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