1 /* $NetBSD: ld_twe.c,v 1.33 2009/05/06 10:34:32 cegger Exp $ */
4 * Copyright (c) 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran; and by Jason R. Thorpe of Wasabi Systems, Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * 3ware "Escalade" RAID controller front-end for ld(4) driver.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ld_twe.c,v 1.33 2009/05/06 10:34:32 cegger Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
47 #include <sys/endian.h>
57 #include <uvm/uvm_extern.h>
59 #include <dev/ldvar.h>
61 #include <dev/pci/twereg.h>
62 #include <dev/pci/twevar.h>
65 struct ld_softc sc_ld
;
69 static void ld_twe_attach(device_t
, device_t
, void *);
70 static int ld_twe_detach(device_t
, int);
71 static int ld_twe_dobio(struct ld_twe_softc
*, void *, int, int, int,
73 static int ld_twe_dump(struct ld_softc
*, void *, int, int);
74 static int ld_twe_flush(struct ld_softc
*, int);
75 static void ld_twe_handler(struct twe_ccb
*, int);
76 static int ld_twe_match(device_t
, cfdata_t
, void *);
77 static int ld_twe_start(struct ld_softc
*, struct buf
*);
79 static void ld_twe_adjqparam(device_t
, int);
81 CFATTACH_DECL_NEW(ld_twe
, sizeof(struct ld_twe_softc
),
82 ld_twe_match
, ld_twe_attach
, ld_twe_detach
, NULL
);
84 static const struct twe_callbacks ld_twe_callbacks
= {
89 ld_twe_match(device_t parent
, cfdata_t match
, void *aux
)
96 ld_twe_attach(device_t parent
, device_t self
, void *aux
)
98 struct twe_attach_args
*twea
= aux
;
99 struct ld_twe_softc
*sc
= device_private(self
);
100 struct ld_softc
*ld
= &sc
->sc_ld
;
101 struct twe_softc
*twe
= device_private(parent
);
102 struct twe_drive
*td
= &twe
->sc_units
[twea
->twea_unit
];
103 const char *typestr
, *stripestr
, *statstr
;
104 char unktype
[16], stripebuf
[32], unkstat
[32];
110 twe_register_callbacks(twe
, twea
->twea_unit
, &ld_twe_callbacks
);
112 sc
->sc_hwunit
= twea
->twea_unit
;
113 ld
->sc_flags
= LDF_ENABLED
;
114 ld
->sc_maxxfer
= twe_get_maxxfer(twe_get_maxsegs());
115 ld
->sc_secperunit
= td
->td_size
;
116 ld
->sc_secsize
= TWE_SECTOR_SIZE
;
117 ld
->sc_maxqueuecnt
= twe
->sc_openings
;
118 ld
->sc_start
= ld_twe_start
;
119 ld
->sc_dump
= ld_twe_dump
;
120 ld
->sc_flush
= ld_twe_flush
;
122 typestr
= twe_describe_code(twe_table_unittype
, td
->td_type
);
123 if (typestr
== NULL
) {
124 snprintf(unktype
, sizeof(unktype
), "<0x%02x>", td
->td_type
);
127 switch (td
->td_type
) {
128 case TWE_AD_CONFIG_RAID0
:
129 case TWE_AD_CONFIG_RAID5
:
130 case TWE_AD_CONFIG_RAID10
:
131 stripestr
= twe_describe_code(twe_table_stripedepth
,
133 if (stripestr
== NULL
)
134 snprintf(stripebuf
, sizeof(stripebuf
),
135 "<stripe code 0x%02x> ", td
->td_stripe
);
137 snprintf(stripebuf
, sizeof(stripebuf
), "%s stripe ",
144 error
= twe_param_get_1(twe
, TWE_PARAM_UNITINFO
+ twea
->twea_unit
,
145 TWE_PARAM_UNITINFO_Status
, &status
);
146 status
&= TWE_PARAM_UNITSTATUS_MASK
;
148 snprintf(unkstat
, sizeof(unkstat
), "<unknown>");
150 } else if ((statstr
=
151 twe_describe_code(twe_table_unitstate
, status
)) == NULL
) {
152 snprintf(unkstat
, sizeof(unkstat
), "<status code 0x%02x>",
157 aprint_normal(": %s%s, status: %s\n", stripebuf
, typestr
, statstr
);
162 ld_twe_detach(device_t self
, int flags
)
164 struct ld_twe_softc
*sc
= device_private(self
);
165 struct ld_softc
*ld
= &sc
->sc_ld
;
168 if ((rv
= ldbegindetach(ld
, flags
)) != 0)
176 ld_twe_dobio(struct ld_twe_softc
*sc
, void *data
, int datasize
, int blkno
,
177 int dowrite
, struct buf
*bp
)
181 struct twe_softc
*twe
;
184 twe
= device_private(device_parent(sc
->sc_ld
.sc_dv
));
186 flags
= (dowrite
? TWE_CCB_DATA_OUT
: TWE_CCB_DATA_IN
);
187 if ((ccb
= twe_ccb_alloc(twe
, flags
)) == NULL
)
190 ccb
->ccb_data
= data
;
191 ccb
->ccb_datasize
= datasize
;
194 /* Build the command. */
196 tc
->tc_unit
= sc
->sc_hwunit
;
197 tc
->tc_count
= htole16(datasize
/ TWE_SECTOR_SIZE
);
198 tc
->tc_args
.io
.lba
= htole32(blkno
);
201 tc
->tc_opcode
= TWE_OP_WRITE
| (tc
->tc_size
<< 5);
203 tc
->tc_opcode
= TWE_OP_READ
| (tc
->tc_size
<< 5);
205 /* Map the data transfer. */
206 if ((rv
= twe_ccb_map(twe
, ccb
)) != 0) {
207 twe_ccb_free(twe
, ccb
);
213 * Polled commands must not sit on the software queue. Wait
214 * up to 2 seconds for the command to complete.
217 rv
= twe_ccb_poll(twe
, ccb
, 2000);
218 twe_ccb_unmap(twe
, ccb
);
219 twe_ccb_free(twe
, ccb
);
222 ccb
->ccb_tx
.tx_handler
= ld_twe_handler
;
223 ccb
->ccb_tx
.tx_context
= bp
;
224 ccb
->ccb_tx
.tx_dv
= sc
->sc_ld
.sc_dv
;
225 twe_ccb_enqueue(twe
, ccb
);
233 ld_twe_start(struct ld_softc
*ld
, struct buf
*bp
)
236 return (ld_twe_dobio((struct ld_twe_softc
*)ld
, bp
->b_data
,
237 bp
->b_bcount
, bp
->b_rawblkno
, (bp
->b_flags
& B_READ
) == 0, bp
));
241 ld_twe_handler(struct twe_ccb
*ccb
, int error
)
244 struct twe_context
*tx
;
245 struct ld_twe_softc
*sc
;
246 struct twe_softc
*twe
;
250 sc
= device_private(tx
->tx_dv
);
251 twe
= device_private(device_parent(sc
->sc_ld
.sc_dv
));
253 twe_ccb_unmap(twe
, ccb
);
254 twe_ccb_free(twe
, ccb
);
258 bp
->b_resid
= bp
->b_bcount
;
262 lddone(&sc
->sc_ld
, bp
);
266 ld_twe_dump(struct ld_softc
*ld
, void *data
, int blkno
, int blkcnt
)
269 return (ld_twe_dobio((struct ld_twe_softc
*)ld
, data
,
270 blkcnt
* ld
->sc_secsize
, blkno
, 1, NULL
));
274 ld_twe_flush(struct ld_softc
*ld
, int flags
)
276 struct ld_twe_softc
*sc
= (void *) ld
;
277 struct twe_softc
*twe
= device_private(device_parent(ld
->sc_dv
));
282 ccb
= twe_ccb_alloc_wait(twe
, 0);
283 KASSERT(ccb
!= NULL
);
285 ccb
->ccb_data
= NULL
;
286 ccb
->ccb_datasize
= 0;
290 tc
->tc_opcode
= TWE_OP_FLUSH
;
291 tc
->tc_unit
= sc
->sc_hwunit
;
294 if (flags
& LDFL_POLL
) {
296 * Polled commands must not sit on the software queue. Wait
297 * up to 2 seconds for the command to complete.
300 rv
= twe_ccb_poll(twe
, ccb
, 2000);
301 twe_ccb_unmap(twe
, ccb
);
302 twe_ccb_free(twe
, ccb
);
305 ccb
->ccb_tx
.tx_handler
= twe_ccb_wait_handler
;
306 ccb
->ccb_tx
.tx_context
= NULL
;
307 ccb
->ccb_tx
.tx_dv
= ld
->sc_dv
;
308 twe_ccb_enqueue(twe
, ccb
);
312 while ((ccb
->ccb_flags
& TWE_CCB_COMPLETE
) == 0)
313 if ((rv
= tsleep(ccb
, PRIBIO
, "tweflush",
316 twe_ccb_free(twe
, ccb
);
324 ld_twe_adjqparam(device_t self
, int openings
)
326 struct ld_twe_softc
*sc
= device_private(self
);
327 struct ld_softc
*ld
= &sc
->sc_ld
;
329 ldadjqparam(ld
, openings
);