xref: /netbsd-src/sys/dev/pci/twe.c (revision d20841bb642898112fe68f0ad3f7b26dddf56f07)
1 /*	$NetBSD: twe.c,v 1.54 2003/12/04 05:46:47 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*-
40  * Copyright (c) 2000 Michael Smith
41  * Copyright (c) 2000 BSDi
42  * All rights reserved.
43  *
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted provided that the following conditions
46  * are met:
47  * 1. Redistributions of source code must retain the above copyright
48  *    notice, this list of conditions and the following disclaimer.
49  * 2. Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  * from FreeBSD: twe.c,v 1.1 2000/05/24 23:35:23 msmith Exp
66  */
67 
68 /*
69  * Driver for the 3ware Escalade family of RAID controllers.
70  */
71 
72 #include <sys/cdefs.h>
73 __KERNEL_RCSID(0, "$NetBSD: twe.c,v 1.54 2003/12/04 05:46:47 thorpej Exp $");
74 
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/kernel.h>
78 #include <sys/device.h>
79 #include <sys/queue.h>
80 #include <sys/proc.h>
81 #include <sys/buf.h>
82 #include <sys/endian.h>
83 #include <sys/malloc.h>
84 #include <sys/conf.h>
85 #include <sys/disk.h>
86 
87 #include <uvm/uvm_extern.h>
88 
89 #include <machine/bswap.h>
90 #include <machine/bus.h>
91 
92 #include <dev/pci/pcireg.h>
93 #include <dev/pci/pcivar.h>
94 #include <dev/pci/pcidevs.h>
95 #include <dev/pci/twereg.h>
96 #include <dev/pci/twevar.h>
97 #include <dev/pci/tweio.h>
98 
99 #define	PCI_CBIO	0x10
100 
101 static int	twe_aen_get(struct twe_softc *, uint16_t *);
102 static void	twe_aen_handler(struct twe_ccb *, int);
103 static void	twe_aen_enqueue(struct twe_softc *sc, uint16_t, int);
104 static uint16_t	twe_aen_dequeue(struct twe_softc *);
105 
106 static void	twe_attach(struct device *, struct device *, void *);
107 static int	twe_init_connection(struct twe_softc *);
108 static int	twe_intr(void *);
109 static int	twe_match(struct device *, struct cfdata *, void *);
110 static int	twe_param_set(struct twe_softc *, int, int, size_t, void *);
111 static void	twe_poll(struct twe_softc *);
112 static int	twe_print(void *, const char *);
113 static int	twe_reset(struct twe_softc *);
114 static int	twe_submatch(struct device *, struct cfdata *, void *);
115 static int	twe_status_check(struct twe_softc *, u_int);
116 static int	twe_status_wait(struct twe_softc *, u_int, int);
117 static void	twe_describe_controller(struct twe_softc *);
118 
119 static int	twe_add_unit(struct twe_softc *, int);
120 static int	twe_del_unit(struct twe_softc *, int);
121 
122 static inline u_int32_t	twe_inl(struct twe_softc *, int);
123 static inline void twe_outl(struct twe_softc *, int, u_int32_t);
124 
125 dev_type_open(tweopen);
126 dev_type_close(tweclose);
127 dev_type_ioctl(tweioctl);
128 
129 const struct cdevsw twe_cdevsw = {
130 	tweopen, tweclose, noread, nowrite, tweioctl,
131 	nostop, notty, nopoll, nommap,
132 };
133 
134 extern struct	cfdriver twe_cd;
135 
136 CFATTACH_DECL(twe, sizeof(struct twe_softc),
137     twe_match, twe_attach, NULL, NULL);
138 
139 /*
140  * Tables to convert numeric codes to strings.
141  */
142 const struct twe_code_table twe_table_status[] = {
143 	{ 0x00,	"successful completion" },
144 
145 	/* info */
146 	{ 0x42,	"command in progress" },
147 	{ 0x6c,	"retrying interface CRC error from UDMA command" },
148 
149 	/* warning */
150 	{ 0x81,	"redundant/inconsequential request ignored" },
151 	{ 0x8e,	"failed to write zeroes to LBA 0" },
152 	{ 0x8f,	"failed to profile TwinStor zones" },
153 
154 	/* fatal */
155 	{ 0xc1,	"aborted due to system command or reconfiguration" },
156 	{ 0xc4,	"aborted" },
157 	{ 0xc5,	"access error" },
158 	{ 0xc6,	"access violation" },
159 	{ 0xc7,	"device failure" },	/* high byte may be port # */
160 	{ 0xc8,	"controller error" },
161 	{ 0xc9,	"timed out" },
162 	{ 0xcb,	"invalid unit number" },
163 	{ 0xcf,	"unit not available" },
164 	{ 0xd2,	"undefined opcode" },
165 	{ 0xdb,	"request incompatible with unit" },
166 	{ 0xdc,	"invalid request" },
167 	{ 0xff,	"firmware error, reset requested" },
168 
169 	{ 0,	NULL }
170 };
171 
172 const struct twe_code_table twe_table_unitstate[] = {
173 	{ TWE_PARAM_UNITSTATUS_Normal,		"Normal" },
174 	{ TWE_PARAM_UNITSTATUS_Initialising,	"Initializing" },
175 	{ TWE_PARAM_UNITSTATUS_Degraded,	"Degraded" },
176 	{ TWE_PARAM_UNITSTATUS_Rebuilding,	"Rebuilding" },
177 	{ TWE_PARAM_UNITSTATUS_Verifying,	"Verifying" },
178 	{ TWE_PARAM_UNITSTATUS_Corrupt,		"Corrupt" },
179 	{ TWE_PARAM_UNITSTATUS_Missing,		"Missing" },
180 
181 	{ 0,					NULL }
182 };
183 
184 const struct twe_code_table twe_table_unittype[] = {
185 	/* array descriptor configuration */
186 	{ TWE_AD_CONFIG_RAID0,			"RAID0" },
187 	{ TWE_AD_CONFIG_RAID1,			"RAID1" },
188 	{ TWE_AD_CONFIG_TwinStor,		"TwinStor" },
189 	{ TWE_AD_CONFIG_RAID5,			"RAID5" },
190 	{ TWE_AD_CONFIG_RAID10,			"RAID10" },
191 
192 	{ 0,					NULL }
193 };
194 
195 const struct twe_code_table twe_table_stripedepth[] = {
196 	{ TWE_AD_STRIPE_4k,			"4K" },
197 	{ TWE_AD_STRIPE_8k,			"8K" },
198 	{ TWE_AD_STRIPE_16k,			"16K" },
199 	{ TWE_AD_STRIPE_32k,			"32K" },
200 	{ TWE_AD_STRIPE_64k,			"64K" },
201 
202 	{ 0,					NULL }
203 };
204 
205 /*
206  * Asynchronous event notification messages are qualified:
207  *	a - not unit/port specific
208  *	u - unit specific
209  *	p - port specific
210  */
211 const struct twe_code_table twe_table_aen[] = {
212 	{ 0x00,	"a queue empty" },
213 	{ 0x01,	"a soft reset" },
214 	{ 0x02,	"u degraded mode" },
215 	{ 0x03,	"a controller error" },
216 	{ 0x04,	"u rebuild fail" },
217 	{ 0x05,	"u rebuild done" },
218 	{ 0x06,	"u incomplete unit" },
219 	{ 0x07,	"u initialization done" },
220 	{ 0x08,	"u unclean shutdown detected" },
221 	{ 0x09,	"p drive timeout" },
222 	{ 0x0a,	"p drive error" },
223 	{ 0x0b,	"u rebuild started" },
224 	{ 0x0c,	"u initialization started" },
225 	{ 0x0d,	"u logical unit deleted" },
226 	{ 0x0f,	"p SMART threshold exceeded" },
227 	{ 0x15,	"a table undefined" },	/* XXX: Not in FreeBSD's table */
228 	{ 0x21,	"p ATA UDMA downgrade" },
229 	{ 0x22,	"p ATA UDMA upgrade" },
230 	{ 0x23,	"p sector repair occurred" },
231 	{ 0x24,	"a SBUF integrity check failure" },
232 	{ 0x25,	"p lost cached write" },
233 	{ 0x26,	"p drive ECC error detected" },
234 	{ 0x27,	"p DCB checksum error" },
235 	{ 0x28,	"p DCB unsupported version" },
236 	{ 0x29,	"u verify started" },
237 	{ 0x2a,	"u verify failed" },
238 	{ 0x2b,	"u verify complete" },
239 	{ 0x2c,	"p overwrote bad sector during rebuild" },
240 	{ 0x2d,	"p encountered bad sector during rebuild" },
241 	{ 0x2e,	"p replacement drive too small" },
242 	{ 0x2f,	"u array not previously initialized" },
243 	{ 0x30,	"p drive not supported" },
244 	{ 0xff,	"a aen queue full" },
245 
246 	{ 0,	NULL },
247 };
248 
249 const char *
250 twe_describe_code(const struct twe_code_table *table, uint32_t code)
251 {
252 
253 	for (; table->string != NULL; table++) {
254 		if (table->code == code)
255 			return (table->string);
256 	}
257 	return (NULL);
258 }
259 
260 static inline u_int32_t
261 twe_inl(struct twe_softc *sc, int off)
262 {
263 
264 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, off, 4,
265 	    BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ);
266 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off));
267 }
268 
269 static inline void
270 twe_outl(struct twe_softc *sc, int off, u_int32_t val)
271 {
272 
273 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
274 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, off, 4,
275 	    BUS_SPACE_BARRIER_WRITE);
276 }
277 
278 /*
279  * Match a supported board.
280  */
281 static int
282 twe_match(struct device *parent, struct cfdata *cfdata, void *aux)
283 {
284 	struct pci_attach_args *pa;
285 
286 	pa = aux;
287 
288 	return (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3WARE &&
289 	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3WARE_ESCALADE ||
290 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3WARE_ESCALADE_ASIC));
291 }
292 
293 /*
294  * Attach a supported board.
295  *
296  * XXX This doesn't fail gracefully.
297  */
298 static void
299 twe_attach(struct device *parent, struct device *self, void *aux)
300 {
301 	struct pci_attach_args *pa;
302 	struct twe_softc *sc;
303 	pci_chipset_tag_t pc;
304 	pci_intr_handle_t ih;
305 	pcireg_t csr;
306 	const char *intrstr;
307 	int s, size, i, rv, rseg;
308 	size_t max_segs, max_xfer;
309 	bus_dma_segment_t seg;
310 	struct twe_cmd *tc;
311 	struct twe_ccb *ccb;
312 
313 	sc = (struct twe_softc *)self;
314 	pa = aux;
315 	pc = pa->pa_pc;
316 	sc->sc_dmat = pa->pa_dmat;
317 	SIMPLEQ_INIT(&sc->sc_ccb_queue);
318 	SLIST_INIT(&sc->sc_ccb_freelist);
319 
320 	aprint_naive(": RAID controller\n");
321 	aprint_normal(": 3ware Escalade\n");
322 
323 	ccb = malloc(sizeof(*ccb) * TWE_MAX_QUEUECNT, M_DEVBUF, M_NOWAIT);
324 	if (ccb == NULL) {
325 		aprint_error("%s: unable to allocate memory for ccbs\n",
326 		    sc->sc_dv.dv_xname);
327 		return;
328 	}
329 
330 	if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
331 	    &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) {
332 		aprint_error("%s: can't map i/o space\n", sc->sc_dv.dv_xname);
333 		return;
334 	}
335 
336 	/* Enable the device. */
337 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
338 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
339 	    csr | PCI_COMMAND_MASTER_ENABLE);
340 
341 	/* Map and establish the interrupt. */
342 	if (pci_intr_map(pa, &ih)) {
343 		aprint_error("%s: can't map interrupt\n", sc->sc_dv.dv_xname);
344 		return;
345 	}
346 
347 	intrstr = pci_intr_string(pc, ih);
348 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, twe_intr, sc);
349 	if (sc->sc_ih == NULL) {
350 		aprint_error("%s: can't establish interrupt%s%s\n",
351 			sc->sc_dv.dv_xname,
352 			(intrstr) ? " at " : "",
353 			(intrstr) ? intrstr : "");
354 		return;
355 	}
356 
357 	if (intrstr != NULL)
358 		aprint_normal("%s: interrupting at %s\n",
359 			sc->sc_dv.dv_xname, intrstr);
360 
361 	/*
362 	 * Allocate and initialise the command blocks and CCBs.
363 	 */
364         size = sizeof(struct twe_cmd) * TWE_MAX_QUEUECNT;
365 
366 	if ((rv = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1,
367 	    &rseg, BUS_DMA_NOWAIT)) != 0) {
368 		aprint_error("%s: unable to allocate commands, rv = %d\n",
369 		    sc->sc_dv.dv_xname, rv);
370 		return;
371 	}
372 
373 	if ((rv = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
374 	    (caddr_t *)&sc->sc_cmds,
375 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
376 		aprint_error("%s: unable to map commands, rv = %d\n",
377 		    sc->sc_dv.dv_xname, rv);
378 		return;
379 	}
380 
381 	if ((rv = bus_dmamap_create(sc->sc_dmat, size, size, 1, 0,
382 	    BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
383 		aprint_error("%s: unable to create command DMA map, rv = %d\n",
384 		    sc->sc_dv.dv_xname, rv);
385 		return;
386 	}
387 
388 	if ((rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_cmds,
389 	    size, NULL, BUS_DMA_NOWAIT)) != 0) {
390 		aprint_error("%s: unable to load command DMA map, rv = %d\n",
391 		    sc->sc_dv.dv_xname, rv);
392 		return;
393 	}
394 
395 	sc->sc_cmds_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
396 	memset(sc->sc_cmds, 0, size);
397 
398 	sc->sc_ccbs = ccb;
399 	tc = (struct twe_cmd *)sc->sc_cmds;
400 	max_segs = twe_get_maxsegs();
401 	max_xfer = twe_get_maxxfer(max_segs);
402 
403 	for (i = 0; i < TWE_MAX_QUEUECNT; i++, tc++, ccb++) {
404 		ccb->ccb_cmd = tc;
405 		ccb->ccb_cmdid = i;
406 		ccb->ccb_flags = 0;
407 		rv = bus_dmamap_create(sc->sc_dmat, max_xfer,
408 		    max_segs, PAGE_SIZE, 0,
409 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
410 		    &ccb->ccb_dmamap_xfer);
411 		if (rv != 0) {
412 			aprint_error("%s: can't create dmamap, rv = %d\n",
413 			    sc->sc_dv.dv_xname, rv);
414 			return;
415 		}
416 
417 		/* Save the first CCB for AEN retrieval. */
418 		if (i != 0)
419 			SLIST_INSERT_HEAD(&sc->sc_ccb_freelist, ccb,
420 			    ccb_chain.slist);
421 	}
422 
423 	/* Wait for the controller to become ready. */
424 	if (twe_status_wait(sc, TWE_STS_MICROCONTROLLER_READY, 6)) {
425 		aprint_error("%s: microcontroller not ready\n",
426 			sc->sc_dv.dv_xname);
427 		return;
428 	}
429 
430 	twe_outl(sc, TWE_REG_CTL, TWE_CTL_DISABLE_INTRS);
431 
432 	/* Reset the controller. */
433 	s = splbio();
434 	rv = twe_reset(sc);
435 	splx(s);
436 	if (rv) {
437 		aprint_error("%s: reset failed\n", sc->sc_dv.dv_xname);
438 		return;
439 	}
440 
441 	/* Initialise connection with controller. */
442 	twe_init_connection(sc);
443 
444 	twe_describe_controller(sc);
445 
446 	/* Find and attach RAID array units. */
447 	sc->sc_nunits = 0;
448 	for (i = 0; i < TWE_MAX_UNITS; i++)
449 		(void) twe_add_unit(sc, i);
450 
451 	/* ...and finally, enable interrupts. */
452 	twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR |
453 	    TWE_CTL_UNMASK_RESP_INTR |
454 	    TWE_CTL_ENABLE_INTRS);
455 }
456 
457 void
458 twe_register_callbacks(struct twe_softc *sc, int unit,
459     const struct twe_callbacks *tcb)
460 {
461 
462 	sc->sc_units[unit].td_callbacks = tcb;
463 }
464 
465 static void
466 twe_recompute_openings(struct twe_softc *sc)
467 {
468 	struct twe_drive *td;
469 	int unit, openings;
470 
471 	if (sc->sc_nunits != 0)
472 		openings = (TWE_MAX_QUEUECNT - 1) / sc->sc_nunits;
473 	else
474 		openings = 0;
475 	if (openings == sc->sc_openings)
476 		return;
477 	sc->sc_openings = openings;
478 
479 #ifdef TWE_DEBUG
480 	printf("%s: %d array%s, %d openings per array\n",
481 	    sc->sc_dv.dv_xname, sc->sc_nunits,
482 	    sc->sc_nunits == 1 ? "" : "s", sc->sc_openings);
483 #endif
484 
485 	for (unit = 0; unit < TWE_MAX_UNITS; unit++) {
486 		td = &sc->sc_units[unit];
487 		if (td->td_dev != NULL)
488 			(*td->td_callbacks->tcb_openings)(td->td_dev,
489 			    sc->sc_openings);
490 	}
491 }
492 
493 static int
494 twe_add_unit(struct twe_softc *sc, int unit)
495 {
496 	struct twe_param *dtp, *atp;
497 	struct twe_array_descriptor *ad;
498 	struct twe_drive *td;
499 	struct twe_attach_args twea;
500 	uint32_t newsize;
501 	int rv;
502 	uint16_t dsize;
503 	uint8_t newtype, newstripe;
504 
505 	if (unit < 0 || unit >= TWE_MAX_UNITS)
506 		return (EINVAL);
507 
508 	/* Find attached units. */
509 	rv = twe_param_get(sc, TWE_PARAM_UNITSUMMARY,
510 	    TWE_PARAM_UNITSUMMARY_Status, TWE_MAX_UNITS, NULL, &dtp);
511 	if (rv != 0) {
512 		aprint_error("%s: error %d fetching unit summary\n",
513 		    sc->sc_dv.dv_xname, rv);
514 		return (rv);
515 	}
516 
517 	/* For each detected unit, collect size and store in an array. */
518 	td = &sc->sc_units[unit];
519 
520 	/* Unit present? */
521 	if ((dtp->tp_data[unit] & TWE_PARAM_UNITSTATUS_Online) == 0) {
522 		/*
523 		 * XXX Should we check to see if a device has been
524 		 * XXX attached at this index and detach it if it
525 		 * XXX has?  ("rescan" semantics)
526 		 */
527 		rv = 0;
528 		goto out;
529    	}
530 
531 	rv = twe_param_get_2(sc, TWE_PARAM_UNITINFO + unit,
532 	    TWE_PARAM_UNITINFO_DescriptorSize, &dsize);
533 	if (rv != 0) {
534 		aprint_error("%s: error %d fetching descriptor size "
535 		    "for unit %d\n", sc->sc_dv.dv_xname, rv, unit);
536 		goto out;
537 	}
538 
539 	rv = twe_param_get(sc, TWE_PARAM_UNITINFO + unit,
540 	    TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL, &atp);
541 	if (rv != 0) {
542 		aprint_error("%s: error %d fetching array descriptor "
543 		    "for unit %d\n", sc->sc_dv.dv_xname, rv, unit);
544 		goto out;
545 	}
546 
547 	ad = (struct twe_array_descriptor *)atp->tp_data;
548 	newtype = ad->configuration;
549 	newstripe = ad->stripe_size;
550 	free(atp, M_DEVBUF);
551 
552 	rv = twe_param_get_4(sc, TWE_PARAM_UNITINFO + unit,
553 	    TWE_PARAM_UNITINFO_Capacity, &newsize);
554 	if (rv != 0) {
555 		aprint_error(
556 		    "%s: error %d fetching capacity for unit %d\n",
557 		    sc->sc_dv.dv_xname, rv, unit);
558 		goto out;
559 	}
560 
561 	/*
562 	 * Have a device, so we need to attach it.  If there is currently
563 	 * something sitting at the slot, and the parameters are different,
564 	 * then we detach the old device before attaching the new one.
565 	 */
566 	if (td->td_dev != NULL &&
567 	    td->td_size == newsize &&
568 	    td->td_type == newtype &&
569 	    td->td_stripe == newstripe) {
570 		/* Same as the old device; just keep using it. */
571 		rv = 0;
572 		goto out;
573 	} else if (td->td_dev != NULL) {
574 		/* Detach the old device first. */
575 		(void) config_detach(td->td_dev, DETACH_FORCE);
576 		td->td_dev = NULL;
577 	} else if (td->td_size == 0)
578 		sc->sc_nunits++;
579 
580 	/*
581 	 * Committed to the new array unit; assign its parameters and
582 	 * recompute the number of available command openings.
583 	 */
584 	td->td_size = newsize;
585 	td->td_type = newtype;
586 	td->td_stripe = newstripe;
587 	twe_recompute_openings(sc);
588 
589 	twea.twea_unit = unit;
590 	td->td_dev = config_found_sm(&sc->sc_dv, &twea, twe_print,
591 	    twe_submatch);
592 
593 	rv = 0;
594  out:
595 	free(dtp, M_DEVBUF);
596 	return (rv);
597 }
598 
599 static int
600 twe_del_unit(struct twe_softc *sc, int unit)
601 {
602 	struct twe_drive *td;
603 
604 	if (unit < 0 || unit >= TWE_MAX_UNITS)
605 		return (EINVAL);
606 
607 	td = &sc->sc_units[unit];
608 	if (td->td_size != 0)
609 		sc->sc_nunits--;
610 	td->td_size = 0;
611 	td->td_type = 0;
612 	td->td_stripe = 0;
613 	if (td->td_dev != NULL) {
614 		(void) config_detach(td->td_dev, DETACH_FORCE);
615 		td->td_dev = NULL;
616 	}
617 	twe_recompute_openings(sc);
618 	return (0);
619 }
620 
621 /*
622  * Reset the controller.
623  * MUST BE CALLED AT splbio()!
624  */
625 static int
626 twe_reset(struct twe_softc *sc)
627 {
628 	uint16_t aen;
629 	u_int status;
630 	volatile u_int32_t junk;
631 	int got, rv;
632 
633 	/* Issue a soft reset. */
634 	twe_outl(sc, TWE_REG_CTL, TWE_CTL_ISSUE_SOFT_RESET |
635 	    TWE_CTL_CLEAR_HOST_INTR |
636 	    TWE_CTL_CLEAR_ATTN_INTR |
637 	    TWE_CTL_MASK_CMD_INTR |
638 	    TWE_CTL_MASK_RESP_INTR |
639 	    TWE_CTL_CLEAR_ERROR_STS |
640 	    TWE_CTL_DISABLE_INTRS);
641 
642 	/* Wait for attention... */
643 	if (twe_status_wait(sc, TWE_STS_ATTN_INTR, 15)) {
644 		printf("%s: no attention interrupt\n",
645 		    sc->sc_dv.dv_xname);
646 		return (-1);
647 	}
648 
649 	/* ...and ACK it. */
650 	twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR);
651 
652 	/*
653 	 * Pull AENs out of the controller; look for a soft reset AEN.
654 	 * Open code this, since we want to detect reset even if the
655 	 * queue for management tools is full.
656 	 *
657 	 * Note that since:
658 	 *	- interrupts are blocked
659 	 *	- we have reset the controller
660 	 *	- acknowledged the pending ATTENTION
661 	 * that there is no way a pending asynchronous AEN fetch would
662 	 * finish, so clear the flag.
663 	 */
664 	sc->sc_flags &= ~TWEF_AEN;
665 	for (got = 0;;) {
666 		rv = twe_aen_get(sc, &aen);
667 		if (rv != 0)
668 			printf("%s: error %d while draining event queue\n",
669 			    sc->sc_dv.dv_xname, rv);
670 		if (TWE_AEN_CODE(aen) == TWE_AEN_QUEUE_EMPTY)
671 			break;
672 		if (TWE_AEN_CODE(aen) == TWE_AEN_SOFT_RESET)
673 			got = 1;
674 		twe_aen_enqueue(sc, aen, 1);
675 	}
676 
677 	if (!got) {
678 		printf("%s: reset not reported\n", sc->sc_dv.dv_xname);
679 		return (-1);
680 	}
681 
682 	/* Check controller status. */
683 	status = twe_inl(sc, TWE_REG_STS);
684 	if (twe_status_check(sc, status)) {
685 		printf("%s: controller errors detected\n",
686 		    sc->sc_dv.dv_xname);
687 		return (-1);
688 	}
689 
690 	/* Drain the response queue. */
691 	for (;;) {
692 		status = twe_inl(sc, TWE_REG_STS);
693 		if (twe_status_check(sc, status) != 0) {
694 			printf("%s: can't drain response queue\n",
695 			    sc->sc_dv.dv_xname);
696 			return (-1);
697 		}
698 		if ((status & TWE_STS_RESP_QUEUE_EMPTY) != 0)
699 			break;
700 		junk = twe_inl(sc, TWE_REG_RESP_QUEUE);
701 	}
702 
703 	return (0);
704 }
705 
706 /*
707  * Print autoconfiguration message for a sub-device.
708  */
709 static int
710 twe_print(void *aux, const char *pnp)
711 {
712 	struct twe_attach_args *twea;
713 
714 	twea = aux;
715 
716 	if (pnp != NULL)
717 		aprint_normal("block device at %s", pnp);
718 	aprint_normal(" unit %d", twea->twea_unit);
719 	return (UNCONF);
720 }
721 
722 /*
723  * Match a sub-device.
724  */
725 static int
726 twe_submatch(struct device *parent, struct cfdata *cf, void *aux)
727 {
728 	struct twe_attach_args *twea;
729 
730 	twea = aux;
731 
732 	if (cf->tweacf_unit != TWECF_UNIT_DEFAULT &&
733 	    cf->tweacf_unit != twea->twea_unit)
734 		return (0);
735 
736 	return (config_match(parent, cf, aux));
737 }
738 
739 /*
740  * Interrupt service routine.
741  */
742 static int
743 twe_intr(void *arg)
744 {
745 	struct twe_softc *sc;
746 	u_int status;
747 	int caught, rv;
748 
749 	sc = arg;
750 	caught = 0;
751 	status = twe_inl(sc, TWE_REG_STS);
752 	twe_status_check(sc, status);
753 
754 	/* Host interrupts - purpose unknown. */
755 	if ((status & TWE_STS_HOST_INTR) != 0) {
756 #ifdef DEBUG
757 		printf("%s: host interrupt\n", sc->sc_dv.dv_xname);
758 #endif
759 		twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_HOST_INTR);
760 		caught = 1;
761 	}
762 
763 	/*
764 	 * Attention interrupts, signalled when a controller or child device
765 	 * state change has occurred.
766 	 */
767 	if ((status & TWE_STS_ATTN_INTR) != 0) {
768 		rv = twe_aen_get(sc, NULL);
769 		if (rv != 0)
770 			printf("%s: unable to retrieve AEN (%d)\n",
771 			    sc->sc_dv.dv_xname, rv);
772 		else
773 			twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR);
774 		caught = 1;
775 	}
776 
777 	/*
778 	 * Command interrupts, signalled when the controller can accept more
779 	 * commands.  We don't use this; instead, we try to submit commands
780 	 * when we receive them, and when other commands have completed.
781 	 * Mask it so we don't get another one.
782 	 */
783 	if ((status & TWE_STS_CMD_INTR) != 0) {
784 #ifdef DEBUG
785 		printf("%s: command interrupt\n", sc->sc_dv.dv_xname);
786 #endif
787 		twe_outl(sc, TWE_REG_CTL, TWE_CTL_MASK_CMD_INTR);
788 		caught = 1;
789 	}
790 
791 	if ((status & TWE_STS_RESP_INTR) != 0) {
792 		twe_poll(sc);
793 		caught = 1;
794 	}
795 
796 	return (caught);
797 }
798 
799 /*
800  * Fetch an AEN.  Even though this is really like parameter
801  * retrieval, we handle this specially, because we issue this
802  * AEN retrieval command from interrupt context, and thus
803  * reserve a CCB for it to avoid resource shortage.
804  *
805  * XXX There are still potential resource shortages we could
806  * XXX encounter.  Consider pre-allocating all AEN-related
807  * XXX resources.
808  *
809  * MUST BE CALLED AT splbio()!
810  */
811 static int
812 twe_aen_get(struct twe_softc *sc, uint16_t *aenp)
813 {
814 	struct twe_ccb *ccb;
815 	struct twe_cmd *tc;
816 	struct twe_param *tp;
817 	int rv;
818 
819 	/*
820 	 * If we're already retrieving an AEN, just wait; another
821 	 * retrieval will be chained after the current one completes.
822 	 */
823 	if (sc->sc_flags & TWEF_AEN) {
824 		/*
825 		 * It is a fatal software programming error to attempt
826 		 * to fetch an AEN synchronously when an AEN fetch is
827 		 * already pending.
828 		 */
829 		KASSERT(aenp == NULL);
830 		return (0);
831 	}
832 
833 	tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT);
834 	if (tp == NULL)
835 		return (ENOMEM);
836 
837 	ccb = twe_ccb_alloc(sc,
838 	    TWE_CCB_AEN | TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
839 	KASSERT(ccb != NULL);
840 
841 	ccb->ccb_data = tp;
842 	ccb->ccb_datasize = TWE_SECTOR_SIZE;
843 	ccb->ccb_tx.tx_handler = (aenp == NULL) ? twe_aen_handler : NULL;
844 	ccb->ccb_tx.tx_context = tp;
845 	ccb->ccb_tx.tx_dv = &sc->sc_dv;
846 
847 	tc = ccb->ccb_cmd;
848 	tc->tc_size = 2;
849 	tc->tc_opcode = TWE_OP_GET_PARAM | (tc->tc_size << 5);
850 	tc->tc_unit = 0;
851 	tc->tc_count = htole16(1);
852 
853 	/* Fill in the outbound parameter data. */
854 	tp->tp_table_id = htole16(TWE_PARAM_AEN);
855 	tp->tp_param_id = TWE_PARAM_AEN_UnitCode;
856 	tp->tp_param_size = 2;
857 
858 	/* Map the transfer. */
859 	if ((rv = twe_ccb_map(sc, ccb)) != 0) {
860 		twe_ccb_free(sc, ccb);
861 		goto done;
862 	}
863 
864 	/* Enqueue the command and wait. */
865 	if (aenp != NULL) {
866 		rv = twe_ccb_poll(sc, ccb, 5);
867 		twe_ccb_unmap(sc, ccb);
868 		twe_ccb_free(sc, ccb);
869 		if (rv == 0)
870 			*aenp = le16toh(*(uint16_t *)tp->tp_data);
871 		free(tp, M_DEVBUF);
872 	} else {
873 		sc->sc_flags |= TWEF_AEN;
874 		twe_ccb_enqueue(sc, ccb);
875 		rv = 0;
876 	}
877 
878  done:
879 	return (rv);
880 }
881 
882 /*
883  * Handle an AEN returned by the controller.
884  * MUST BE CALLED AT splbio()!
885  */
886 static void
887 twe_aen_handler(struct twe_ccb *ccb, int error)
888 {
889 	struct twe_softc *sc;
890 	struct twe_param *tp;
891 	uint16_t aen;
892 	int rv;
893 
894 	sc = (struct twe_softc *)ccb->ccb_tx.tx_dv;
895 	tp = ccb->ccb_tx.tx_context;
896 	twe_ccb_unmap(sc, ccb);
897 
898 	sc->sc_flags &= ~TWEF_AEN;
899 
900 	if (error) {
901 		printf("%s: error retrieving AEN\n", sc->sc_dv.dv_xname);
902 		aen = TWE_AEN_QUEUE_EMPTY;
903 	} else
904 		aen = le16toh(*(u_int16_t *)tp->tp_data);
905 	free(tp, M_DEVBUF);
906 	twe_ccb_free(sc, ccb);
907 
908 	if (TWE_AEN_CODE(aen) == TWE_AEN_QUEUE_EMPTY) {
909 		twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR);
910 		return;
911 	}
912 
913 	twe_aen_enqueue(sc, aen, 0);
914 
915 	/*
916 	 * Chain another retrieval in case interrupts have been
917 	 * coalesced.
918 	 */
919 	rv = twe_aen_get(sc, NULL);
920 	if (rv != 0)
921 		printf("%s: unable to retrieve AEN (%d)\n",
922 		    sc->sc_dv.dv_xname, rv);
923 }
924 
925 static void
926 twe_aen_enqueue(struct twe_softc *sc, uint16_t aen, int quiet)
927 {
928 	const char *str, *msg;
929 	int s, next, nextnext;
930 
931 	/*
932 	 * First report the AEN on the console.  Maybe.
933 	 */
934 	if (! quiet) {
935 		str = twe_describe_code(twe_table_aen, TWE_AEN_CODE(aen));
936 		if (str == NULL) {
937 			printf("%s: unknown AEN 0x%04x\n",
938 			    sc->sc_dv.dv_xname, aen);
939 		} else {
940 			msg = str + 2;
941 			switch (*str) {
942 			case 'u':
943 				printf("%s: unit %d: %s\n",
944 				    sc->sc_dv.dv_xname, TWE_AEN_UNIT(aen), msg);
945 				break;
946 
947 			case 'p':
948 				printf("%s: port %d: %s\n",
949 				    sc->sc_dv.dv_xname, TWE_AEN_UNIT(aen), msg);
950 				break;
951 
952 			default:
953 				printf("%s: %s\n", sc->sc_dv.dv_xname, msg);
954 			}
955 		}
956 	}
957 
958 	/* Now enqueue the AEN for mangement tools. */
959 	s = splbio();
960 
961 	next = (sc->sc_aen_head + 1) % TWE_AEN_Q_LENGTH;
962 	nextnext = (sc->sc_aen_head + 2) % TWE_AEN_Q_LENGTH;
963 
964 	/*
965 	 * If this is the last free slot, then queue up a "queue
966 	 * full" message.
967 	 */
968 	if (nextnext == sc->sc_aen_tail)
969 		aen = TWE_AEN_QUEUE_FULL;
970 
971 	if (next != sc->sc_aen_tail) {
972 		sc->sc_aen_queue[sc->sc_aen_head] = aen;
973 		sc->sc_aen_head = next;
974 	}
975 
976 	if (sc->sc_flags & TWEF_AENQ_WAIT) {
977 		sc->sc_flags &= ~TWEF_AENQ_WAIT;
978 		wakeup(&sc->sc_aen_queue);
979 	}
980 
981 	splx(s);
982 }
983 
984 /* NOTE: Must be called at splbio(). */
985 static uint16_t
986 twe_aen_dequeue(struct twe_softc *sc)
987 {
988 	uint16_t aen;
989 
990 	if (sc->sc_aen_tail == sc->sc_aen_head)
991 		aen = TWE_AEN_QUEUE_EMPTY;
992 	else {
993 		aen = sc->sc_aen_queue[sc->sc_aen_tail];
994 		sc->sc_aen_tail = (sc->sc_aen_tail + 1) & TWE_AEN_Q_LENGTH;
995 	}
996 
997 	return (aen);
998 }
999 
1000 /*
1001  * These are short-hand functions that execute TWE_OP_GET_PARAM to
1002  * fetch 1, 2, and 4 byte parameter values, respectively.
1003  */
1004 int
1005 twe_param_get_1(struct twe_softc *sc, int table_id, int param_id,
1006     uint8_t *valp)
1007 {
1008 	struct twe_param *tp;
1009 	int rv;
1010 
1011 	rv = twe_param_get(sc, table_id, param_id, 1, NULL, &tp);
1012 	if (rv != 0)
1013 		return (rv);
1014 	*valp = *(uint8_t *)tp->tp_data;
1015 	free(tp, M_DEVBUF);
1016 	return (0);
1017 }
1018 
1019 int
1020 twe_param_get_2(struct twe_softc *sc, int table_id, int param_id,
1021     uint16_t *valp)
1022 {
1023 	struct twe_param *tp;
1024 	int rv;
1025 
1026 	rv = twe_param_get(sc, table_id, param_id, 2, NULL, &tp);
1027 	if (rv != 0)
1028 		return (rv);
1029 	*valp = le16toh(*(uint16_t *)tp->tp_data);
1030 	free(tp, M_DEVBUF);
1031 	return (0);
1032 }
1033 
1034 int
1035 twe_param_get_4(struct twe_softc *sc, int table_id, int param_id,
1036     uint32_t *valp)
1037 {
1038 	struct twe_param *tp;
1039 	int rv;
1040 
1041 	rv = twe_param_get(sc, table_id, param_id, 4, NULL, &tp);
1042 	if (rv != 0)
1043 		return (rv);
1044 	*valp = le32toh(*(uint32_t *)tp->tp_data);
1045 	free(tp, M_DEVBUF);
1046 	return (0);
1047 }
1048 
1049 /*
1050  * Execute a TWE_OP_GET_PARAM command.  If a callback function is provided,
1051  * it will be called with generated context when the command has completed.
1052  * If no callback is provided, the command will be executed synchronously
1053  * and a pointer to a buffer containing the data returned.
1054  *
1055  * The caller or callback is responsible for freeing the buffer.
1056  *
1057  * NOTE: We assume we can sleep here to wait for a CCB to become available.
1058  */
1059 int
1060 twe_param_get(struct twe_softc *sc, int table_id, int param_id, size_t size,
1061 	      void (*func)(struct twe_ccb *, int), struct twe_param **pbuf)
1062 {
1063 	struct twe_ccb *ccb;
1064 	struct twe_cmd *tc;
1065 	struct twe_param *tp;
1066 	int rv, s;
1067 
1068 	tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT);
1069 	if (tp == NULL)
1070 		return ENOMEM;
1071 
1072 	ccb = twe_ccb_alloc_wait(sc, TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
1073 	KASSERT(ccb != NULL);
1074 
1075 	ccb->ccb_data = tp;
1076 	ccb->ccb_datasize = TWE_SECTOR_SIZE;
1077 	ccb->ccb_tx.tx_handler = func;
1078 	ccb->ccb_tx.tx_context = tp;
1079 	ccb->ccb_tx.tx_dv = &sc->sc_dv;
1080 
1081 	tc = ccb->ccb_cmd;
1082 	tc->tc_size = 2;
1083 	tc->tc_opcode = TWE_OP_GET_PARAM | (tc->tc_size << 5);
1084 	tc->tc_unit = 0;
1085 	tc->tc_count = htole16(1);
1086 
1087 	/* Fill in the outbound parameter data. */
1088 	tp->tp_table_id = htole16(table_id);
1089 	tp->tp_param_id = param_id;
1090 	tp->tp_param_size = size;
1091 
1092 	/* Map the transfer. */
1093 	if ((rv = twe_ccb_map(sc, ccb)) != 0) {
1094 		twe_ccb_free(sc, ccb);
1095 		goto done;
1096 	}
1097 
1098 	/* Submit the command and either wait or let the callback handle it. */
1099 	if (func == NULL) {
1100 		s = splbio();
1101 		rv = twe_ccb_poll(sc, ccb, 5);
1102 		twe_ccb_unmap(sc, ccb);
1103 		twe_ccb_free(sc, ccb);
1104 		splx(s);
1105 	} else {
1106 #ifdef DEBUG
1107 		if (pbuf != NULL)
1108 			panic("both func and pbuf defined");
1109 #endif
1110 		twe_ccb_enqueue(sc, ccb);
1111 		return 0;
1112 	}
1113 
1114 done:
1115 	if (pbuf == NULL || rv != 0)
1116 		free(tp, M_DEVBUF);
1117 	else if (pbuf != NULL && rv == 0)
1118 		*pbuf = tp;
1119 	return rv;
1120 }
1121 
1122 /*
1123  * Execute a TWE_OP_SET_PARAM command.
1124  *
1125  * NOTE: We assume we can sleep here to wait for a CCB to become available.
1126  */
1127 static int
1128 twe_param_set(struct twe_softc *sc, int table_id, int param_id, size_t size,
1129 	      void *buf)
1130 {
1131 	struct twe_ccb *ccb;
1132 	struct twe_cmd *tc;
1133 	struct twe_param *tp;
1134 	int rv, s;
1135 
1136 	tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT);
1137 	if (tp == NULL)
1138 		return ENOMEM;
1139 
1140 	ccb = twe_ccb_alloc_wait(sc, TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
1141 	KASSERT(ccb != NULL);
1142 
1143 	ccb->ccb_data = tp;
1144 	ccb->ccb_datasize = TWE_SECTOR_SIZE;
1145 	ccb->ccb_tx.tx_handler = 0;
1146 	ccb->ccb_tx.tx_context = tp;
1147 	ccb->ccb_tx.tx_dv = &sc->sc_dv;
1148 
1149 	tc = ccb->ccb_cmd;
1150 	tc->tc_size = 2;
1151 	tc->tc_opcode = TWE_OP_SET_PARAM | (tc->tc_size << 5);
1152 	tc->tc_unit = 0;
1153 	tc->tc_count = htole16(1);
1154 
1155 	/* Fill in the outbound parameter data. */
1156 	tp->tp_table_id = htole16(table_id);
1157 	tp->tp_param_id = param_id;
1158 	tp->tp_param_size = size;
1159 	memcpy(tp->tp_data, buf, size);
1160 
1161 	/* Map the transfer. */
1162 	if ((rv = twe_ccb_map(sc, ccb)) != 0) {
1163 		twe_ccb_free(sc, ccb);
1164 		goto done;
1165 	}
1166 
1167 	/* Submit the command and wait. */
1168 	s = splbio();
1169 	rv = twe_ccb_poll(sc, ccb, 5);
1170 	twe_ccb_unmap(sc, ccb);
1171 	twe_ccb_free(sc, ccb);
1172 	splx(s);
1173 done:
1174 	free(tp, M_DEVBUF);
1175 	return (rv);
1176 }
1177 
1178 /*
1179  * Execute a TWE_OP_INIT_CONNECTION command.  Return non-zero on error.
1180  * Must be called with interrupts blocked.
1181  */
1182 static int
1183 twe_init_connection(struct twe_softc *sc)
1184 /*###762 [cc] warning: `twe_init_connection' was used with no prototype before its definition%%%*/
1185 /*###762 [cc] warning: `twe_init_connection' was declared implicitly `extern' and later `static'%%%*/
1186 {
1187 	struct twe_ccb *ccb;
1188 	struct twe_cmd *tc;
1189 	int rv;
1190 
1191 	if ((ccb = twe_ccb_alloc(sc, 0)) == NULL)
1192 		return (EAGAIN);
1193 
1194 	/* Build the command. */
1195 	tc = ccb->ccb_cmd;
1196 	tc->tc_size = 3;
1197 	tc->tc_opcode = TWE_OP_INIT_CONNECTION;
1198 	tc->tc_unit = 0;
1199 	tc->tc_count = htole16(TWE_MAX_CMDS);
1200 	tc->tc_args.init_connection.response_queue_pointer = 0;
1201 
1202 	/* Submit the command for immediate execution. */
1203 	rv = twe_ccb_poll(sc, ccb, 5);
1204 	twe_ccb_free(sc, ccb);
1205 	return (rv);
1206 }
1207 
1208 /*
1209  * Poll the controller for completed commands.  Must be called with
1210  * interrupts blocked.
1211  */
1212 static void
1213 twe_poll(struct twe_softc *sc)
1214 {
1215 	struct twe_ccb *ccb;
1216 	int found;
1217 	u_int status, cmdid;
1218 
1219 	found = 0;
1220 
1221 	for (;;) {
1222 		status = twe_inl(sc, TWE_REG_STS);
1223 		twe_status_check(sc, status);
1224 
1225 		if ((status & TWE_STS_RESP_QUEUE_EMPTY))
1226 			break;
1227 
1228 		found = 1;
1229 		cmdid = twe_inl(sc, TWE_REG_RESP_QUEUE);
1230 		cmdid = (cmdid & TWE_RESP_MASK) >> TWE_RESP_SHIFT;
1231 		if (cmdid >= TWE_MAX_QUEUECNT) {
1232 			printf("%s: bad cmdid %d\n", sc->sc_dv.dv_xname, cmdid);
1233 			continue;
1234 		}
1235 
1236 		ccb = sc->sc_ccbs + cmdid;
1237 		if ((ccb->ccb_flags & TWE_CCB_ACTIVE) == 0) {
1238 			printf("%s: CCB for cmdid %d not active\n",
1239 			    sc->sc_dv.dv_xname, cmdid);
1240 			continue;
1241 		}
1242 		ccb->ccb_flags ^= TWE_CCB_COMPLETE | TWE_CCB_ACTIVE;
1243 
1244 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
1245 		    (caddr_t)ccb->ccb_cmd - sc->sc_cmds,
1246 		    sizeof(struct twe_cmd),
1247 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1248 
1249 		/* Pass notification to upper layers. */
1250 		if (ccb->ccb_tx.tx_handler != NULL)
1251 			(*ccb->ccb_tx.tx_handler)(ccb,
1252 			    ccb->ccb_cmd->tc_status != 0 ? EIO : 0);
1253 	}
1254 
1255 	/* If any commands have completed, run the software queue. */
1256 	if (found)
1257 		twe_ccb_enqueue(sc, NULL);
1258 }
1259 
1260 /*
1261  * Wait for `status' to be set in the controller status register.  Return
1262  * zero if found, non-zero if the operation timed out.
1263  */
1264 static int
1265 twe_status_wait(struct twe_softc *sc, u_int32_t status, int timo)
1266 {
1267 
1268 	for (timo *= 10; timo != 0; timo--) {
1269 		if ((twe_inl(sc, TWE_REG_STS) & status) == status)
1270 			break;
1271 		delay(100000);
1272 	}
1273 
1274 	return (timo == 0);
1275 }
1276 
1277 /*
1278  * Complain if the status bits aren't what we expect.
1279  */
1280 static int
1281 twe_status_check(struct twe_softc *sc, u_int status)
1282 {
1283 	int rv;
1284 
1285 	rv = 0;
1286 
1287 	if ((status & TWE_STS_EXPECTED_BITS) != TWE_STS_EXPECTED_BITS) {
1288 		printf("%s: missing status bits: 0x%08x\n", sc->sc_dv.dv_xname,
1289 		    status & ~TWE_STS_EXPECTED_BITS);
1290 		rv = -1;
1291 	}
1292 
1293 	if ((status & TWE_STS_UNEXPECTED_BITS) != 0) {
1294 		printf("%s: unexpected status bits: 0x%08x\n",
1295 		    sc->sc_dv.dv_xname, status & TWE_STS_UNEXPECTED_BITS);
1296 		rv = -1;
1297 	}
1298 
1299 	return (rv);
1300 }
1301 
1302 /*
1303  * Allocate and initialise a CCB.
1304  */
1305 static __inline void
1306 twe_ccb_init(struct twe_softc *sc, struct twe_ccb *ccb, int flags)
1307 {
1308 	struct twe_cmd *tc;
1309 
1310 	ccb->ccb_tx.tx_handler = NULL;
1311 	ccb->ccb_flags = flags;
1312 	tc = ccb->ccb_cmd;
1313 	tc->tc_status = 0;
1314 	tc->tc_flags = 0;
1315 	tc->tc_cmdid = ccb->ccb_cmdid;
1316 }
1317 
1318 struct twe_ccb *
1319 twe_ccb_alloc(struct twe_softc *sc, int flags)
1320 {
1321 	struct twe_ccb *ccb;
1322 	int s;
1323 
1324 	s = splbio();
1325 	if (__predict_false((flags & TWE_CCB_AEN) != 0)) {
1326 		/* Use the reserved CCB. */
1327 		ccb = sc->sc_ccbs;
1328 	} else {
1329 		/* Allocate a CCB and command block. */
1330 		if (__predict_false((ccb =
1331 				SLIST_FIRST(&sc->sc_ccb_freelist)) == NULL)) {
1332 			splx(s);
1333 			return (NULL);
1334 		}
1335 		SLIST_REMOVE_HEAD(&sc->sc_ccb_freelist, ccb_chain.slist);
1336 	}
1337 #ifdef DIAGNOSTIC
1338 	if ((long)(ccb - sc->sc_ccbs) == 0 && (flags & TWE_CCB_AEN) == 0)
1339 		panic("twe_ccb_alloc: got reserved CCB for non-AEN");
1340 	if ((ccb->ccb_flags & TWE_CCB_ALLOCED) != 0)
1341 		panic("twe_ccb_alloc: CCB %ld already allocated",
1342 		    (long)(ccb - sc->sc_ccbs));
1343 	flags |= TWE_CCB_ALLOCED;
1344 #endif
1345 	splx(s);
1346 
1347 	twe_ccb_init(sc, ccb, flags);
1348 	return (ccb);
1349 }
1350 
1351 struct twe_ccb *
1352 twe_ccb_alloc_wait(struct twe_softc *sc, int flags)
1353 {
1354 	struct twe_ccb *ccb;
1355 	int s;
1356 
1357 	KASSERT((flags & TWE_CCB_AEN) == 0);
1358 
1359 	s = splbio();
1360 	while (__predict_false((ccb =
1361 				SLIST_FIRST(&sc->sc_ccb_freelist)) == NULL)) {
1362 		sc->sc_flags |= TWEF_WAIT_CCB;
1363 		(void) tsleep(&sc->sc_ccb_freelist, PRIBIO, "tweccb", 0);
1364 	}
1365 	SLIST_REMOVE_HEAD(&sc->sc_ccb_freelist, ccb_chain.slist);
1366 #ifdef DIAGNOSTIC
1367 	if ((ccb->ccb_flags & TWE_CCB_ALLOCED) != 0)
1368 		panic("twe_ccb_alloc_wait: CCB %ld already allocated",
1369 		    (long)(ccb - sc->sc_ccbs));
1370 	flags |= TWE_CCB_ALLOCED;
1371 #endif
1372 	splx(s);
1373 
1374 	twe_ccb_init(sc, ccb, flags);
1375 	return (ccb);
1376 }
1377 
1378 /*
1379  * Free a CCB.
1380  */
1381 void
1382 twe_ccb_free(struct twe_softc *sc, struct twe_ccb *ccb)
1383 {
1384 	int s;
1385 
1386 	s = splbio();
1387 	if ((ccb->ccb_flags & TWE_CCB_AEN) == 0) {
1388 		SLIST_INSERT_HEAD(&sc->sc_ccb_freelist, ccb, ccb_chain.slist);
1389 		if (__predict_false((sc->sc_flags & TWEF_WAIT_CCB) != 0)) {
1390 			sc->sc_flags &= ~TWEF_WAIT_CCB;
1391 			wakeup(&sc->sc_ccb_freelist);
1392 		}
1393 	}
1394 	ccb->ccb_flags = 0;
1395 	splx(s);
1396 }
1397 
1398 /*
1399  * Map the specified CCB's command block and data buffer (if any) into
1400  * controller visible space.  Perform DMA synchronisation.
1401  */
1402 int
1403 twe_ccb_map(struct twe_softc *sc, struct twe_ccb *ccb)
1404 {
1405 	struct twe_cmd *tc;
1406 	int flags, nsegs, i, s, rv;
1407 	void *data;
1408 
1409 	/*
1410 	 * The data as a whole must be 512-byte aligned.
1411 	 */
1412 	if (((u_long)ccb->ccb_data & (TWE_ALIGNMENT - 1)) != 0) {
1413 		s = splvm();
1414 		/* XXX */
1415 		ccb->ccb_abuf = uvm_km_kmemalloc(kmem_map, NULL,
1416 		    ccb->ccb_datasize, UVM_KMF_NOWAIT);
1417 		splx(s);
1418 		data = (void *)ccb->ccb_abuf;
1419 		if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0)
1420 			memcpy(data, ccb->ccb_data, ccb->ccb_datasize);
1421 	} else {
1422 		ccb->ccb_abuf = (vaddr_t)0;
1423 		data = ccb->ccb_data;
1424 	}
1425 
1426 	/*
1427 	 * Map the data buffer into bus space and build the S/G list.
1428 	 */
1429 	rv = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, data,
1430 	    ccb->ccb_datasize, NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1431 	    ((ccb->ccb_flags & TWE_CCB_DATA_IN) ?
1432 	    BUS_DMA_READ : BUS_DMA_WRITE));
1433 	if (rv != 0) {
1434 		if (ccb->ccb_abuf != (vaddr_t)0) {
1435 			s = splvm();
1436 			/* XXX */
1437 			uvm_km_free(kmem_map, ccb->ccb_abuf,
1438 			    ccb->ccb_datasize);
1439 			splx(s);
1440 		}
1441 		return (rv);
1442 	}
1443 
1444 	nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
1445 	tc = ccb->ccb_cmd;
1446 	tc->tc_size += 2 * nsegs;
1447 
1448 	/* The location of the S/G list is dependant upon command type. */
1449 	switch (tc->tc_opcode >> 5) {
1450 	case 2:
1451 		for (i = 0; i < nsegs; i++) {
1452 			tc->tc_args.param.sgl[i].tsg_address =
1453 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
1454 			tc->tc_args.param.sgl[i].tsg_length =
1455 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
1456 		}
1457 		/* XXX Needed? */
1458 		for (; i < TWE_SG_SIZE; i++) {
1459 			tc->tc_args.param.sgl[i].tsg_address = 0;
1460 			tc->tc_args.param.sgl[i].tsg_length = 0;
1461 		}
1462 		break;
1463 	case 3:
1464 		for (i = 0; i < nsegs; i++) {
1465 			tc->tc_args.io.sgl[i].tsg_address =
1466 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
1467 			tc->tc_args.io.sgl[i].tsg_length =
1468 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
1469 		}
1470 		/* XXX Needed? */
1471 		for (; i < TWE_SG_SIZE; i++) {
1472 			tc->tc_args.io.sgl[i].tsg_address = 0;
1473 			tc->tc_args.io.sgl[i].tsg_length = 0;
1474 		}
1475 		break;
1476 #ifdef DEBUG
1477 	default:
1478 		panic("twe_ccb_map: oops");
1479 #endif
1480 	}
1481 
1482 	if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0)
1483 		flags = BUS_DMASYNC_PREREAD;
1484 	else
1485 		flags = 0;
1486 	if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0)
1487 		flags |= BUS_DMASYNC_PREWRITE;
1488 
1489 	bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
1490 	    ccb->ccb_datasize, flags);
1491 	return (0);
1492 }
1493 
1494 /*
1495  * Unmap the specified CCB's command block and data buffer (if any) and
1496  * perform DMA synchronisation.
1497  */
1498 void
1499 twe_ccb_unmap(struct twe_softc *sc, struct twe_ccb *ccb)
1500 {
1501 	int flags, s;
1502 
1503 	if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0)
1504 		flags = BUS_DMASYNC_POSTREAD;
1505 	else
1506 		flags = 0;
1507 	if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0)
1508 		flags |= BUS_DMASYNC_POSTWRITE;
1509 
1510 	bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
1511 	    ccb->ccb_datasize, flags);
1512 	bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
1513 
1514 	if (ccb->ccb_abuf != (vaddr_t)0) {
1515 		if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0)
1516 			memcpy(ccb->ccb_data, (void *)ccb->ccb_abuf,
1517 			    ccb->ccb_datasize);
1518 		s = splvm();
1519 		/* XXX */
1520 		uvm_km_free(kmem_map, ccb->ccb_abuf, ccb->ccb_datasize);
1521 		splx(s);
1522 	}
1523 }
1524 
1525 /*
1526  * Submit a command to the controller and poll on completion.  Return
1527  * non-zero on timeout (but don't check status, as some command types don't
1528  * return status).  Must be called with interrupts blocked.
1529  */
1530 int
1531 twe_ccb_poll(struct twe_softc *sc, struct twe_ccb *ccb, int timo)
1532 {
1533 	int rv;
1534 
1535 	if ((rv = twe_ccb_submit(sc, ccb)) != 0)
1536 		return (rv);
1537 
1538 	for (timo *= 1000; timo != 0; timo--) {
1539 		twe_poll(sc);
1540 		if ((ccb->ccb_flags & TWE_CCB_COMPLETE) != 0)
1541 			break;
1542 		DELAY(100);
1543 	}
1544 
1545 	return (timo == 0);
1546 }
1547 
1548 /*
1549  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
1550  * the order that they were enqueued and try to submit their command blocks
1551  * to the controller for execution.
1552  */
1553 void
1554 twe_ccb_enqueue(struct twe_softc *sc, struct twe_ccb *ccb)
1555 {
1556 	int s;
1557 
1558 	s = splbio();
1559 
1560 	if (ccb != NULL)
1561 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain.simpleq);
1562 
1563 	while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) {
1564 		if (twe_ccb_submit(sc, ccb))
1565 			break;
1566 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain.simpleq);
1567 	}
1568 
1569 	splx(s);
1570 }
1571 
1572 /*
1573  * Submit the command block associated with the specified CCB to the
1574  * controller for execution.  Must be called with interrupts blocked.
1575  */
1576 int
1577 twe_ccb_submit(struct twe_softc *sc, struct twe_ccb *ccb)
1578 {
1579 	bus_addr_t pa;
1580 	int rv;
1581 	u_int status;
1582 
1583 	/* Check to see if we can post a command. */
1584 	status = twe_inl(sc, TWE_REG_STS);
1585 	twe_status_check(sc, status);
1586 
1587 	if ((status & TWE_STS_CMD_QUEUE_FULL) == 0) {
1588 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
1589 		    (caddr_t)ccb->ccb_cmd - sc->sc_cmds, sizeof(struct twe_cmd),
1590 		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1591 #ifdef DIAGNOSTIC
1592 		if ((ccb->ccb_flags & TWE_CCB_ALLOCED) == 0)
1593 			panic("%s: CCB %ld not ALLOCED\n",
1594 			    sc->sc_dv.dv_xname, (long)(ccb - sc->sc_ccbs));
1595 #endif
1596 		ccb->ccb_flags |= TWE_CCB_ACTIVE;
1597 		pa = sc->sc_cmds_paddr +
1598 		    ccb->ccb_cmdid * sizeof(struct twe_cmd);
1599 		twe_outl(sc, TWE_REG_CMD_QUEUE, (u_int32_t)pa);
1600 		rv = 0;
1601 	} else
1602 		rv = EBUSY;
1603 
1604 	return (rv);
1605 }
1606 
1607 
1608 /*
1609  * Accept an open operation on the control device.
1610  */
1611 int
1612 tweopen(dev_t dev, int flag, int mode, struct proc *p)
1613 {
1614 	struct twe_softc *twe;
1615 
1616 	if ((twe = device_lookup(&twe_cd, minor(dev))) == NULL)
1617 		return (ENXIO);
1618 	if ((twe->sc_flags & TWEF_OPEN) != 0)
1619 		return (EBUSY);
1620 
1621 	twe->sc_flags |= TWEF_OPEN;
1622 	return (0);
1623 }
1624 
1625 /*
1626  * Accept the last close on the control device.
1627  */
1628 int
1629 tweclose(dev_t dev, int flag, int mode, struct proc *p)
1630 {
1631 	struct twe_softc *twe;
1632 
1633 	twe = device_lookup(&twe_cd, minor(dev));
1634 	twe->sc_flags &= ~TWEF_OPEN;
1635 	return (0);
1636 }
1637 
1638 static void
1639 twe_tweio_command_handler(struct twe_ccb *ccb, int error)
1640 {
1641 
1642 	/* Just wake up the sleeper. */
1643 	wakeup(ccb);
1644 }
1645 
1646 /*
1647  * Handle control operations.
1648  */
1649 int
1650 tweioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1651 {
1652 	struct twe_softc *twe;
1653 	struct twe_ccb *ccb;
1654 	struct twe_param *param;
1655 	struct twe_usercommand *tu;
1656 	struct twe_paramcommand *tp;
1657 	struct twe_drivecommand *td;
1658 	void *pdata = NULL;
1659 	int s, error = 0;
1660 	u_int8_t cmdid;
1661 
1662 	if (securelevel >= 2)
1663 		return (EPERM);
1664 
1665 	twe = device_lookup(&twe_cd, minor(dev));
1666 	tu = (struct twe_usercommand *)data;
1667 	tp = (struct twe_paramcommand *)data;
1668 	td = (struct twe_drivecommand *)data;
1669 
1670 	/* This is intended to be compatible with the FreeBSD interface. */
1671 	switch (cmd) {
1672 	case TWEIO_COMMAND:
1673 		/* XXX mutex */
1674 		if (tu->tu_size > 0) {
1675 			/*
1676 			 * XXX Handle > TWE_SECTOR_SIZE?  Let's see if
1677 			 * it's really necessary, first.
1678 			 */
1679 			if (tu->tu_size > TWE_SECTOR_SIZE) {
1680 #ifdef TWE_DEBUG
1681 				printf("%s: TWEIO_COMMAND: tu_size = %d\n",
1682 				    twe->sc_dv.dv_xname, tu->tu_size);
1683 #endif
1684 				return EINVAL;
1685 			}
1686 			pdata = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_WAITOK);
1687 			error = copyin(tu->tu_data, pdata, tu->tu_size);
1688 			if (error != 0)
1689 				goto done;
1690 			ccb = twe_ccb_alloc_wait(twe,
1691 			    TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
1692 			KASSERT(ccb != NULL);
1693 			ccb->ccb_data = pdata;
1694 			ccb->ccb_datasize = TWE_SECTOR_SIZE;
1695 		} else {
1696 			ccb = twe_ccb_alloc_wait(twe, 0);
1697 			KASSERT(ccb != NULL);
1698 		}
1699 
1700 		ccb->ccb_tx.tx_handler = twe_tweio_command_handler;
1701 		ccb->ccb_tx.tx_context = NULL;
1702 		ccb->ccb_tx.tx_dv = &twe->sc_dv;
1703 
1704 		cmdid = ccb->ccb_cmdid;
1705 		memcpy(ccb->ccb_cmd, &tu->tu_cmd, sizeof(struct twe_cmd));
1706 		ccb->ccb_cmd->tc_cmdid = cmdid;
1707 
1708 		/* Map the transfer. */
1709 		if ((error = twe_ccb_map(twe, ccb)) != 0) {
1710 			twe_ccb_free(twe, ccb);
1711 			goto done;
1712 		}
1713 
1714 		/* Submit the command and wait up to 1 minute. */
1715 		error = 0;
1716 		twe_ccb_enqueue(twe, ccb);
1717 		s = splbio();
1718 		while ((ccb->ccb_flags & TWE_CCB_COMPLETE) == 0)
1719 			if ((error = tsleep(ccb, PRIBIO, "tweioctl",
1720 					    60 * hz)) != 0)
1721 				break;
1722 		splx(s);
1723 
1724 		/* Copy the command back to the ioctl argument. */
1725 		memcpy(&tu->tu_cmd, ccb->ccb_cmd, sizeof(struct twe_cmd));
1726 #ifdef TWE_DEBUG
1727 		printf("%s: TWEIO_COMMAND: tc_opcode = 0x%02x, "
1728 		    "tc_status = 0x%02x\n", twe->sc_dv.dv_xname,
1729 		    tu->tu_cmd.tc_opcode, tu->tu_cmd.tc_status);
1730 #endif
1731 
1732 		s = splbio();
1733 		twe_ccb_free(twe, ccb);
1734 		splx(s);
1735 
1736 		if (tu->tu_size > 0)
1737 			error = copyout(pdata, tu->tu_data, tu->tu_size);
1738 		goto done;
1739 
1740 	case TWEIO_STATS:
1741 		return (ENOENT);
1742 
1743 	case TWEIO_AEN_POLL:
1744 		s = splbio();
1745 		*(u_int *)data = twe_aen_dequeue(twe);
1746 		splx(s);
1747 		return (0);
1748 
1749 	case TWEIO_AEN_WAIT:
1750 		s = splbio();
1751 		while ((*(u_int *)data =
1752 		    twe_aen_dequeue(twe)) == TWE_AEN_QUEUE_EMPTY) {
1753 			twe->sc_flags |= TWEF_AENQ_WAIT;
1754 			error = tsleep(&twe->sc_aen_queue, PRIBIO | PCATCH,
1755 			    "tweaen", 0);
1756 			if (error == EINTR) {
1757 				splx(s);
1758 				return (error);
1759 			}
1760 		}
1761 		splx(s);
1762 		return (0);
1763 
1764 	case TWEIO_GET_PARAM:
1765 		error = twe_param_get(twe, tp->tp_table_id, tp->tp_param_id,
1766 		    tp->tp_size, 0, &param);
1767 		if (error != 0)
1768 			return (error);
1769 		if (param->tp_param_size > tp->tp_size) {
1770 			error = EFAULT;
1771 			goto done;
1772 		}
1773 		error = copyout(param->tp_data, tp->tp_data,
1774 		    param->tp_param_size);
1775 		goto done;
1776 
1777 	case TWEIO_SET_PARAM:
1778 		pdata = malloc(tp->tp_size, M_DEVBUF, M_WAITOK);
1779 		if ((error = copyin(tp->tp_data, pdata, tp->tp_size)) != 0)
1780 			goto done;
1781 		error = twe_param_set(twe, tp->tp_table_id, tp->tp_param_id,
1782 		    tp->tp_size, pdata);
1783 		goto done;
1784 
1785 	case TWEIO_RESET:
1786 		s = splbio();
1787 		twe_reset(twe);
1788 		splx(s);
1789 		return (0);
1790 
1791 	case TWEIO_ADD_UNIT:
1792 		/* XXX mutex */
1793 		return (twe_add_unit(twe, td->td_unit));
1794 
1795 	case TWEIO_DEL_UNIT:
1796 		/* XXX mutex */
1797 		return (twe_del_unit(twe, td->td_unit));
1798 
1799 	default:
1800 		return EINVAL;
1801 	}
1802 done:
1803 	if (pdata)
1804 		free(pdata, M_DEVBUF);
1805 	return error;
1806 }
1807 
1808 /*
1809  * Print some information about the controller
1810  */
1811 static void
1812 twe_describe_controller(struct twe_softc *sc)
1813 {
1814 	struct twe_param *p[6];
1815 	int i, rv = 0;
1816 	uint32_t dsize;
1817 	uint8_t ports;
1818 
1819 	/* get the port count */
1820 	rv |= twe_param_get_1(sc, TWE_PARAM_CONTROLLER,
1821 		TWE_PARAM_CONTROLLER_PortCount, &ports);
1822 
1823 	/* get version strings */
1824 	rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon,
1825 		16, NULL, &p[0]);
1826 	rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW,
1827 		16, NULL, &p[1]);
1828 	rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS,
1829 		16, NULL, &p[2]);
1830 	rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB,
1831 		8, NULL, &p[3]);
1832 	rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA,
1833 		8, NULL, &p[4]);
1834 	rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI,
1835 		8, NULL, &p[5]);
1836 
1837 	if (rv) {
1838 		/* some error occurred */
1839 		aprint_error("%s: failed to fetch version information\n",
1840 			sc->sc_dv.dv_xname);
1841 		return;
1842 	}
1843 
1844 	aprint_normal("%s: %d ports, Firmware %.16s, BIOS %.16s\n",
1845 		sc->sc_dv.dv_xname, ports,
1846 		p[1]->tp_data, p[2]->tp_data);
1847 
1848 	aprint_verbose("%s: Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n",
1849 		sc->sc_dv.dv_xname,
1850 		p[0]->tp_data, p[3]->tp_data,
1851 		p[4]->tp_data, p[5]->tp_data);
1852 
1853 	free(p[0], M_DEVBUF);
1854 	free(p[1], M_DEVBUF);
1855 	free(p[2], M_DEVBUF);
1856 	free(p[3], M_DEVBUF);
1857 	free(p[4], M_DEVBUF);
1858 	free(p[5], M_DEVBUF);
1859 
1860 	rv = twe_param_get(sc, TWE_PARAM_DRIVESUMMARY,
1861 	    TWE_PARAM_DRIVESUMMARY_Status, 16, NULL, &p[0]);
1862 	if (rv) {
1863 		aprint_error("%s: failed to get drive status summary\n",
1864 		    sc->sc_dv.dv_xname);
1865 		return;
1866 	}
1867 	for (i = 0; i < ports; i++) {
1868 		if (p[0]->tp_data[i] != TWE_PARAM_DRIVESTATUS_Present)
1869 			continue;
1870 		rv = twe_param_get_4(sc, TWE_PARAM_DRIVEINFO + i,
1871 		    TWE_PARAM_DRIVEINFO_Size, &dsize);
1872 		if (rv) {
1873 			aprint_error(
1874 			    "%s: unable to get drive size for port %d\n",
1875 			    sc->sc_dv.dv_xname, i);
1876 			continue;
1877 		}
1878 		rv = twe_param_get(sc, TWE_PARAM_DRIVEINFO + i,
1879 		    TWE_PARAM_DRIVEINFO_Model, 40, NULL, &p[1]);
1880 		if (rv) {
1881 			aprint_error(
1882 			    "%s: unable to get drive model for port %d\n",
1883 			    sc->sc_dv.dv_xname, i);
1884 			continue;
1885 		}
1886 		aprint_verbose("%s: port %d: %.40s %d MB\n", sc->sc_dv.dv_xname,
1887 		    i, p[1]->tp_data, dsize / 2048);
1888 		free(p[1], M_DEVBUF);
1889 	}
1890 	free(p[0], M_DEVBUF);
1891 }
1892