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