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