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