xref: /openbsd-src/sys/dev/ic/ami.c (revision d1df930ffab53da22f3324c32bed7ac5709915e6)
1 /*	$OpenBSD: ami.c,v 1.234 2018/08/14 05:22:21 jmatthew 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 
63 #include <machine/bus.h>
64 
65 #include <scsi/scsi_all.h>
66 #include <scsi/scsi_disk.h>
67 #include <scsi/scsiconf.h>
68 
69 #include <dev/biovar.h>
70 #include <dev/ic/amireg.h>
71 #include <dev/ic/amivar.h>
72 
73 #ifdef AMI_DEBUG
74 #define	AMI_DPRINTF(m,a)	do { if (ami_debug & (m)) printf a; } while (0)
75 #define	AMI_D_CMD	0x0001
76 #define	AMI_D_INTR	0x0002
77 #define	AMI_D_MISC	0x0004
78 #define	AMI_D_DMA	0x0008
79 #define	AMI_D_IOCTL	0x0010
80 int ami_debug = 0
81 /*	| AMI_D_CMD */
82 /*	| AMI_D_INTR */
83 /*	| AMI_D_MISC */
84 /*	| AMI_D_DMA */
85 /*	| AMI_D_IOCTL */
86 	;
87 #else
88 #define	AMI_DPRINTF(m,a)	/* m, a */
89 #endif
90 
91 struct cfdriver ami_cd = {
92 	NULL, "ami", DV_DULL
93 };
94 
95 void	ami_scsi_cmd(struct scsi_xfer *);
96 int	ami_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int);
97 void	amiminphys(struct buf *bp, struct scsi_link *sl);
98 
99 struct scsi_adapter ami_switch = {
100 	ami_scsi_cmd, amiminphys, 0, 0, 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, amiminphys, 0, 0,
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 amiminphys(struct buf *bp, struct scsi_link *sl)
1194 {
1195 	if (bp->b_bcount > AMI_MAXFER)
1196 		bp->b_bcount = AMI_MAXFER;
1197 	minphys(bp);
1198 }
1199 
1200 void
1201 ami_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size)
1202 {
1203 	size_t copy_cnt;
1204 
1205 	AMI_DPRINTF(AMI_D_MISC, ("ami_copy_internal_data "));
1206 
1207 	if (!xs->datalen)
1208 		printf("uio move not yet supported\n");
1209 	else {
1210 		copy_cnt = MIN(size, xs->datalen);
1211 		bcopy(v, xs->data, copy_cnt);
1212 	}
1213 }
1214 
1215 void
1216 ami_scsi_raw_cmd(struct scsi_xfer *xs)
1217 {
1218 	struct scsi_link *link = xs->sc_link;
1219 	struct ami_rawsoftc *rsc = link->adapter_softc;
1220 	struct ami_softc *sc = rsc->sc_softc;
1221 	u_int8_t channel = rsc->sc_channel, target = link->target;
1222 	struct ami_ccb *ccb;
1223 
1224 	AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_raw_cmd "));
1225 
1226 	if (xs->cmdlen > AMI_MAX_CDB) {
1227 		AMI_DPRINTF(AMI_D_CMD, ("CDB too big %p ", xs));
1228 		bzero(&xs->sense, sizeof(xs->sense));
1229 		xs->sense.error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT;
1230 		xs->sense.flags = SKEY_ILLEGAL_REQUEST;
1231 		xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
1232 		xs->error = XS_SENSE;
1233 		scsi_done(xs);
1234 		return;
1235 	}
1236 
1237 	xs->error = XS_NOERROR;
1238 
1239 	ccb = xs->io;
1240 
1241 	memset(ccb->ccb_pt, 0, sizeof(struct ami_passthrough));
1242 
1243 	ccb->ccb_xs = xs;
1244 	ccb->ccb_done = ami_done_pt;
1245 
1246 	ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU;
1247 	ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa;
1248 
1249 	ccb->ccb_pt->apt_param = AMI_PTPARAM(AMI_TIMEOUT_6,1,0);
1250 	ccb->ccb_pt->apt_channel = channel;
1251 	ccb->ccb_pt->apt_target = target;
1252 	bcopy(xs->cmd, ccb->ccb_pt->apt_cdb, AMI_MAX_CDB);
1253 	ccb->ccb_pt->apt_ncdb = xs->cmdlen;
1254 	ccb->ccb_pt->apt_nsense = AMI_MAX_SENSE;
1255 	ccb->ccb_pt->apt_datalen = xs->datalen;
1256 	ccb->ccb_pt->apt_data = 0;
1257 
1258 	if (ami_load_ptmem(sc, ccb, xs->data, xs->datalen,
1259 	    xs->flags & SCSI_DATA_IN, xs->flags & SCSI_NOSLEEP) != 0) {
1260 		xs->error = XS_DRIVER_STUFFUP;
1261 		scsi_done(xs);
1262 		return;
1263 	}
1264 
1265 	ami_start_xs(sc, ccb, xs);
1266 }
1267 
1268 int
1269 ami_load_ptmem(struct ami_softc *sc, struct ami_ccb *ccb, void *data,
1270     size_t len, int read, int nowait)
1271 {
1272 	bus_dmamap_t dmap = ccb->ccb_dmamap;
1273 	bus_dma_segment_t *sgd;
1274 	int error, i;
1275 
1276 	if (data != NULL) {
1277 		error = bus_dmamap_load(sc->sc_dmat, dmap, data, len, NULL,
1278 		    nowait ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
1279 		if (error) {
1280 			if (error == EFBIG)
1281 				printf("more than %d dma segs\n",
1282 				    AMI_MAXOFFSETS);
1283 			else
1284 				printf("error %d loading dma map\n", error);
1285 
1286 			return (1);
1287 		}
1288 
1289 		sgd = dmap->dm_segs;
1290 		if (dmap->dm_nsegs > 1) {
1291 			struct ami_sgent *sgl = ccb->ccb_sglist;
1292 
1293 			ccb->ccb_pt->apt_nsge = dmap->dm_nsegs;
1294 			ccb->ccb_pt->apt_data = ccb->ccb_sglistpa;
1295 
1296 			for (i = 0; i < dmap->dm_nsegs; i++) {
1297 				sgl[i].asg_addr = htole32(sgd[i].ds_addr);
1298 				sgl[i].asg_len = htole32(sgd[i].ds_len);
1299 			}
1300 		} else {
1301 			ccb->ccb_pt->apt_nsge = 0;
1302 			ccb->ccb_pt->apt_data = htole32(sgd->ds_addr);
1303 		}
1304 
1305 		bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
1306 		    read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1307 	}
1308 
1309 	bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
1310 	    ccb->ccb_offset, sizeof(struct ami_ccbmem),
1311 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1312 
1313 	return (0);
1314 }
1315 
1316 void
1317 ami_scsi_cmd(struct scsi_xfer *xs)
1318 {
1319 	struct scsi_link *link = xs->sc_link;
1320 	struct ami_softc *sc = link->adapter_softc;
1321 	struct device *dev = link->device_softc;
1322 	struct ami_ccb *ccb;
1323 	struct ami_iocmd *cmd;
1324 	struct scsi_inquiry_data inq;
1325 	struct scsi_sense_data sd;
1326 	struct scsi_read_cap_data rcd;
1327 	u_int8_t target = link->target;
1328 	u_int32_t blockno, blockcnt;
1329 	struct scsi_rw *rw;
1330 	struct scsi_rw_big *rwb;
1331 	bus_dma_segment_t *sgd;
1332 	int error;
1333 	int i;
1334 
1335 	AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd "));
1336 
1337 	if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present ||
1338 	    link->lun != 0) {
1339 		AMI_DPRINTF(AMI_D_CMD, ("no target %d ", target));
1340 		/* XXX should be XS_SENSE and sense filled out */
1341 		xs->error = XS_DRIVER_STUFFUP;
1342 		scsi_done(xs);
1343 		return;
1344 	}
1345 
1346 	xs->error = XS_NOERROR;
1347 
1348 	switch (xs->cmd->opcode) {
1349 	case READ_COMMAND:
1350 	case READ_BIG:
1351 	case WRITE_COMMAND:
1352 	case WRITE_BIG:
1353 		/* deal with io outside the switch */
1354 		break;
1355 
1356 	case SYNCHRONIZE_CACHE:
1357 		ccb = xs->io;
1358 
1359 		ccb->ccb_xs = xs;
1360 		ccb->ccb_done = ami_done_flush;
1361 		if (xs->timeout < 30000)
1362 			xs->timeout = 30000;	/* at least 30sec */
1363 
1364 		cmd = &ccb->ccb_cmd;
1365 		cmd->acc_cmd = AMI_FLUSH;
1366 
1367 		ami_start_xs(sc, ccb, xs);
1368 		return;
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 = ENOTTY;
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, sizeof *p);
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 = (uint64_t)p->apd[i].adp_size *
1975 		    (uint64_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 *= (uint64_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, sizeof *p);
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 = (uint64_t)p->apd[off].adp_size *
2227 			    (uint64_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, sizeof *p);
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 = mallocarray(sc->sc_nunits, sizeof(struct ksensor),
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, sizeof(*sc->sc_bd));
2448 bad:
2449 	free(sc->sc_sensors, M_DEVBUF, sc->sc_nunits * sizeof(struct ksensor));
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