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