xref: /openbsd-src/sys/dev/ic/ami.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: ami.c,v 1.226 2013/10/19 13:03:43 dlg Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Michael Shalayeff
5  * Copyright (c) 2005 Marco Peereboom
6  * Copyright (c) 2006 David Gwynne
7  * All rights reserved.
8  *
9  * The SCSI emulation layer is derived from gdt(4) driver,
10  * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 /*
34  * American Megatrends Inc. MegaRAID controllers driver
35  *
36  * This driver was made because these ppl and organizations
37  * donated hardware and provided documentation:
38  *
39  * - 428 model card
40  *	John Kerbawy, Stephan Matis, Mark Stovall;
41  *
42  * - 467 and 475 model cards, docs
43  *	American Megatrends Inc.;
44  *
45  * - uninterruptable electric power for cvs
46  *	Theo de Raadt.
47  */
48 
49 #include "bio.h"
50 
51 /* #define	AMI_DEBUG */
52 
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/buf.h>
56 #include <sys/ioctl.h>
57 #include <sys/device.h>
58 #include <sys/kernel.h>
59 #include <sys/malloc.h>
60 #include <sys/proc.h>
61 #include <sys/rwlock.h>
62 #include <sys/pool.h>
63 
64 #include <machine/bus.h>
65 
66 #include <scsi/scsi_all.h>
67 #include <scsi/scsi_disk.h>
68 #include <scsi/scsiconf.h>
69 
70 #include <dev/biovar.h>
71 #include <dev/ic/amireg.h>
72 #include <dev/ic/amivar.h>
73 
74 #ifdef AMI_DEBUG
75 #define	AMI_DPRINTF(m,a)	do { if (ami_debug & (m)) printf a; } while (0)
76 #define	AMI_D_CMD	0x0001
77 #define	AMI_D_INTR	0x0002
78 #define	AMI_D_MISC	0x0004
79 #define	AMI_D_DMA	0x0008
80 #define	AMI_D_IOCTL	0x0010
81 int ami_debug = 0
82 /*	| AMI_D_CMD */
83 /*	| AMI_D_INTR */
84 /*	| AMI_D_MISC */
85 /*	| AMI_D_DMA */
86 /*	| AMI_D_IOCTL */
87 	;
88 #else
89 #define	AMI_DPRINTF(m,a)	/* m, a */
90 #endif
91 
92 struct cfdriver ami_cd = {
93 	NULL, "ami", DV_DULL
94 };
95 
96 void	ami_scsi_cmd(struct scsi_xfer *);
97 int	ami_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int);
98 void	amiminphys(struct buf *bp, struct scsi_link *sl);
99 
100 struct scsi_adapter ami_switch = {
101 	ami_scsi_cmd, amiminphys, 0, 0, ami_scsi_ioctl
102 };
103 
104 void	ami_scsi_raw_cmd(struct scsi_xfer *);
105 
106 struct scsi_adapter ami_raw_switch = {
107 	ami_scsi_raw_cmd, amiminphys, 0, 0,
108 };
109 
110 void *		ami_get_ccb(void *);
111 void		ami_put_ccb(void *, void *);
112 
113 u_int32_t	ami_read(struct ami_softc *, bus_size_t);
114 void		ami_write(struct ami_softc *, bus_size_t, u_int32_t);
115 
116 void		ami_copyhds(struct ami_softc *, const u_int32_t *,
117 		    const u_int8_t *, const u_int8_t *);
118 struct ami_mem	*ami_allocmem(struct ami_softc *, size_t);
119 void		ami_freemem(struct ami_softc *, struct ami_mem *);
120 int		ami_alloc_ccbs(struct ami_softc *, int);
121 
122 int		ami_poll(struct ami_softc *, struct ami_ccb *);
123 void		ami_start(struct ami_softc *, struct ami_ccb *);
124 void		ami_complete(struct ami_softc *, struct ami_ccb *, int);
125 void		ami_runqueue_tick(void *);
126 void		ami_runqueue(struct ami_softc *);
127 
128 void 		ami_start_xs(struct ami_softc *sc, struct ami_ccb *,
129 		    struct scsi_xfer *);
130 void		ami_done_xs(struct ami_softc *, struct ami_ccb *);
131 void		ami_done_pt(struct ami_softc *, struct ami_ccb *);
132 void		ami_done_flush(struct ami_softc *, struct ami_ccb *);
133 void		ami_done_sysflush(struct ami_softc *, struct ami_ccb *);
134 
135 void		ami_done_dummy(struct ami_softc *, struct ami_ccb *);
136 void		ami_done_ioctl(struct ami_softc *, struct ami_ccb *);
137 void		ami_done_init(struct ami_softc *, struct ami_ccb *);
138 
139 void		ami_copy_internal_data(struct scsi_xfer *, void *, size_t);
140 
141 int		ami_load_ptmem(struct ami_softc*, struct ami_ccb *,
142 		    void *, size_t, int, int);
143 
144 #if NBIO > 0
145 int		ami_mgmt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t,
146 		    u_int8_t, size_t, void *);
147 int		ami_drv_pt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t *,
148 		    int, int, void *);
149 int		ami_drv_readcap(struct ami_softc *, u_int8_t, u_int8_t,
150 		    daddr_t *);
151 int		ami_drv_inq(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t,
152 		    void *);
153 int		ami_ioctl(struct device *, u_long, caddr_t);
154 int		ami_ioctl_inq(struct ami_softc *, struct bioc_inq *);
155 int		ami_vol(struct ami_softc *, struct bioc_vol *,
156 		    struct ami_big_diskarray *);
157 int		ami_disk(struct ami_softc *, struct bioc_disk *,
158 		    struct ami_big_diskarray *);
159 int		ami_ioctl_vol(struct ami_softc *, struct bioc_vol *);
160 int		ami_ioctl_disk(struct ami_softc *, struct bioc_disk *);
161 int		ami_ioctl_alarm(struct ami_softc *, struct bioc_alarm *);
162 int		ami_ioctl_setstate(struct ami_softc *, struct bioc_setstate *);
163 
164 #ifndef SMALL_KERNEL
165 int		ami_create_sensors(struct ami_softc *);
166 void		ami_refresh_sensors(void *);
167 #endif
168 #endif /* NBIO > 0 */
169 
170 #define DEVNAME(_s)	((_s)->sc_dev.dv_xname)
171 
172 void *
173 ami_get_ccb(void *xsc)
174 {
175 	struct ami_softc *sc = xsc;
176 	struct ami_ccb *ccb;
177 
178 	mtx_enter(&sc->sc_ccb_freeq_mtx);
179 	ccb = TAILQ_FIRST(&sc->sc_ccb_freeq);
180 	if (ccb != NULL) {
181 		TAILQ_REMOVE(&sc->sc_ccb_freeq, ccb, ccb_link);
182 		ccb->ccb_state = AMI_CCB_READY;
183 	}
184 	mtx_leave(&sc->sc_ccb_freeq_mtx);
185 
186 	return (ccb);
187 }
188 
189 void
190 ami_put_ccb(void *xsc, void *xccb)
191 {
192 	struct ami_softc *sc = xsc;
193 	struct ami_ccb *ccb = xccb;
194 
195 	ccb->ccb_state = AMI_CCB_FREE;
196 	ccb->ccb_xs = NULL;
197 	ccb->ccb_flags = 0;
198 	ccb->ccb_done = NULL;
199 
200 	mtx_enter(&sc->sc_ccb_freeq_mtx);
201 	TAILQ_INSERT_TAIL(&sc->sc_ccb_freeq, ccb, ccb_link);
202 	mtx_leave(&sc->sc_ccb_freeq_mtx);
203 }
204 
205 u_int32_t
206 ami_read(struct ami_softc *sc, bus_size_t r)
207 {
208 	u_int32_t rv;
209 
210 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
211 	    BUS_SPACE_BARRIER_READ);
212 	rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
213 
214 	AMI_DPRINTF(AMI_D_CMD, ("ari 0x%x 0x08%x ", r, rv));
215 	return (rv);
216 }
217 
218 void
219 ami_write(struct ami_softc *sc, bus_size_t r, u_int32_t v)
220 {
221 	AMI_DPRINTF(AMI_D_CMD, ("awo 0x%x 0x%08x ", r, v));
222 
223 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
224 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
225 	    BUS_SPACE_BARRIER_WRITE);
226 }
227 
228 struct ami_mem *
229 ami_allocmem(struct ami_softc *sc, size_t size)
230 {
231 	struct ami_mem		*am;
232 	int			nsegs;
233 
234 	am = malloc(sizeof(struct ami_mem), M_DEVBUF, M_NOWAIT|M_ZERO);
235 	if (am == NULL)
236 		return (NULL);
237 
238 	am->am_size = size;
239 
240 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
241 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &am->am_map) != 0)
242 		goto amfree;
243 
244 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &am->am_seg, 1,
245 	    &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
246 		goto destroy;
247 
248 	if (bus_dmamem_map(sc->sc_dmat, &am->am_seg, nsegs, size, &am->am_kva,
249 	    BUS_DMA_NOWAIT) != 0)
250 		goto free;
251 
252 	if (bus_dmamap_load(sc->sc_dmat, am->am_map, am->am_kva, size, NULL,
253 	    BUS_DMA_NOWAIT) != 0)
254 		goto unmap;
255 
256 	return (am);
257 
258 unmap:
259 	bus_dmamem_unmap(sc->sc_dmat, am->am_kva, size);
260 free:
261 	bus_dmamem_free(sc->sc_dmat, &am->am_seg, 1);
262 destroy:
263 	bus_dmamap_destroy(sc->sc_dmat, am->am_map);
264 amfree:
265 	free(am, M_DEVBUF);
266 
267 	return (NULL);
268 }
269 
270 void
271 ami_freemem(struct ami_softc *sc, struct ami_mem *am)
272 {
273 	bus_dmamap_unload(sc->sc_dmat, am->am_map);
274 	bus_dmamem_unmap(sc->sc_dmat, am->am_kva, am->am_size);
275 	bus_dmamem_free(sc->sc_dmat, &am->am_seg, 1);
276 	bus_dmamap_destroy(sc->sc_dmat, am->am_map);
277 	free(am, M_DEVBUF);
278 }
279 
280 void
281 ami_copyhds(struct ami_softc *sc, const u_int32_t *sizes,
282     const u_int8_t *props, const u_int8_t *stats)
283 {
284 	int i;
285 
286 	for (i = 0; i < sc->sc_nunits; i++) {
287 		sc->sc_hdr[i].hd_present = 1;
288 		sc->sc_hdr[i].hd_is_logdrv = 1;
289 		sc->sc_hdr[i].hd_size = letoh32(sizes[i]);
290 		sc->sc_hdr[i].hd_prop = props[i];
291 		sc->sc_hdr[i].hd_stat = stats[i];
292 	}
293 }
294 
295 int
296 ami_alloc_ccbs(struct ami_softc *sc, int nccbs)
297 {
298 	struct ami_ccb *ccb;
299 	struct ami_ccbmem *ccbmem, *mem;
300 	int i, error;
301 
302 	sc->sc_ccbs = malloc(sizeof(struct ami_ccb) * nccbs,
303 	    M_DEVBUF, M_NOWAIT);
304 	if (sc->sc_ccbs == NULL) {
305 		printf(": unable to allocate ccbs\n");
306 		return (1);
307 	}
308 
309 	sc->sc_ccbmem_am = ami_allocmem(sc, sizeof(struct ami_ccbmem) * nccbs);
310 	if (sc->sc_ccbmem_am == NULL) {
311 		printf(": unable to allocate ccb dmamem\n");
312 		goto free_ccbs;
313 	}
314 	ccbmem = AMIMEM_KVA(sc->sc_ccbmem_am);
315 
316 	TAILQ_INIT(&sc->sc_ccb_freeq);
317 	mtx_init(&sc->sc_ccb_freeq_mtx, IPL_BIO);
318 	TAILQ_INIT(&sc->sc_ccb_preq);
319 	TAILQ_INIT(&sc->sc_ccb_runq);
320 	timeout_set(&sc->sc_run_tmo, ami_runqueue_tick, sc);
321 
322 	scsi_iopool_init(&sc->sc_iopool, sc, ami_get_ccb, ami_put_ccb);
323 
324 	for (i = 0; i < nccbs; i++) {
325 		ccb = &sc->sc_ccbs[i];
326 		mem = &ccbmem[i];
327 
328 		error = bus_dmamap_create(sc->sc_dmat, AMI_MAXFER,
329 		    AMI_MAXOFFSETS, AMI_MAXFER, 0,
330 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap);
331 		if (error) {
332 			printf(": cannot create ccb dmamap (%d)\n", error);
333 			goto free_list;
334 		}
335 
336 		ccb->ccb_sc = sc;
337 
338 		ccb->ccb_cmd.acc_id = i + 1;
339 		ccb->ccb_offset = sizeof(struct ami_ccbmem) * i;
340 
341 		ccb->ccb_pt = &mem->cd_pt;
342 		ccb->ccb_ptpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) +
343 		    ccb->ccb_offset);
344 
345 		ccb->ccb_sglist = mem->cd_sg;
346 		ccb->ccb_sglistpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) +
347 		    ccb->ccb_offset + sizeof(struct ami_passthrough));
348 
349 		/* override last command for management */
350 		if (i == nccbs - 1) {
351 			ccb->ccb_cmd.acc_id = 0xfe;
352 			sc->sc_mgmtccb = ccb;
353 		} else {
354 			ami_put_ccb(sc, ccb);
355 		}
356 	}
357 
358 	return (0);
359 
360 free_list:
361 	while ((ccb = ami_get_ccb(sc)) != NULL)
362 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
363 
364 	ami_freemem(sc, sc->sc_ccbmem_am);
365 free_ccbs:
366 	free(sc->sc_ccbs, M_DEVBUF);
367 
368 	return (1);
369 }
370 
371 int
372 ami_attach(struct ami_softc *sc)
373 {
374 	struct scsibus_attach_args saa;
375 	struct ami_rawsoftc *rsc;
376 	struct ami_ccb iccb;
377 	struct ami_iocmd *cmd;
378 	struct ami_mem *am;
379 	struct ami_inquiry *inq;
380 	struct ami_fc_einquiry *einq;
381 	struct ami_fc_prodinfo *pi;
382 	const char *p;
383 	paddr_t	pa;
384 
385 	mtx_init(&sc->sc_cmd_mtx, IPL_BIO);
386 
387 	am = ami_allocmem(sc, NBPG);
388 	if (am == NULL) {
389 		printf(": unable to allocate init data\n");
390 		return (1);
391 	}
392 	pa = htole32(AMIMEM_DVA(am));
393 
394 	sc->sc_mbox_am = ami_allocmem(sc, sizeof(struct ami_iocmd));
395 	if (sc->sc_mbox_am == NULL) {
396 		printf(": unable to allocate mbox\n");
397 		goto free_idata;
398 	}
399 	sc->sc_mbox = (volatile struct ami_iocmd *)AMIMEM_KVA(sc->sc_mbox_am);
400 	sc->sc_mbox_pa = htole32(AMIMEM_DVA(sc->sc_mbox_am));
401 	AMI_DPRINTF(AMI_D_CMD, ("mbox=%p ", sc->sc_mbox));
402 	AMI_DPRINTF(AMI_D_CMD, ("mbox_pa=0x%llx ", (long long)sc->sc_mbox_pa));
403 
404 	/* create a spartan ccb for use with ami_poll */
405 	bzero(&iccb, sizeof(iccb));
406 	iccb.ccb_sc = sc;
407 	iccb.ccb_done = ami_done_init;
408 	cmd = &iccb.ccb_cmd;
409 
410 	(sc->sc_init)(sc);
411 
412 	/* try FC inquiry first */
413 	cmd->acc_cmd = AMI_FCOP;
414 	cmd->acc_io.aio_channel = AMI_FC_EINQ3;
415 	cmd->acc_io.aio_param = AMI_FC_EINQ3_SOLICITED_FULL;
416 	cmd->acc_io.aio_data = pa;
417 	if (ami_poll(sc, &iccb) == 0) {
418 		einq = AMIMEM_KVA(am);
419 		pi = AMIMEM_KVA(am);
420 
421 		sc->sc_nunits = einq->ain_nlogdrv;
422 		sc->sc_drvinscnt = einq->ain_drvinscnt + 1; /* force scan */
423 		ami_copyhds(sc, einq->ain_ldsize, einq->ain_ldprop,
424 		    einq->ain_ldstat);
425 
426 		cmd->acc_cmd = AMI_FCOP;
427 		cmd->acc_io.aio_channel = AMI_FC_PRODINF;
428 		cmd->acc_io.aio_param = 0;
429 		cmd->acc_io.aio_data = pa;
430 		if (ami_poll(sc, &iccb) == 0) {
431 			sc->sc_maxunits = AMI_BIG_MAX_LDRIVES;
432 
433 			bcopy (pi->api_fwver, sc->sc_fwver, 16);
434 			sc->sc_fwver[15] = '\0';
435 			bcopy (pi->api_biosver, sc->sc_biosver, 16);
436 			sc->sc_biosver[15] = '\0';
437 			sc->sc_channels = pi->api_channels;
438 			sc->sc_targets = pi->api_fcloops;
439 			sc->sc_memory = letoh16(pi->api_ramsize);
440 			sc->sc_maxcmds = pi->api_maxcmd;
441 			p = "FC loop";
442 		}
443 	}
444 
445 	if (sc->sc_maxunits == 0) {
446 		inq = AMIMEM_KVA(am);
447 
448 		cmd->acc_cmd = AMI_EINQUIRY;
449 		cmd->acc_io.aio_channel = 0;
450 		cmd->acc_io.aio_param = 0;
451 		cmd->acc_io.aio_data = pa;
452 		if (ami_poll(sc, &iccb) != 0) {
453 			cmd->acc_cmd = AMI_INQUIRY;
454 			cmd->acc_io.aio_channel = 0;
455 			cmd->acc_io.aio_param = 0;
456 			cmd->acc_io.aio_data = pa;
457 			if (ami_poll(sc, &iccb) != 0) {
458 				printf(": cannot do inquiry\n");
459 				goto free_mbox;
460 			}
461 		}
462 
463 		sc->sc_maxunits = AMI_MAX_LDRIVES;
464 		sc->sc_nunits = inq->ain_nlogdrv;
465 		ami_copyhds(sc, inq->ain_ldsize, inq->ain_ldprop,
466 		    inq->ain_ldstat);
467 
468 		bcopy (inq->ain_fwver, sc->sc_fwver, 4);
469 		sc->sc_fwver[4] = '\0';
470 		bcopy (inq->ain_biosver, sc->sc_biosver, 4);
471 		sc->sc_biosver[4] = '\0';
472 		sc->sc_channels = inq->ain_channels;
473 		sc->sc_targets = inq->ain_targets;
474 		sc->sc_memory = inq->ain_ramsize;
475 		sc->sc_maxcmds = inq->ain_maxcmd;
476 		sc->sc_drvinscnt = inq->ain_drvinscnt + 1; /* force scan */
477 		p = "target";
478 	}
479 
480 	if (sc->sc_flags & AMI_BROKEN) {
481 		sc->sc_link.openings = 1;
482 		sc->sc_maxcmds = 1;
483 		sc->sc_maxunits = 1;
484 	} else {
485 		sc->sc_maxunits = AMI_BIG_MAX_LDRIVES;
486 		if (sc->sc_maxcmds > AMI_MAXCMDS)
487 			sc->sc_maxcmds = AMI_MAXCMDS;
488 		/*
489 		 * Reserve ccb's for ioctl's and raw commands to
490 		 * processors/enclosures by lowering the number of
491 		 * openings available for logical units.
492 		 */
493 		sc->sc_maxcmds -= AMI_MAXIOCTLCMDS + AMI_MAXPROCS *
494 		    AMI_MAXRAWCMDS * sc->sc_channels;
495 
496 		sc->sc_link.openings = sc->sc_maxcmds;
497 	}
498 
499 	if (ami_alloc_ccbs(sc, AMI_MAXCMDS + 1) != 0) {
500 		/* error already printed */
501 		goto free_mbox;
502 	}
503 
504 	ami_freemem(sc, am);
505 
506 	/* hack for hp netraid version encoding */
507 	if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' &&
508 	    sc->sc_fwver[1] < ' ' && sc->sc_fwver[0] < ' ' &&
509 	    'A' <= sc->sc_biosver[2] && sc->sc_biosver[2] <= 'Z' &&
510 	    sc->sc_biosver[1] < ' ' && sc->sc_biosver[0] < ' ') {
511 
512 		snprintf(sc->sc_fwver, sizeof sc->sc_fwver, "%c.%02d.%02d",
513 		    sc->sc_fwver[2], sc->sc_fwver[1], sc->sc_fwver[0]);
514 		snprintf(sc->sc_biosver, sizeof sc->sc_biosver, "%c.%02d.%02d",
515 		    sc->sc_biosver[2], sc->sc_biosver[1], sc->sc_biosver[0]);
516 	}
517 
518 	/* TODO: fetch & print cache strategy */
519 	/* TODO: fetch & print scsi and raid info */
520 
521 	sc->sc_link.adapter_softc = sc;
522 	sc->sc_link.adapter = &ami_switch;
523 	sc->sc_link.adapter_target = sc->sc_maxunits;
524 	sc->sc_link.adapter_buswidth = sc->sc_maxunits;
525 	sc->sc_link.pool = &sc->sc_iopool;
526 
527 #ifdef AMI_DEBUG
528 	printf(", FW %s, BIOS v%s, %dMB RAM\n"
529 	    "%s: %d channels, %d %ss, %d logical drives, "
530 	    "openings %d, max commands %d, quirks: %04x\n",
531 	    sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc),
532 	    sc->sc_channels, sc->sc_targets, p, sc->sc_nunits,
533 	    sc->sc_link.openings, sc->sc_maxcmds, sc->sc_flags);
534 #else
535 	printf(", FW %s, BIOS v%s, %dMB RAM\n"
536 	    "%s: %d channels, %d %ss, %d logical drives\n",
537 	    sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc),
538 	    sc->sc_channels, sc->sc_targets, p, sc->sc_nunits);
539 #endif /* AMI_DEBUG */
540 
541 	if (sc->sc_flags & AMI_BROKEN && sc->sc_nunits > 1)
542 		printf("%s: firmware buggy, limiting access to first logical "
543 		    "disk\n", DEVNAME(sc));
544 
545 	/* lock around ioctl requests */
546 	rw_init(&sc->sc_lock, NULL);
547 
548 	bzero(&saa, sizeof(saa));
549 	saa.saa_sc_link = &sc->sc_link;
550 
551 	config_found(&sc->sc_dev, &saa, scsiprint);
552 
553 	/* can't do bioctls, sensors, or pass-through on broken devices */
554 	if (sc->sc_flags & AMI_BROKEN)
555 		return (0);
556 
557 #if NBIO > 0
558 	if (bio_register(&sc->sc_dev, ami_ioctl) != 0)
559 		printf("%s: controller registration failed\n", DEVNAME(sc));
560 	else
561 		sc->sc_ioctl = ami_ioctl;
562 
563 #ifndef SMALL_KERNEL
564 	if (ami_create_sensors(sc) != 0)
565 		printf("%s: unable to create sensors\n", DEVNAME(sc));
566 #endif
567 #endif
568 
569 	rsc = malloc(sizeof(struct ami_rawsoftc) * sc->sc_channels,
570 	    M_DEVBUF, M_NOWAIT|M_ZERO);
571 	if (!rsc) {
572 		printf("%s: no memory for raw interface\n", DEVNAME(sc));
573 		return (0);
574 	}
575 
576 	for (sc->sc_rawsoftcs = rsc;
577 	     rsc < &sc->sc_rawsoftcs[sc->sc_channels]; rsc++) {
578 
579 		struct scsibus_softc *ptbus;
580 		struct scsi_link *proclink;
581 		struct device *procdev;
582 
583 		rsc->sc_softc = sc;
584 		rsc->sc_channel = rsc - sc->sc_rawsoftcs;
585 		rsc->sc_link.openings = sc->sc_maxcmds;
586 		rsc->sc_link.adapter_softc = rsc;
587 		rsc->sc_link.adapter = &ami_raw_switch;
588 		rsc->sc_proctarget = -1;
589 		/* TODO fetch it from the controller */
590 		rsc->sc_link.adapter_target = 16;
591 		rsc->sc_link.adapter_buswidth = 16;
592 		rsc->sc_link.pool = &sc->sc_iopool;
593 
594 		bzero(&saa, sizeof(saa));
595 		saa.saa_sc_link = &rsc->sc_link;
596 
597 		ptbus = (struct scsibus_softc *)config_found(&sc->sc_dev,
598 		    &saa, scsiprint);
599 
600 		if (ptbus == NULL || rsc->sc_proctarget == -1)
601 			continue;
602 
603 		proclink = scsi_get_link(ptbus, rsc->sc_proctarget, 0);
604 		if (proclink == NULL)
605 			continue;
606 
607 		procdev = proclink->device_softc;
608 		strlcpy(rsc->sc_procdev, procdev->dv_xname,
609 		    sizeof(rsc->sc_procdev));
610 	}
611 
612 	return (0);
613 
614 free_mbox:
615 	ami_freemem(sc, sc->sc_mbox_am);
616 free_idata:
617 	ami_freemem(sc, am);
618 
619 	return (1);
620 }
621 
622 int
623 ami_quartz_init(struct ami_softc *sc)
624 {
625 	ami_write(sc, AMI_QIDB, 0);
626 
627 	return (0);
628 }
629 
630 int
631 ami_quartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd)
632 {
633 	if (sc->sc_mbox->acc_busy) {
634 		AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
635 		return (EBUSY);
636 	}
637 
638 	memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16);
639 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
640 	    sizeof(struct ami_iocmd), BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
641 
642 	sc->sc_mbox->acc_busy = 1;
643 	sc->sc_mbox->acc_poll = 0;
644 	sc->sc_mbox->acc_ack = 0;
645 
646 	ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC));
647 
648 	return (0);
649 }
650 
651 int
652 ami_quartz_done(struct ami_softc *sc, struct ami_iocmd *mbox)
653 {
654 	u_int32_t i, n;
655 	u_int8_t nstat, status;
656 	u_int8_t completed[AMI_MAXSTATACK];
657 
658 	if (ami_read(sc, AMI_QODB) != AMI_QODB_READY)
659 		return (0); /* nothing to do */
660 
661 	ami_write(sc, AMI_QODB, AMI_QODB_READY);
662 
663 	/*
664 	 * The following sequence is not supposed to have a timeout clause
665 	 * since the firmware has a "guarantee" that all commands will
666 	 * complete.  The choice is either panic or hoping for a miracle
667 	 * and that the IOs will complete much later.
668 	 */
669 	i = 0;
670 	while ((nstat = sc->sc_mbox->acc_nstat) == 0xff) {
671 		bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
672 		    sizeof(struct ami_iocmd), BUS_DMASYNC_POSTREAD);
673 		delay(1);
674 		if (i++ > 1000000)
675 			return (0); /* nothing to do */
676 	}
677 	sc->sc_mbox->acc_nstat = 0xff;
678 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
679 	    sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE);
680 
681 	/* wait until fw wrote out all completions */
682 	i = 0;
683 	AMI_DPRINTF(AMI_D_CMD, ("aqd %d ", nstat));
684 	for (n = 0; n < nstat; n++) {
685 		bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
686 		    sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD);
687 		while ((completed[n] = sc->sc_mbox->acc_cmplidl[n]) == 0xff) {
688 			delay(1);
689 			if (i++ > 1000000)
690 				return (0); /* nothing to do */
691 		}
692 		sc->sc_mbox->acc_cmplidl[n] = 0xff;
693 		bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
694 		    sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE);
695 	}
696 
697 	/* this should never happen, someone screwed up the completion status */
698 	if ((status = sc->sc_mbox->acc_status) == 0xff)
699 		panic("%s: status 0xff from the firmware", DEVNAME(sc));
700 
701 	sc->sc_mbox->acc_status = 0xff;
702 
703 	/* copy mailbox to temporary one and fixup other changed values */
704 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16,
705 	    BUS_DMASYNC_POSTWRITE);
706 	memcpy(mbox, (struct ami_iocmd *)sc->sc_mbox, 16);
707 	mbox->acc_nstat = nstat;
708 	mbox->acc_status = status;
709 	for (n = 0; n < nstat; n++)
710 		mbox->acc_cmplidl[n] = completed[n];
711 
712 	/* ack interrupt */
713 	ami_write(sc, AMI_QIDB, AMI_QIDB_ACK);
714 
715 	return (1);	/* ready to complete all IOs in acc_cmplidl */
716 }
717 
718 int
719 ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd)
720 {
721 	/* struct scsi_xfer *xs = ccb->ccb_xs; */
722 	u_int32_t i;
723 	u_int8_t status;
724 
725 	splassert(IPL_BIO);
726 
727 	if (sc->sc_dis_poll)
728 		return (-1); /* fail */
729 
730 	i = 0;
731 	while (sc->sc_mbox->acc_busy && (i < AMI_MAX_BUSYWAIT)) {
732 		delay(1);
733 		i++;
734 	}
735 	if (sc->sc_mbox->acc_busy) {
736 		AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
737 		return (-1);
738 	}
739 
740 	memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16);
741 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16,
742 	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
743 
744 	sc->sc_mbox->acc_id = 0xfe;
745 	sc->sc_mbox->acc_busy = 1;
746 	sc->sc_mbox->acc_poll = 0;
747 	sc->sc_mbox->acc_ack = 0;
748 	sc->sc_mbox->acc_nstat = 0xff;
749 	sc->sc_mbox->acc_status = 0xff;
750 
751 	/* send command to firmware */
752 	ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC));
753 
754 	i = 0;
755 	while ((sc->sc_mbox->acc_nstat == 0xff) && (i < AMI_MAX_POLLWAIT)) {
756 		delay(1);
757 		i++;
758 	}
759 	if (i >= AMI_MAX_POLLWAIT) {
760 		printf("%s: command not accepted, polling disabled\n",
761 		    DEVNAME(sc));
762 		sc->sc_dis_poll = 1;
763 		return (-1);
764 	}
765 
766 	/* poll firmware */
767 	i = 0;
768 	while ((sc->sc_mbox->acc_poll != 0x77) && (i < AMI_MAX_POLLWAIT)) {
769 		delay(1);
770 		i++;
771 	}
772 	if (i >= AMI_MAX_POLLWAIT) {
773 		printf("%s: firmware didn't reply, polling disabled\n",
774 		    DEVNAME(sc));
775 		sc->sc_dis_poll = 1;
776 		return (-1);
777 	}
778 
779 	/* ack */
780 	ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_ACK));
781 
782 	i = 0;
783 	while((ami_read(sc, AMI_QIDB) & AMI_QIDB_ACK) &&
784 	    (i < AMI_MAX_POLLWAIT)) {
785 		delay(1);
786 		i++;
787 	}
788 	if (i >= AMI_MAX_POLLWAIT) {
789 		printf("%s: firmware didn't ack the ack, polling disabled\n",
790 		    DEVNAME(sc));
791 		sc->sc_dis_poll = 1;
792 		return (-1);
793 	}
794 
795 	sc->sc_mbox->acc_poll = 0;
796 	sc->sc_mbox->acc_ack = 0x77;
797 	status = sc->sc_mbox->acc_status;
798 	sc->sc_mbox->acc_nstat = 0xff;
799 	sc->sc_mbox->acc_status = 0xff;
800 
801 	for (i = 0; i < AMI_MAXSTATACK; i++)
802 		sc->sc_mbox->acc_cmplidl[i] = 0xff;
803 
804 	return (status);
805 }
806 
807 int
808 ami_schwartz_init(struct ami_softc *sc)
809 {
810 	u_int32_t a = (u_int32_t)sc->sc_mbox_pa;
811 
812 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AMI_SMBADDR, a);
813 	/* XXX 40bit address ??? */
814 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SMBENA, 0);
815 
816 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK);
817 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM, AMI_SEIM_ENA |
818 	    bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM));
819 
820 	return (0);
821 }
822 
823 int
824 ami_schwartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd)
825 {
826 	if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
827 	    AMI_SMBST_BUSY) {
828 		AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
829 		return (EBUSY);
830 	}
831 
832 	memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16);
833 	sc->sc_mbox->acc_busy = 1;
834 	sc->sc_mbox->acc_poll = 0;
835 	sc->sc_mbox->acc_ack = 0;
836 
837 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC);
838 	return (0);
839 }
840 
841 int
842 ami_schwartz_done(struct ami_softc *sc, struct ami_iocmd *mbox)
843 {
844 	u_int8_t stat;
845 
846 #if 0
847 	/* do not scramble the busy mailbox */
848 	if (sc->sc_mbox->acc_busy)
849 		return (0);
850 #endif
851 	if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
852 	    AMI_SMBST_BUSY)
853 		return (0);
854 
855 	stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT);
856 	if (stat & AMI_ISTAT_PEND) {
857 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, stat);
858 
859 		*mbox = *sc->sc_mbox;
860 		AMI_DPRINTF(AMI_D_CMD, ("asd %d ", mbox->acc_nstat));
861 
862 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD,
863 		    AMI_SCMD_ACK);
864 
865 		return (1);
866 	}
867 
868 	return (0);
869 }
870 
871 int
872 ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox)
873 {
874 	u_int8_t status;
875 	u_int32_t i;
876 	int rv;
877 
878 	splassert(IPL_BIO);
879 
880 	if (sc->sc_dis_poll)
881 		return (-1); /* fail */
882 
883 	for (i = 0; i < AMI_MAX_POLLWAIT; i++) {
884 		if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
885 		    AMI_SMBST_BUSY))
886 			break;
887 		delay(1);
888 	}
889 	if (i >= AMI_MAX_POLLWAIT) {
890 		AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
891 		return (-1);
892 	}
893 
894 	memcpy((struct ami_iocmd *)sc->sc_mbox, mbox, 16);
895 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16,
896 	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
897 
898 	sc->sc_mbox->acc_busy = 1;
899 	sc->sc_mbox->acc_poll = 0;
900 	sc->sc_mbox->acc_ack = 0;
901 	/* send command to firmware */
902 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC);
903 
904 	/* wait until no longer busy */
905 	for (i = 0; i < AMI_MAX_POLLWAIT; i++) {
906 		if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
907 		    AMI_SMBST_BUSY))
908 			break;
909 		delay(1);
910 	}
911 	if (i >= AMI_MAX_POLLWAIT) {
912 		printf("%s: command not accepted, polling disabled\n",
913 		    DEVNAME(sc));
914 		sc->sc_dis_poll = 1;
915 		return (-1);
916 	}
917 
918 	/* wait for interrupt bit */
919 	for (i = 0; i < AMI_MAX_POLLWAIT; i++) {
920 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT);
921 		if (status & AMI_ISTAT_PEND)
922 			break;
923 		delay(1);
924 	}
925 	if (i >= AMI_MAX_POLLWAIT) {
926 		printf("%s: interrupt didn't arrive, polling disabled\n",
927 		    DEVNAME(sc));
928 		sc->sc_dis_poll = 1;
929 		return (-1);
930 	}
931 
932 	/* write ststus back to firmware */
933 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, status);
934 
935 	/* copy mailbox and status back */
936 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
937 	    sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD);
938 	*mbox = *sc->sc_mbox;
939 	rv = sc->sc_mbox->acc_status;
940 
941 	/* ack interrupt */
942 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK);
943 
944 	return (rv);
945 }
946 
947 void
948 ami_start_xs(struct ami_softc *sc, struct ami_ccb *ccb, struct scsi_xfer *xs)
949 {
950 	if (xs->flags & SCSI_POLL)
951 		ami_complete(sc, ccb, xs->timeout);
952 	else
953 		ami_start(sc, ccb);
954 }
955 
956 void
957 ami_start(struct ami_softc *sc, struct ami_ccb *ccb)
958 {
959 	mtx_enter(&sc->sc_cmd_mtx);
960 	ccb->ccb_state = AMI_CCB_PREQUEUED;
961 	TAILQ_INSERT_TAIL(&sc->sc_ccb_preq, ccb, ccb_link);
962 	mtx_leave(&sc->sc_cmd_mtx);
963 
964 	ami_runqueue(sc);
965 }
966 
967 void
968 ami_runqueue_tick(void *arg)
969 {
970 	ami_runqueue(arg);
971 }
972 
973 void
974 ami_runqueue(struct ami_softc *sc)
975 {
976 	struct ami_ccb *ccb;
977 	int add = 0;
978 
979 	mtx_enter(&sc->sc_cmd_mtx);
980 	if (!sc->sc_drainio) {
981 		while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) {
982 			if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) {
983 				add = 1;
984 				break;
985 			}
986 
987 			TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link);
988 			ccb->ccb_state = AMI_CCB_QUEUED;
989 			TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
990 		}
991 	}
992 	mtx_leave(&sc->sc_cmd_mtx);
993 
994 	if (add)
995 		timeout_add(&sc->sc_run_tmo, 1);
996 }
997 
998 int
999 ami_poll(struct ami_softc *sc, struct ami_ccb *ccb)
1000 {
1001 	int error;
1002 
1003 	mtx_enter(&sc->sc_cmd_mtx);
1004 	error = sc->sc_poll(sc, &ccb->ccb_cmd);
1005 	if (error == -1)
1006 		ccb->ccb_flags |= AMI_CCB_F_ERR;
1007 	mtx_leave(&sc->sc_cmd_mtx);
1008 
1009 	ccb->ccb_done(sc, ccb);
1010 
1011 	return (error);
1012 }
1013 
1014 void
1015 ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout)
1016 {
1017 	void (*done)(struct ami_softc *, struct ami_ccb *);
1018 	int ready;
1019 	int i = 0;
1020 	int s;
1021 
1022 	done = ccb->ccb_done;
1023 	ccb->ccb_done = ami_done_dummy;
1024 
1025 	/*
1026 	 * since exec will return if the mbox is busy we have to busy wait
1027 	 * ourselves. once its in, jam it into the runq.
1028 	 */
1029 	mtx_enter(&sc->sc_cmd_mtx);
1030 	while (i < AMI_MAX_BUSYWAIT) {
1031 		if (sc->sc_exec(sc, &ccb->ccb_cmd) == 0) {
1032 			ccb->ccb_state = AMI_CCB_QUEUED;
1033 			TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
1034 			break;
1035 		}
1036 		DELAY(1000);
1037 		i++;
1038 	}
1039 	ready = (ccb->ccb_state == AMI_CCB_QUEUED);
1040 	mtx_leave(&sc->sc_cmd_mtx);
1041 
1042 	if (!ready) {
1043 		ccb->ccb_flags |= AMI_CCB_F_ERR;
1044 		ccb->ccb_state = AMI_CCB_READY;
1045 		goto done;
1046 	}
1047 
1048 	/*
1049 	 * Override timeout for PERC3.  The first command triggers a chip
1050 	 * reset on the QL12160 chip which causes the firmware to reload.
1051 	 * 30000 is slightly less than double of how long it takes for the
1052 	 * firmware to be up again.  After the first two commands the
1053 	 * timeouts are as expected.
1054 	 */
1055 	timeout = MAX(30000, timeout); /* timeout */
1056 
1057 	while (ccb->ccb_state == AMI_CCB_QUEUED) {
1058 		s = splbio(); /* interrupt handlers are called at their IPL */
1059 		ready = ami_intr(sc);
1060 		splx(s);
1061 
1062 		if (ready == 0) {
1063 			if (timeout-- == 0) {
1064 				/* XXX */
1065 				printf("%s: timeout\n", DEVNAME(sc));
1066 				return;
1067 			}
1068 
1069 			delay(1000);
1070 			continue;
1071 		}
1072 	}
1073 
1074 done:
1075 	done(sc, ccb);
1076 }
1077 
1078 void
1079 ami_done_pt(struct ami_softc *sc, struct ami_ccb *ccb)
1080 {
1081 	struct scsi_xfer *xs = ccb->ccb_xs;
1082 	struct scsi_link *link = xs->sc_link;
1083 	struct ami_rawsoftc *rsc = link->adapter_softc;
1084 	u_int8_t target = link->target, type;
1085 
1086 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
1087 	    ccb->ccb_offset, sizeof(struct ami_ccbmem),
1088 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1089 
1090 	if (xs->data != NULL) {
1091 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1092 		    ccb->ccb_dmamap->dm_mapsize,
1093 		    (xs->flags & SCSI_DATA_IN) ?
1094 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1095 
1096 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
1097 	}
1098 
1099 	xs->resid = 0;
1100 
1101 	if (ccb->ccb_flags & AMI_CCB_F_ERR)
1102 		xs->error = XS_DRIVER_STUFFUP;
1103  	else if (ccb->ccb_status != 0x00)
1104 		xs->error = XS_DRIVER_STUFFUP;
1105 	else if (xs->flags & SCSI_POLL && xs->cmd->opcode == INQUIRY) {
1106 		type = ((struct scsi_inquiry_data *)xs->data)->device &
1107 		    SID_TYPE;
1108 		if (!(type == T_PROCESSOR || type == T_ENCLOSURE))
1109 			xs->error = XS_DRIVER_STUFFUP;
1110 		else
1111 			rsc->sc_proctarget = target;
1112 	}
1113 
1114 	scsi_done(xs);
1115 }
1116 
1117 void
1118 ami_done_xs(struct ami_softc *sc, struct ami_ccb *ccb)
1119 {
1120 	struct scsi_xfer *xs = ccb->ccb_xs;
1121 
1122 	if (xs->data != NULL) {
1123 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1124 		    ccb->ccb_dmamap->dm_mapsize,
1125 		    (xs->flags & SCSI_DATA_IN) ?
1126 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1127 
1128 		bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
1129 		    ccb->ccb_offset, sizeof(struct ami_ccbmem),
1130 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1131 
1132 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
1133 	}
1134 
1135 	xs->resid = 0;
1136 
1137 	if (ccb->ccb_flags & AMI_CCB_F_ERR)
1138 		xs->error = XS_DRIVER_STUFFUP;
1139 
1140 	scsi_done(xs);
1141 }
1142 
1143 void
1144 ami_done_flush(struct ami_softc *sc, struct ami_ccb *ccb)
1145 {
1146 	struct scsi_xfer *xs = ccb->ccb_xs;
1147 	struct ami_iocmd *cmd = &ccb->ccb_cmd;
1148 
1149 	if (ccb->ccb_flags & AMI_CCB_F_ERR) {
1150 		xs->error = XS_DRIVER_STUFFUP;
1151 		xs->resid = 0;
1152 
1153 		scsi_done(xs);
1154 		return;
1155 	}
1156 
1157 	/* reuse the ccb for the sysflush command */
1158 	ccb->ccb_done = ami_done_sysflush;
1159 	cmd->acc_cmd = AMI_SYSFLUSH;
1160 
1161 	ami_start_xs(sc, ccb, xs);
1162 }
1163 
1164 void
1165 ami_done_sysflush(struct ami_softc *sc, struct ami_ccb *ccb)
1166 {
1167 	struct scsi_xfer *xs = ccb->ccb_xs;
1168 
1169 	xs->resid = 0;
1170 	if (ccb->ccb_flags & AMI_CCB_F_ERR)
1171 		xs->error = XS_DRIVER_STUFFUP;
1172 
1173 	scsi_done(xs);
1174 }
1175 
1176 void
1177 ami_done_dummy(struct ami_softc *sc, struct ami_ccb *ccb)
1178 {
1179 }
1180 
1181 void
1182 ami_done_ioctl(struct ami_softc *sc, struct ami_ccb *ccb)
1183 {
1184 	wakeup(ccb);
1185 }
1186 
1187 void
1188 ami_done_init(struct ami_softc *sc, struct ami_ccb *ccb)
1189 {
1190 	/* the ccb is going to be reused, so do nothing with it */
1191 }
1192 
1193 void
1194 amiminphys(struct buf *bp, struct scsi_link *sl)
1195 {
1196 	if (bp->b_bcount > AMI_MAXFER)
1197 		bp->b_bcount = AMI_MAXFER;
1198 	minphys(bp);
1199 }
1200 
1201 void
1202 ami_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size)
1203 {
1204 	size_t copy_cnt;
1205 
1206 	AMI_DPRINTF(AMI_D_MISC, ("ami_copy_internal_data "));
1207 
1208 	if (!xs->datalen)
1209 		printf("uio move not yet supported\n");
1210 	else {
1211 		copy_cnt = MIN(size, xs->datalen);
1212 		bcopy(v, xs->data, copy_cnt);
1213 	}
1214 }
1215 
1216 void
1217 ami_scsi_raw_cmd(struct scsi_xfer *xs)
1218 {
1219 	struct scsi_link *link = xs->sc_link;
1220 	struct ami_rawsoftc *rsc = link->adapter_softc;
1221 	struct ami_softc *sc = rsc->sc_softc;
1222 	u_int8_t channel = rsc->sc_channel, target = link->target;
1223 	struct ami_ccb *ccb;
1224 
1225 	AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_raw_cmd "));
1226 
1227 	if (xs->cmdlen > AMI_MAX_CDB) {
1228 		AMI_DPRINTF(AMI_D_CMD, ("CDB too big %p ", xs));
1229 		bzero(&xs->sense, sizeof(xs->sense));
1230 		xs->sense.error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT;
1231 		xs->sense.flags = SKEY_ILLEGAL_REQUEST;
1232 		xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
1233 		xs->error = XS_SENSE;
1234 		scsi_done(xs);
1235 		return;
1236 	}
1237 
1238 	xs->error = XS_NOERROR;
1239 
1240 	ccb = xs->io;
1241 
1242 	memset(ccb->ccb_pt, 0, sizeof(struct ami_passthrough));
1243 
1244 	ccb->ccb_xs = xs;
1245 	ccb->ccb_done = ami_done_pt;
1246 
1247 	ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU;
1248 	ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa;
1249 
1250 	ccb->ccb_pt->apt_param = AMI_PTPARAM(AMI_TIMEOUT_6,1,0);
1251 	ccb->ccb_pt->apt_channel = channel;
1252 	ccb->ccb_pt->apt_target = target;
1253 	bcopy(xs->cmd, ccb->ccb_pt->apt_cdb, AMI_MAX_CDB);
1254 	ccb->ccb_pt->apt_ncdb = xs->cmdlen;
1255 	ccb->ccb_pt->apt_nsense = AMI_MAX_SENSE;
1256 	ccb->ccb_pt->apt_datalen = xs->datalen;
1257 	ccb->ccb_pt->apt_data = 0;
1258 
1259 	if (ami_load_ptmem(sc, ccb, xs->data, xs->datalen,
1260 	    xs->flags & SCSI_DATA_IN, xs->flags & SCSI_NOSLEEP) != 0) {
1261 		xs->error = XS_DRIVER_STUFFUP;
1262 		scsi_done(xs);
1263 		return;
1264 	}
1265 
1266 	ami_start_xs(sc, ccb, xs);
1267 }
1268 
1269 int
1270 ami_load_ptmem(struct ami_softc *sc, struct ami_ccb *ccb, void *data,
1271     size_t len, int read, int nowait)
1272 {
1273 	bus_dmamap_t dmap = ccb->ccb_dmamap;
1274 	bus_dma_segment_t *sgd;
1275 	int error, i;
1276 
1277 	if (data != NULL) {
1278 		error = bus_dmamap_load(sc->sc_dmat, dmap, data, len, NULL,
1279 		    nowait ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
1280 		if (error) {
1281 			if (error == EFBIG)
1282 				printf("more than %d dma segs\n",
1283 				    AMI_MAXOFFSETS);
1284 			else
1285 				printf("error %d loading dma map\n", error);
1286 
1287 			return (1);
1288 		}
1289 
1290 		sgd = dmap->dm_segs;
1291 		if (dmap->dm_nsegs > 1) {
1292 			struct ami_sgent *sgl = ccb->ccb_sglist;
1293 
1294 			ccb->ccb_pt->apt_nsge = dmap->dm_nsegs;
1295 			ccb->ccb_pt->apt_data = ccb->ccb_sglistpa;
1296 
1297 			for (i = 0; i < dmap->dm_nsegs; i++) {
1298 				sgl[i].asg_addr = htole32(sgd[i].ds_addr);
1299 				sgl[i].asg_len = htole32(sgd[i].ds_len);
1300 			}
1301 		} else {
1302 			ccb->ccb_pt->apt_nsge = 0;
1303 			ccb->ccb_pt->apt_data = htole32(sgd->ds_addr);
1304 		}
1305 
1306 		bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
1307 		    read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1308 	}
1309 
1310 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
1311 	    ccb->ccb_offset, sizeof(struct ami_ccbmem),
1312 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1313 
1314 	return (0);
1315 }
1316 
1317 void
1318 ami_scsi_cmd(struct scsi_xfer *xs)
1319 {
1320 	struct scsi_link *link = xs->sc_link;
1321 	struct ami_softc *sc = link->adapter_softc;
1322 	struct device *dev = link->device_softc;
1323 	struct ami_ccb *ccb;
1324 	struct ami_iocmd *cmd;
1325 	struct scsi_inquiry_data inq;
1326 	struct scsi_sense_data sd;
1327 	struct scsi_read_cap_data rcd;
1328 	u_int8_t target = link->target;
1329 	u_int32_t blockno, blockcnt;
1330 	struct scsi_rw *rw;
1331 	struct scsi_rw_big *rwb;
1332 	bus_dma_segment_t *sgd;
1333 	int error;
1334 	int i;
1335 
1336 	AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd "));
1337 
1338 	if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present ||
1339 	    link->lun != 0) {
1340 		AMI_DPRINTF(AMI_D_CMD, ("no target %d ", target));
1341 		/* XXX should be XS_SENSE and sense filled out */
1342 		xs->error = XS_DRIVER_STUFFUP;
1343 		scsi_done(xs);
1344 		return;
1345 	}
1346 
1347 	xs->error = XS_NOERROR;
1348 
1349 	switch (xs->cmd->opcode) {
1350 	case READ_COMMAND:
1351 	case READ_BIG:
1352 	case WRITE_COMMAND:
1353 	case WRITE_BIG:
1354 		/* deal with io outside the switch */
1355 		break;
1356 
1357 	case SYNCHRONIZE_CACHE:
1358 		ccb = xs->io;
1359 
1360 		ccb->ccb_xs = xs;
1361 		ccb->ccb_done = ami_done_flush;
1362 		if (xs->timeout < 30000)
1363 			xs->timeout = 30000;	/* at least 30sec */
1364 
1365 		cmd = &ccb->ccb_cmd;
1366 		cmd->acc_cmd = AMI_FLUSH;
1367 
1368 		return (ami_start_xs(sc, ccb, xs));
1369 
1370 	case TEST_UNIT_READY:
1371 		/* save off sd? after autoconf */
1372 		if (!cold)	/* XXX bogus */
1373 			strlcpy(sc->sc_hdr[target].dev, dev->dv_xname,
1374 			    sizeof(sc->sc_hdr[target].dev));
1375 	case START_STOP:
1376 #if 0
1377 	case VERIFY:
1378 #endif
1379 	case PREVENT_ALLOW:
1380 		AMI_DPRINTF(AMI_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode,
1381 		    target));
1382 		xs->error = XS_NOERROR;
1383 		scsi_done(xs);
1384 		return;
1385 
1386 	case REQUEST_SENSE:
1387 		AMI_DPRINTF(AMI_D_CMD, ("REQUEST SENSE tgt %d ", target));
1388 		bzero(&sd, sizeof(sd));
1389 		sd.error_code = SSD_ERRCODE_CURRENT;
1390 		sd.segment = 0;
1391 		sd.flags = SKEY_NO_SENSE;
1392 		*(u_int32_t*)sd.info = htole32(0);
1393 		sd.extra_len = 0;
1394 		ami_copy_internal_data(xs, &sd, sizeof(sd));
1395 
1396 		xs->error = XS_NOERROR;
1397 		scsi_done(xs);
1398 		return;
1399 
1400 	case INQUIRY:
1401 		if (ISSET(((struct scsi_inquiry *)xs->cmd)->flags, SI_EVPD)) {
1402 			xs->error = XS_DRIVER_STUFFUP;
1403 			scsi_done(xs);
1404 			return;
1405 		}
1406 
1407 		AMI_DPRINTF(AMI_D_CMD, ("INQUIRY tgt %d ", target));
1408 		bzero(&inq, sizeof(inq));
1409 		inq.device = T_DIRECT;
1410 		inq.dev_qual2 = 0;
1411 		inq.version = 2;
1412 		inq.response_format = 2;
1413 		inq.additional_length = 32;
1414 		inq.flags |= SID_CmdQue;
1415 		strlcpy(inq.vendor, "AMI    ", sizeof(inq.vendor));
1416 		snprintf(inq.product, sizeof(inq.product),
1417 		    "Host drive  #%02d", target);
1418 		strlcpy(inq.revision, "   ", sizeof(inq.revision));
1419 		ami_copy_internal_data(xs, &inq, sizeof(inq));
1420 
1421 		xs->error = XS_NOERROR;
1422 		scsi_done(xs);
1423 		return;
1424 
1425 	case READ_CAPACITY:
1426 		AMI_DPRINTF(AMI_D_CMD, ("READ CAPACITY tgt %d ", target));
1427 		bzero(&rcd, sizeof(rcd));
1428 		_lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr);
1429 		_lto4b(AMI_SECTOR_SIZE, rcd.length);
1430 		ami_copy_internal_data(xs, &rcd, sizeof(rcd));
1431 
1432 		xs->error = XS_NOERROR;
1433 		scsi_done(xs);
1434 		return;
1435 
1436 	default:
1437 		AMI_DPRINTF(AMI_D_CMD, ("unsupported scsi command %#x tgt %d ",
1438 		    xs->cmd->opcode, target));
1439 
1440 		xs->error = XS_DRIVER_STUFFUP;
1441 		scsi_done(xs);
1442 		return;
1443 	}
1444 
1445 	/* A read or write operation. */
1446 	if (xs->cmdlen == 6) {
1447 		rw = (struct scsi_rw *)xs->cmd;
1448 		blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
1449 		blockcnt = rw->length ? rw->length : 0x100;
1450 	} else {
1451 		rwb = (struct scsi_rw_big *)xs->cmd;
1452 		blockno = _4btol(rwb->addr);
1453 		blockcnt = _2btol(rwb->length);
1454 	}
1455 
1456 	if (blockno >= sc->sc_hdr[target].hd_size ||
1457 	    blockno + blockcnt > sc->sc_hdr[target].hd_size) {
1458 		printf("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc),
1459 		    blockno, blockcnt, sc->sc_hdr[target].hd_size);
1460 		xs->error = XS_DRIVER_STUFFUP;
1461 		scsi_done(xs);
1462 		return;
1463 	}
1464 
1465 	ccb = xs->io;
1466 
1467 	ccb->ccb_xs = xs;
1468 	ccb->ccb_done = ami_done_xs;
1469 
1470 	cmd = &ccb->ccb_cmd;
1471 	cmd->acc_cmd = (xs->flags & SCSI_DATA_IN) ? AMI_READ : AMI_WRITE;
1472 	cmd->acc_mbox.amb_nsect = htole16(blockcnt);
1473 	cmd->acc_mbox.amb_lba = htole32(blockno);
1474 	cmd->acc_mbox.amb_ldn = target;
1475 
1476 	error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap,
1477 	    xs->data, xs->datalen, NULL,
1478 	    (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
1479 	if (error) {
1480 		if (error == EFBIG)
1481 			printf("more than %d dma segs\n", AMI_MAXOFFSETS);
1482 		else
1483 			printf("error %d loading dma map\n", error);
1484 
1485 		xs->error = XS_DRIVER_STUFFUP;
1486 		scsi_done(xs);
1487 		return;
1488 	}
1489 
1490 	sgd = ccb->ccb_dmamap->dm_segs;
1491 	if (ccb->ccb_dmamap->dm_nsegs > 1) {
1492 		struct ami_sgent *sgl = ccb->ccb_sglist;
1493 
1494 		cmd->acc_mbox.amb_nsge = ccb->ccb_dmamap->dm_nsegs;
1495 		cmd->acc_mbox.amb_data = ccb->ccb_sglistpa;
1496 
1497 		for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) {
1498 			sgl[i].asg_addr = htole32(sgd[i].ds_addr);
1499 			sgl[i].asg_len = htole32(sgd[i].ds_len);
1500 		}
1501 	} else {
1502 		cmd->acc_mbox.amb_nsge = 0;
1503 		cmd->acc_mbox.amb_data = htole32(sgd->ds_addr);
1504 	}
1505 
1506 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
1507 	    ccb->ccb_offset, sizeof(struct ami_ccbmem),
1508 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1509 
1510 	bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1511 	    ccb->ccb_dmamap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ?
1512 	    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1513 
1514 	ami_start_xs(sc, ccb, xs);
1515 }
1516 
1517 int
1518 ami_intr(void *v)
1519 {
1520 	struct ami_iocmd mbox;
1521 	struct ami_softc *sc = v;
1522 	struct ami_ccb *ccb;
1523 	int i, rv = 0, ready;
1524 
1525 	mtx_enter(&sc->sc_cmd_mtx);
1526 	while (!TAILQ_EMPTY(&sc->sc_ccb_runq) && sc->sc_done(sc, &mbox)) {
1527 		AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat));
1528 		for (i = 0; i < mbox.acc_nstat; i++ ) {
1529 			ready = mbox.acc_cmplidl[i] - 1;
1530 			AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready));
1531 
1532 			ccb = &sc->sc_ccbs[ready];
1533 			ccb->ccb_status = mbox.acc_status;
1534 			ccb->ccb_state = AMI_CCB_READY;
1535 			TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link);
1536 
1537 			mtx_leave(&sc->sc_cmd_mtx);
1538 			ccb->ccb_done(sc, ccb);
1539 			mtx_enter(&sc->sc_cmd_mtx);
1540 
1541 			rv = 1;
1542 		}
1543 	}
1544 	ready = (sc->sc_drainio && TAILQ_EMPTY(&sc->sc_ccb_runq));
1545 	mtx_leave(&sc->sc_cmd_mtx);
1546 
1547 	if (ready)
1548 		wakeup(sc);
1549 	else if (rv)
1550 		ami_runqueue(sc);
1551 
1552 	AMI_DPRINTF(AMI_D_INTR, ("exit "));
1553 	return (rv);
1554 }
1555 
1556 int
1557 ami_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag)
1558 {
1559 	struct ami_softc *sc = (struct ami_softc *)link->adapter_softc;
1560 	/* struct device *dev = (struct device *)link->device_softc; */
1561 	/* u_int8_t target = link->target; */
1562 
1563 	if (sc->sc_ioctl)
1564 		return (sc->sc_ioctl(link->adapter_softc, cmd, addr));
1565 	else
1566 		return (ENOTTY);
1567 }
1568 
1569 #if NBIO > 0
1570 int
1571 ami_ioctl(struct device *dev, u_long cmd, caddr_t addr)
1572 {
1573 	struct ami_softc *sc = (struct ami_softc *)dev;
1574 	int error = 0;
1575 
1576 	AMI_DPRINTF(AMI_D_IOCTL, ("%s: ioctl ", DEVNAME(sc)));
1577 
1578 	if (sc->sc_flags & AMI_BROKEN)
1579 		return (ENODEV); /* can't do this to broken device for now */
1580 
1581 	switch (cmd) {
1582 	case BIOCINQ:
1583 		AMI_DPRINTF(AMI_D_IOCTL, ("inq "));
1584 		error = ami_ioctl_inq(sc, (struct bioc_inq *)addr);
1585 		break;
1586 
1587 	case BIOCVOL:
1588 		AMI_DPRINTF(AMI_D_IOCTL, ("vol "));
1589 		error = ami_ioctl_vol(sc, (struct bioc_vol *)addr);
1590 		break;
1591 
1592 	case BIOCDISK:
1593 		AMI_DPRINTF(AMI_D_IOCTL, ("disk "));
1594 		error = ami_ioctl_disk(sc, (struct bioc_disk *)addr);
1595 		break;
1596 
1597 	case BIOCALARM:
1598 		AMI_DPRINTF(AMI_D_IOCTL, ("alarm "));
1599 		error = ami_ioctl_alarm(sc, (struct bioc_alarm *)addr);
1600 		break;
1601 
1602 	case BIOCSETSTATE:
1603 		AMI_DPRINTF(AMI_D_IOCTL, ("setstate "));
1604 		error = ami_ioctl_setstate(sc, (struct bioc_setstate *)addr);
1605 		break;
1606 
1607 	default:
1608 		AMI_DPRINTF(AMI_D_IOCTL, (" invalid ioctl\n"));
1609 		error = EINVAL;
1610 	}
1611 
1612 	return (error);
1613 }
1614 
1615 int
1616 ami_drv_pt(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t *cmd,
1617     int clen, int blen, void *buf)
1618 {
1619 	struct ami_ccb *ccb;
1620 	struct ami_passthrough *pt;
1621 	int error = 0;
1622 
1623 	rw_enter_write(&sc->sc_lock);
1624 
1625 	ccb = scsi_io_get(&sc->sc_iopool, 0);
1626 	if (ccb == NULL) {
1627 		error = ENOMEM;
1628 		goto err;
1629 	}
1630 
1631 	ccb->ccb_done = ami_done_ioctl;
1632 
1633 	ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU;
1634 	ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa;
1635 
1636 	pt = ccb->ccb_pt;
1637 	memset(pt, 0, sizeof *pt);
1638 	pt->apt_channel = ch;
1639 	pt->apt_target = tg;
1640 	pt->apt_ncdb = clen;
1641 	pt->apt_nsense = sizeof(struct scsi_sense_data);
1642 	pt->apt_datalen = blen;
1643 	pt->apt_data = 0;
1644 
1645 	bcopy(cmd, pt->apt_cdb, clen);
1646 
1647 	if (ami_load_ptmem(sc, ccb, buf, blen, 1, 0) != 0) {
1648 		error = ENOMEM;
1649 		goto ptmemerr;
1650 	}
1651 
1652 	ami_start(sc, ccb);
1653 
1654 	while (ccb->ccb_state != AMI_CCB_READY)
1655 		tsleep(ccb, PRIBIO, "ami_drv_pt", 0);
1656 
1657 	bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1658 	    ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
1659 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
1660 	    ccb->ccb_offset, sizeof(struct ami_ccbmem),
1661 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1662 	bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
1663 
1664 	if (ccb->ccb_flags & AMI_CCB_F_ERR)
1665 		error = EIO;
1666 	else if (pt->apt_scsistat != 0x00)
1667 		error = EIO;
1668 
1669 ptmemerr:
1670 	scsi_io_put(&sc->sc_iopool, ccb);
1671 
1672 err:
1673 	rw_exit_write(&sc->sc_lock);
1674 	return (error);
1675 }
1676 
1677 int
1678 ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page,
1679     void *inqbuf)
1680 {
1681 	struct scsi_inquiry_data *inq = inqbuf;
1682 	u_int8_t cdb[6];
1683 	int error = 0;
1684 
1685 	bzero(&cdb, sizeof cdb);
1686 
1687 	cdb[0] = INQUIRY;
1688 	cdb[1] = 0;
1689 	cdb[2] = 0;
1690 	cdb[3] = 0;
1691 	cdb[4] = sizeof(struct scsi_inquiry_data);
1692 	cdb[5] = 0;
1693 	if (page != 0) {
1694 		cdb[1] = SI_EVPD;
1695 		cdb[2] = page;
1696 	}
1697 
1698 	error = ami_drv_pt(sc, ch, tg, cdb, 6, sizeof *inq, inqbuf);
1699 	if (error)
1700 		return (error);
1701 
1702 	if ((inq->device & SID_TYPE) != T_DIRECT)
1703 		error = EINVAL;
1704 
1705 	return (error);
1706 }
1707 
1708 int
1709 ami_drv_readcap(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, daddr_t *sz)
1710 {
1711 	struct scsi_read_cap_data *rcd = NULL;
1712 	struct scsi_read_cap_data_16 *rcd16 = NULL;
1713 	u_int8_t cdb[16];
1714 	u_int32_t blksz;
1715 	daddr_t noblk;
1716 	int error = 0;
1717 
1718 	bzero(&cdb, sizeof cdb);
1719 	cdb[0] = READ_CAPACITY;
1720 	rcd = dma_alloc(sizeof(*rcd), PR_WAITOK);
1721 
1722 	error = ami_drv_pt(sc, ch, tg, cdb, 10, sizeof(*rcd), rcd);
1723 	if (error)
1724 		goto fail;
1725 
1726 	noblk = _4btol(rcd->addr);
1727 	if (noblk == 0xffffffffllu) {
1728 		/* huge disk */
1729 		bzero(&cdb, sizeof cdb);
1730 		cdb[0] = READ_CAPACITY_16;
1731 		rcd16 = dma_alloc(sizeof(*rcd16), PR_WAITOK);
1732 
1733 		error = ami_drv_pt(sc, ch, tg, cdb, 16, sizeof(*rcd16), rcd16);
1734 		if (error)
1735 			goto fail;
1736 
1737 		noblk = _8btol(rcd16->addr);
1738 		blksz = _4btol(rcd16->length);
1739 	} else
1740 		blksz = _4btol(rcd->length);
1741 
1742 	if (blksz == 0)
1743 		blksz = 512;
1744 	*sz = noblk * blksz;
1745 
1746 fail:
1747 	if (rcd16)
1748 		dma_free(rcd16, sizeof(*rcd16));
1749 	dma_free(rcd, sizeof(*rcd));
1750 	return (error);
1751 }
1752 
1753 int
1754 ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
1755     u_int8_t par3, size_t size, void *buffer)
1756 {
1757 	struct ami_ccb *ccb;
1758 	struct ami_iocmd *cmd;
1759 	struct ami_mem *am = NULL;
1760 	char *idata = NULL;
1761 	int error = 0;
1762 
1763 	rw_enter_write(&sc->sc_lock);
1764 
1765 	if (opcode != AMI_CHSTATE) {
1766 		ccb = scsi_io_get(&sc->sc_iopool, 0);
1767 		if (ccb == NULL) {
1768 			error = ENOMEM;
1769 			goto err;
1770 		}
1771 		ccb->ccb_done = ami_done_ioctl;
1772 	} else
1773 		ccb = sc->sc_mgmtccb;
1774 
1775 	if (size) {
1776 		if ((am = ami_allocmem(sc, size)) == NULL) {
1777 			error = ENOMEM;
1778 			goto memerr;
1779 		}
1780 		idata = AMIMEM_KVA(am);
1781 	}
1782 
1783 	cmd = &ccb->ccb_cmd;
1784 	cmd->acc_cmd = opcode;
1785 
1786 	/*
1787 	 * some commands require data to be written to idata before sending
1788 	 * command to fw
1789 	 */
1790 	switch (opcode) {
1791 	case AMI_SPEAKER:
1792 		*idata = par1;
1793 		break;
1794 	default:
1795 		cmd->acc_io.aio_channel = par1;
1796 		cmd->acc_io.aio_param = par2;
1797 		cmd->acc_io.aio_pad[0] = par3;
1798 		break;
1799 	};
1800 
1801 	cmd->acc_io.aio_data = am ? htole32(AMIMEM_DVA(am)) : 0;
1802 
1803 	if (opcode != AMI_CHSTATE) {
1804 		ami_start(sc, ccb);
1805 		mtx_enter(&sc->sc_cmd_mtx);
1806 		while (ccb->ccb_state != AMI_CCB_READY)
1807 			msleep(ccb, &sc->sc_cmd_mtx, PRIBIO,"ami_mgmt", 0);
1808 		mtx_leave(&sc->sc_cmd_mtx);
1809 	} else {
1810 		/* change state must be run with id 0xfe and MUST be polled */
1811 		mtx_enter(&sc->sc_cmd_mtx);
1812 		sc->sc_drainio = 1;
1813 		while (!TAILQ_EMPTY(&sc->sc_ccb_runq)) {
1814 			if (msleep(sc, &sc->sc_cmd_mtx, PRIBIO,
1815 			    "amimgmt", hz * 60) == EWOULDBLOCK) {
1816 				printf("%s: drain io timeout\n", DEVNAME(sc));
1817 				ccb->ccb_flags |= AMI_CCB_F_ERR;
1818 				goto restartio;
1819 			}
1820 		}
1821 
1822 		error = sc->sc_poll(sc, &ccb->ccb_cmd);
1823 		if (error == -1)
1824 			ccb->ccb_flags |= AMI_CCB_F_ERR;
1825 
1826 restartio:
1827 		/* restart io */
1828 		sc->sc_drainio = 0;
1829 		mtx_leave(&sc->sc_cmd_mtx);
1830 		ami_runqueue(sc);
1831 	}
1832 
1833 	if (ccb->ccb_flags & AMI_CCB_F_ERR)
1834 		error = EIO;
1835 	else if (buffer && size)
1836 		memcpy(buffer, idata, size);
1837 
1838 	if (am)
1839 		ami_freemem(sc, am);
1840 memerr:
1841 	if (opcode != AMI_CHSTATE) {
1842 		scsi_io_put(&sc->sc_iopool, ccb);
1843 	} else {
1844 		ccb->ccb_flags = 0;
1845 		ccb->ccb_state = AMI_CCB_FREE;
1846 	}
1847 
1848 err:
1849 	rw_exit_write(&sc->sc_lock);
1850 	return (error);
1851 }
1852 
1853 int
1854 ami_ioctl_inq(struct ami_softc *sc, struct bioc_inq *bi)
1855 {
1856 	struct ami_big_diskarray *p; /* struct too large for stack */
1857 	struct scsi_inquiry_data *inqbuf;
1858 	struct ami_fc_einquiry einq;
1859 	int ch, tg;
1860 	int i, s, t, off;
1861 	int error = 0, changes = 0;
1862 
1863 	if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_EINQ3,
1864 	    AMI_FC_EINQ3_SOLICITED_FULL, 0, sizeof einq, &einq)))
1865 		return (EINVAL);
1866 
1867 	inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK);
1868 
1869 	if (einq.ain_drvinscnt == sc->sc_drvinscnt) {
1870 		/* poke existing known drives to make sure they aren't gone */
1871 		for(i = 0; i < sc->sc_channels * 16; i++) {
1872 			if (sc->sc_plist[i] == 0)
1873 				continue;
1874 
1875 			ch = (i & 0xf0) >> 4;
1876 			tg = i & 0x0f;
1877 			if (ami_drv_inq(sc, ch, tg, 0, inqbuf)) {
1878 				/* drive is gone, force rescan */
1879 				changes = 1;
1880 				break;
1881 			}
1882 		}
1883 		if (changes == 0) {
1884 			bcopy(&sc->sc_bi, bi, sizeof *bi);
1885 			goto done;
1886 		}
1887 	}
1888 
1889 	sc->sc_drvinscnt = einq.ain_drvinscnt;
1890 
1891 	p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT);
1892 	if (!p) {
1893 		error = ENOMEM;
1894 		goto done;
1895 	}
1896 
1897 	if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p,
1898 	    p))) {
1899 		error = EINVAL;
1900 		goto bail;
1901 	}
1902 
1903 	bzero(sc->sc_plist, sizeof sc->sc_plist);
1904 
1905 	bi->bi_novol = p->ada_nld;
1906 	bi->bi_nodisk = 0;
1907 	strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
1908 
1909 	/* count used disks, including failed ones */
1910 	for (i = 0; i < p->ada_nld; i++)
1911 		for (s = 0; s < p->ald[i].adl_spandepth; s++)
1912 			for (t = 0; t < p->ald[i].adl_nstripes; t++) {
1913 				off = p->ald[i].asp[s].adv[t].add_channel *
1914 				    AMI_MAX_TARGET +
1915 				    p->ald[i].asp[s].adv[t].add_target;
1916 
1917 				/* account for multi raid vol on same disk */
1918 				if (!sc->sc_plist[off]) {
1919 					sc->sc_plist[off] = 1;
1920 					bi->bi_nodisk++;
1921 				}
1922 			}
1923 
1924 	/* count unsued disks */
1925 	for(i = 0; i < sc->sc_channels * 16; i++) {
1926 	    	if (sc->sc_plist[i])
1927 			continue; /* skip claimed drives */
1928 
1929 		/*
1930 		 * hack to invalidate device type, needed for initiator id
1931 		 * on an unconnected channel.
1932 		 * XXX find out if we can determine this differently
1933 		 */
1934 		memset(inqbuf, 0xff, sizeof(*inqbuf));
1935 
1936 		ch = (i & 0xf0) >> 4;
1937 		tg = i & 0x0f;
1938 		if (!ami_drv_inq(sc, ch, tg, 0, inqbuf)) {
1939 			if ((inqbuf->device & SID_TYPE) != T_DIRECT)
1940 				continue;
1941 			bi->bi_novol++;
1942 			bi->bi_nodisk++;
1943 			sc->sc_plist[i] = 2;
1944 		} else
1945 			sc->sc_plist[i] = 0;
1946 	}
1947 
1948 	bcopy(bi, &sc->sc_bi, sizeof sc->sc_bi);
1949 	error = 0;
1950 bail:
1951 	free(p, M_DEVBUF);
1952 done:
1953 	dma_free(inqbuf, sizeof(*inqbuf));
1954 	return (error);
1955 }
1956 
1957 int
1958 ami_vol(struct ami_softc *sc, struct bioc_vol *bv, struct ami_big_diskarray *p)
1959 {
1960 	int i, ld = p->ada_nld, error = EINVAL;
1961 
1962 	for(i = 0; i < sc->sc_channels * 16; i++) {
1963 	    	/* skip claimed/unused drives */
1964 	    	if (sc->sc_plist[i] != 2)
1965 			continue;
1966 
1967 		/* are we it? */
1968 		if (ld != bv->bv_volid) {
1969 			ld++;
1970 			continue;
1971 		}
1972 
1973 		bv->bv_status = BIOC_SVONLINE;
1974 		bv->bv_size = (u_quad_t)p->apd[i].adp_size *
1975 		    (u_quad_t)512;
1976 		bv->bv_nodisk = 1;
1977 		strlcpy(bv->bv_dev,
1978 		    sc->sc_hdr[bv->bv_volid].dev,
1979 		    sizeof(bv->bv_dev));
1980 
1981 		if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE
1982 		    && p->apd[i].adp_type == 0)
1983 			bv->bv_level = -1;
1984 		else
1985 			bv->bv_level = -2;
1986 
1987 		error = 0;
1988 		goto bail;
1989 	}
1990 
1991 bail:
1992 	return (error);
1993 }
1994 
1995 int
1996 ami_disk(struct ami_softc *sc, struct bioc_disk *bd,
1997     struct ami_big_diskarray *p)
1998 {
1999 	char vend[8+16+4+1], *vendp;
2000 	char ser[32 + 1];
2001 	struct scsi_inquiry_data *inqbuf;
2002 	struct scsi_vpd_serial *vpdbuf;
2003 	int i, ld = p->ada_nld, error = EINVAL;
2004 	u_int8_t ch, tg;
2005 	daddr_t sz = 0;
2006 
2007 	inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK);
2008 	vpdbuf = dma_alloc(sizeof(*vpdbuf), PR_WAITOK);
2009 
2010 	for(i = 0; i < sc->sc_channels * 16; i++) {
2011 	    	/* skip claimed/unused drives */
2012 	    	if (sc->sc_plist[i] != 2)
2013 			continue;
2014 
2015 		/* are we it? */
2016 		if (ld != bd->bd_volid) {
2017 			ld++;
2018 			continue;
2019 		}
2020 
2021 		ch = (i & 0xf0) >> 4;
2022 		tg = i & 0x0f;
2023 		if (ami_drv_inq(sc, ch, tg, 0, inqbuf))
2024 			goto bail;
2025 
2026 		vendp = inqbuf->vendor;
2027 		bcopy(vendp, vend, sizeof vend - 1);
2028 
2029 		vend[sizeof vend - 1] = '\0';
2030 		strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
2031 
2032 		if (!ami_drv_inq(sc, ch, tg, 0x80, vpdbuf)) {
2033 			bcopy(vpdbuf->serial, ser, sizeof ser - 1);
2034 			ser[sizeof ser - 1] = '\0';
2035 			if (_2btol(vpdbuf->hdr.page_length) < sizeof ser)
2036 				ser[_2btol(vpdbuf->hdr.page_length)] = '\0';
2037 			strlcpy(bd->bd_serial, ser, sizeof(bd->bd_serial));
2038 		}
2039 
2040 		error = ami_drv_readcap(sc, ch, tg, &sz);
2041 		if (error)
2042 			goto bail;
2043 
2044 		bd->bd_size = sz;
2045 		bd->bd_channel = ch;
2046 		bd->bd_target = tg;
2047 
2048 		strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev,
2049 		    sizeof(bd->bd_procdev));
2050 
2051 		if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE)
2052 			bd->bd_status = BIOC_SDHOTSPARE;
2053 		else
2054 			bd->bd_status = BIOC_SDUNUSED;
2055 
2056 #ifdef AMI_DEBUG
2057 		if (p->apd[i].adp_type != 0)
2058 			printf("invalid disk type: %d %d %x inquiry type: %x\n",
2059 			    ch, tg, p->apd[i].adp_type, inqbuf->device);
2060 #endif /* AMI_DEBUG */
2061 
2062 		error = 0;
2063 		goto bail;
2064 	}
2065 
2066 bail:
2067 	dma_free(inqbuf, sizeof(*inqbuf));
2068 	dma_free(vpdbuf, sizeof(*vpdbuf));
2069 	return (error);
2070 }
2071 
2072 int
2073 ami_ioctl_vol(struct ami_softc *sc, struct bioc_vol *bv)
2074 {
2075 	struct ami_big_diskarray *p; /* struct too large for stack */
2076 	int i, s, t, off;
2077 	int error = 0;
2078 	struct ami_progress perc;
2079 	u_int8_t bgi[5]; /* 40 LD, 1 bit per LD if BGI is active */
2080 
2081 	p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT);
2082 	if (!p)
2083 		return (ENOMEM);
2084 
2085 	if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p)))
2086 		goto bail;
2087 
2088 	if (bv->bv_volid >= p->ada_nld) {
2089 		error = ami_vol(sc, bv, p);
2090 		goto bail;
2091 	}
2092 
2093 	i = bv->bv_volid;
2094 
2095 	switch (p->ald[i].adl_status) {
2096 	case AMI_RDRV_OFFLINE:
2097 		bv->bv_status = BIOC_SVOFFLINE;
2098 		break;
2099 
2100 	case AMI_RDRV_DEGRADED:
2101 		bv->bv_status = BIOC_SVDEGRADED;
2102 		break;
2103 
2104 	case AMI_RDRV_OPTIMAL:
2105 		bv->bv_status = BIOC_SVONLINE;
2106 		bv->bv_percent = -1;
2107 
2108 		/* get BGI progress here and over-ride status if so */
2109 		memset(bgi, 0, sizeof bgi);
2110 		if (ami_mgmt(sc, AMI_MISC, AMI_GET_BGI, 0, 0, sizeof bgi, &bgi))
2111 			break;
2112 
2113 		if ((bgi[i / 8] & (1 << i % 8)) == 0)
2114 			break;
2115 
2116 		if (!ami_mgmt(sc, AMI_GCHECKPROGR, i, 0, 0, sizeof perc, &perc))
2117 		    	if (perc.apr_progress < 100) {
2118 				bv->bv_status = BIOC_SVSCRUB;
2119 				bv->bv_percent = perc.apr_progress >= 100 ? -1 :
2120 				    perc.apr_progress;
2121 			}
2122 		break;
2123 
2124 	default:
2125 		bv->bv_status = BIOC_SVINVALID;
2126 	}
2127 
2128 	/* over-ride status if a pd is in rebuild status for this ld */
2129 	for (s = 0; s < p->ald[i].adl_spandepth; s++)
2130 		for (t = 0; t < p->ald[i].adl_nstripes; t++) {
2131 			off = p->ald[i].asp[s].adv[t].add_channel *
2132 			    AMI_MAX_TARGET +
2133 			    p->ald[i].asp[s].adv[t].add_target;
2134 
2135 			if (p->apd[off].adp_ostatus != AMI_PD_RBLD)
2136 				continue;
2137 
2138 			/* get rebuild progress from pd 0 */
2139 			bv->bv_status = BIOC_SVREBUILD;
2140 			if (ami_mgmt(sc, AMI_GRBLDPROGR,
2141 			    p->ald[i].asp[s].adv[t].add_channel,
2142 			    p->ald[i].asp[s].adv[t].add_target, 0,
2143 			    sizeof perc, &perc))
2144 				bv->bv_percent = -1;
2145 			else
2146 				bv->bv_percent = perc.apr_progress >= 100 ? -1 :
2147 				    perc.apr_progress;
2148 			break;
2149 		}
2150 
2151 	bv->bv_size = 0;
2152 	bv->bv_level = p->ald[i].adl_raidlvl;
2153 	bv->bv_nodisk = 0;
2154 
2155 	for (s = 0; s < p->ald[i].adl_spandepth; s++) {
2156 		for (t = 0; t < p->ald[i].adl_nstripes; t++)
2157 			bv->bv_nodisk++;
2158 
2159 		switch (bv->bv_level) {
2160 		case 0:
2161 			bv->bv_size += p->ald[i].asp[s].ads_length *
2162 			    p->ald[i].adl_nstripes;
2163 			break;
2164 
2165 		case 1:
2166 			bv->bv_size += p->ald[i].asp[s].ads_length;
2167 			break;
2168 
2169 		case 5:
2170 			bv->bv_size += p->ald[i].asp[s].ads_length *
2171 			    (p->ald[i].adl_nstripes - 1);
2172 			break;
2173 		}
2174 	}
2175 
2176 	if (p->ald[i].adl_spandepth > 1)
2177 		bv->bv_level *= 10;
2178 
2179 	bv->bv_size *= (u_quad_t)512;
2180 
2181 	strlcpy(bv->bv_dev, sc->sc_hdr[i].dev, sizeof(bv->bv_dev));
2182 
2183 bail:
2184 	free(p, M_DEVBUF);
2185 
2186 	return (error);
2187 }
2188 
2189 int
2190 ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd)
2191 {
2192 	struct scsi_inquiry_data *inqbuf;
2193 	struct scsi_vpd_serial *vpdbuf;
2194 	struct ami_big_diskarray *p; /* struct too large for stack */
2195 	int i, s, t, d;
2196 	int off;
2197 	int error = EINVAL;
2198 	u_int16_t ch, tg;
2199 	char vend[8+16+4+1], *vendp;
2200 	char ser[32 + 1];
2201 
2202 	inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK);
2203 	vpdbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK);
2204 	p = malloc(sizeof *p, M_DEVBUF, M_WAITOK);
2205 
2206 	if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p)))
2207 		goto bail;
2208 
2209 	if (bd->bd_volid >= p->ada_nld) {
2210 		error = ami_disk(sc, bd, p);
2211 		goto bail;
2212 	}
2213 
2214 	i = bd->bd_volid;
2215 	for (s = 0, d = 0; s < p->ald[i].adl_spandepth; s++)
2216 		for (t = 0; t < p->ald[i].adl_nstripes; t++) {
2217 			if (d != bd->bd_diskid) {
2218 				d++;
2219 				continue;
2220 			}
2221 
2222 			off = p->ald[i].asp[s].adv[t].add_channel *
2223 			    AMI_MAX_TARGET +
2224 			    p->ald[i].asp[s].adv[t].add_target;
2225 
2226 			bd->bd_size = (u_quad_t)p->apd[off].adp_size *
2227 			    (u_quad_t)512;
2228 
2229 			switch (p->apd[off].adp_ostatus) {
2230 			case AMI_PD_UNCNF:
2231 				bd->bd_status = BIOC_SDUNUSED;
2232 				break;
2233 
2234 			case AMI_PD_ONLINE:
2235 				bd->bd_status = BIOC_SDONLINE;
2236 				break;
2237 
2238 			case AMI_PD_FAILED:
2239 				bd->bd_status = BIOC_SDFAILED;
2240 				bd->bd_size = 0;
2241 				break;
2242 
2243 			case AMI_PD_RBLD:
2244 				bd->bd_status = BIOC_SDREBUILD;
2245 				break;
2246 
2247 			case AMI_PD_HOTSPARE:
2248 				bd->bd_status = BIOC_SDHOTSPARE;
2249 				break;
2250 
2251 			default:
2252 				bd->bd_status = BIOC_SDINVALID;
2253 				bd->bd_size = 0;
2254 			}
2255 
2256 
2257 			ch = p->ald[i].asp[s].adv[t].add_target >> 4;
2258 			tg = p->ald[i].asp[s].adv[t].add_target & 0x0f;
2259 
2260 			bd->bd_channel = ch;
2261 			bd->bd_target = tg;
2262 			strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev,
2263 			    sizeof(bd->bd_procdev));
2264 
2265 			/* if we are failed don't query drive */
2266 			if (bd->bd_size == 0) {
2267 				bzero(&bd->bd_vendor, sizeof(bd->bd_vendor));
2268 				bzero(&bd->bd_serial, sizeof(bd->bd_serial));
2269 				goto done;
2270 			}
2271 
2272 			if (!ami_drv_inq(sc, ch, tg, 0, inqbuf)) {
2273 				vendp = inqbuf->vendor;
2274 				bcopy(vendp, vend, sizeof vend - 1);
2275 				vend[sizeof vend - 1] = '\0';
2276 				strlcpy(bd->bd_vendor, vend,
2277 				    sizeof(bd->bd_vendor));
2278 			}
2279 
2280 			if (!ami_drv_inq(sc, ch, tg, 0x80, vpdbuf)) {
2281 				bcopy(vpdbuf->serial, ser, sizeof ser - 1);
2282 				ser[sizeof ser - 1] = '\0';
2283 				if (_2btol(vpdbuf->hdr.page_length) <
2284 				    sizeof(ser))
2285 					ser[_2btol(vpdbuf->hdr.page_length)] =
2286 					    '\0';
2287 				strlcpy(bd->bd_serial, ser,
2288 				    sizeof(bd->bd_serial));
2289 			}
2290 			goto done;
2291 		}
2292 
2293 done:
2294 	error = 0;
2295 bail:
2296 	free(p, M_DEVBUF);
2297 	dma_free(vpdbuf, sizeof(*vpdbuf));
2298 	dma_free(inqbuf, sizeof(*inqbuf));
2299 
2300 	return (error);
2301 }
2302 
2303 int ami_ioctl_alarm(struct ami_softc *sc, struct bioc_alarm *ba)
2304 {
2305 	int error = 0;
2306 	u_int8_t func, ret;
2307 
2308 	switch(ba->ba_opcode) {
2309 	case BIOC_SADISABLE:
2310 		func = AMI_SPKR_OFF;
2311 		break;
2312 
2313 	case BIOC_SAENABLE:
2314 		func = AMI_SPKR_ON;
2315 		break;
2316 
2317 	case BIOC_SASILENCE:
2318 		func = AMI_SPKR_SHUT;
2319 		break;
2320 
2321 	case BIOC_GASTATUS:
2322 		func = AMI_SPKR_GVAL;
2323 		break;
2324 
2325 	case BIOC_SATEST:
2326 		func = AMI_SPKR_TEST;
2327 		break;
2328 
2329 	default:
2330 		AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocalarm invalid opcode %x\n",
2331 		    DEVNAME(sc), ba->ba_opcode));
2332 		return (EINVAL);
2333 	}
2334 
2335 	if (!(error = ami_mgmt(sc, AMI_SPEAKER, func, 0, 0, sizeof ret,
2336 	    &ret))) {
2337 		if (ba->ba_opcode == BIOC_GASTATUS)
2338 			ba->ba_status = ret;
2339 		else
2340 			ba->ba_status = 0;
2341 	}
2342 
2343 	return (error);
2344 }
2345 
2346 int
2347 ami_ioctl_setstate(struct ami_softc *sc, struct bioc_setstate *bs)
2348 {
2349 	struct scsi_inquiry_data *inqbuf;
2350 	int func, error = 0;
2351 
2352 	inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK);
2353 
2354 	switch (bs->bs_status) {
2355 	case BIOC_SSONLINE:
2356 		func = AMI_STATE_ON;
2357 		break;
2358 
2359 	case BIOC_SSOFFLINE:
2360 		func = AMI_STATE_FAIL;
2361 		break;
2362 
2363 	case BIOC_SSHOTSPARE:
2364 		if (ami_drv_inq(sc, bs->bs_channel, bs->bs_target, 0,
2365 		    inqbuf)) {
2366 			error = EINVAL;
2367 			goto done;
2368 		}
2369 
2370 		func = AMI_STATE_SPARE;
2371 		break;
2372 
2373 	default:
2374 		AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocsetstate invalid opcode %x\n"
2375 		    , DEVNAME(sc), bs->bs_status));
2376 		error = EINVAL;
2377 		goto done;
2378 	}
2379 
2380 	if ((error = ami_mgmt(sc, AMI_CHSTATE, bs->bs_channel, bs->bs_target,
2381 	    func, 0, NULL)))
2382 		goto done;
2383 
2384 done:
2385 	dma_free(inqbuf, sizeof(*inqbuf));
2386 	return (error);
2387 }
2388 
2389 #ifndef SMALL_KERNEL
2390 int
2391 ami_create_sensors(struct ami_softc *sc)
2392 {
2393 	struct device *dev;
2394 	struct scsibus_softc *ssc = NULL;
2395 	struct scsi_link *link;
2396 	int i;
2397 
2398 	TAILQ_FOREACH(dev, &alldevs, dv_list) {
2399 		if (dev->dv_parent != &sc->sc_dev)
2400 			continue;
2401 
2402 		/* check if this is the scsibus for the logical disks */
2403 		ssc = (struct scsibus_softc *)dev;
2404 		if (ssc->adapter_link == &sc->sc_link)
2405 			break;
2406 	}
2407 
2408 	if (ssc == NULL)
2409 		return (1);
2410 
2411 	sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_nunits,
2412 	    M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
2413 	if (sc->sc_sensors == NULL)
2414 		return (1);
2415 
2416 	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
2417 	    sizeof(sc->sc_sensordev.xname));
2418 
2419 	for (i = 0; i < sc->sc_nunits; i++) {
2420 		link = scsi_get_link(ssc, i, 0);
2421 		if (link == NULL)
2422 			goto bad;
2423 
2424 		dev = link->device_softc;
2425 
2426 		sc->sc_sensors[i].type = SENSOR_DRIVE;
2427 		sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
2428 
2429 		strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
2430 		    sizeof(sc->sc_sensors[i].desc));
2431 
2432 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
2433 	}
2434 
2435 	sc->sc_bd = malloc(sizeof(*sc->sc_bd), M_DEVBUF, M_WAITOK|M_CANFAIL);
2436 	if (sc->sc_bd == NULL)
2437 		goto bad;
2438 
2439 	if (sensor_task_register(sc, ami_refresh_sensors, 10) == NULL)
2440 		goto freebd;
2441 
2442 	sensordev_install(&sc->sc_sensordev);
2443 
2444 	return (0);
2445 
2446 freebd:
2447 	free(sc->sc_bd, M_DEVBUF);
2448 bad:
2449 	free(sc->sc_sensors, M_DEVBUF);
2450 
2451 	return (1);
2452 }
2453 
2454 void
2455 ami_refresh_sensors(void *arg)
2456 {
2457 	struct ami_softc *sc = arg;
2458 	int i;
2459 
2460 	if (ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof(*sc->sc_bd),
2461 	    sc->sc_bd)) {
2462 		for (i = 0; i < sc->sc_nunits; i++) {
2463 			sc->sc_sensors[i].value = 0; /* unknown */
2464 			sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
2465 		}
2466 		return;
2467 	}
2468 
2469 	for (i = 0; i < sc->sc_nunits; i++) {
2470 		switch (sc->sc_bd->ald[i].adl_status) {
2471 		case AMI_RDRV_OFFLINE:
2472 			sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
2473 			sc->sc_sensors[i].status = SENSOR_S_CRIT;
2474 			break;
2475 
2476 		case AMI_RDRV_DEGRADED:
2477 			sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
2478 			sc->sc_sensors[i].status = SENSOR_S_WARN;
2479 			break;
2480 
2481 		case AMI_RDRV_OPTIMAL:
2482 			sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
2483 			sc->sc_sensors[i].status = SENSOR_S_OK;
2484 			break;
2485 
2486 		default:
2487 			sc->sc_sensors[i].value = 0; /* unknown */
2488 			sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
2489 		}
2490 	}
2491 }
2492 #endif /* SMALL_KERNEL */
2493 #endif /* NBIO > 0 */
2494 
2495 #ifdef AMI_DEBUG
2496 void
2497 ami_print_mbox(struct ami_iocmd *mbox)
2498 {
2499 	int i;
2500 
2501 	printf("acc_cmd: %d  aac_id: %d  acc_busy: %d  acc_nstat: %d  ",
2502 	    mbox->acc_cmd, mbox->acc_id, mbox->acc_busy, mbox->acc_nstat);
2503 	printf("acc_status: %d  acc_poll: %d  acc_ack: %d\n",
2504 	    mbox->acc_status, mbox->acc_poll, mbox->acc_ack);
2505 
2506 	printf("acc_cmplidl: ");
2507 	for (i = 0; i < AMI_MAXSTATACK; i++) {
2508 		printf("[%d] = %d  ", i, mbox->acc_cmplidl[i]);
2509 	}
2510 
2511 	printf("\n");
2512 }
2513 #endif /* AMI_DEBUG */
2514