1 /*	$OpenBSD: ami.c,v 1.24 2004/01/09 21:32:23 brad Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Michael Shalayeff
5  * All rights reserved.
6  *
7  * The SCSI emulation layer is derived from gdt(4) driver,
8  * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29  * THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*
32  * American Megatrends Inc. MegaRAID controllers driver
33  *
34  * This driver was made because these ppl and organizations
35  * donated hardware and provided documentation:
36  *
37  * - 428 model card
38  *	John Kerbawy, Stephan Matis, Mark Stovall;
39  *
40  * - 467 and 475 model cards, docs
41  *	American Megatrends Inc.;
42  *
43  * - uninterruptable electric power for cvs
44  *	Theo de Raadt.
45  */
46 
47 /* #define	AMI_DEBUG */
48 
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/buf.h>
52 #include <sys/device.h>
53 #include <sys/kernel.h>
54 #include <sys/malloc.h>
55 
56 #include <machine/bus.h>
57 
58 #include <scsi/scsi_all.h>
59 #include <scsi/scsi_disk.h>
60 #include <scsi/scsiconf.h>
61 
62 #include <dev/ic/amireg.h>
63 #include <dev/ic/amivar.h>
64 
65 #ifdef AMI_DEBUG
66 #define	AMI_DPRINTF(m,a)	if (ami_debug & (m)) printf a
67 #define	AMI_D_CMD	0x0001
68 #define	AMI_D_INTR	0x0002
69 #define	AMI_D_MISC	0x0004
70 #define	AMI_D_DMA	0x0008
71 int ami_debug = 0
72 	| AMI_D_CMD
73 	| AMI_D_INTR
74 /*	| AMI_D_MISC */
75 /*	| AMI_D_DMA */
76 	;
77 #else
78 #define	AMI_DPRINTF(m,a)	/* m, a */
79 #endif
80 
81 struct cfdriver ami_cd = {
82 	NULL, "ami", DV_DULL
83 };
84 
85 int	ami_scsi_cmd(struct scsi_xfer *xs);
86 void	amiminphys(struct buf *bp);
87 
88 struct scsi_adapter ami_switch = {
89 	ami_scsi_cmd, amiminphys, 0, 0,
90 };
91 
92 struct scsi_device ami_dev = {
93 	NULL, NULL, NULL, NULL
94 };
95 
96 int	ami_scsi_raw_cmd(struct scsi_xfer *xs);
97 
98 struct scsi_adapter ami_raw_switch = {
99 	ami_scsi_raw_cmd, amiminphys, 0, 0,
100 };
101 
102 struct scsi_device ami_raw_dev = {
103 	NULL, NULL, NULL, NULL
104 };
105 
106 static __inline struct ami_ccb *ami_get_ccb(struct ami_softc *sc);
107 static __inline void ami_put_ccb(struct ami_ccb *ccb);
108 void ami_copyhds(struct ami_softc *sc, const u_int32_t *sizes,
109 	const u_int8_t *props, const u_int8_t *stats);
110 void *ami_allocmem(bus_dma_tag_t dmat, bus_dmamap_t *map,
111 	bus_dma_segment_t *segp, size_t isize, size_t nent, const char *iname);
112 void ami_freemem(bus_dma_tag_t dmat, bus_dmamap_t *map,
113 	bus_dma_segment_t *segp, size_t isize, size_t nent, const char *iname);
114 void ami_dispose(struct ami_softc *sc);
115 void ami_stimeout(void *v);
116 int  ami_cmd(struct ami_ccb *ccb, int flags, int wait);
117 int  ami_start(struct ami_ccb *ccb, int wait);
118 int  ami_complete(struct ami_ccb *ccb);
119 int  ami_done(struct ami_softc *sc, int idx);
120 void ami_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size);
121 int  ami_inquire(struct ami_softc *sc, u_int8_t op);
122 
123 
124 static __inline struct ami_ccb *
ami_get_ccb(sc)125 ami_get_ccb(sc)
126 	struct ami_softc *sc;
127 {
128 	struct ami_ccb *ccb;
129 
130 	ccb = TAILQ_LAST(&sc->sc_free_ccb, ami_queue_head);
131 	if (ccb) {
132 		TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_link);
133 		ccb->ccb_state = AMI_CCB_READY;
134 	}
135 	return ccb;
136 }
137 
138 static __inline void
ami_put_ccb(ccb)139 ami_put_ccb(ccb)
140 	struct ami_ccb *ccb;
141 {
142 	struct ami_softc *sc = ccb->ccb_sc;
143 
144 	ccb->ccb_state = AMI_CCB_FREE;
145 	TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link);
146 }
147 
148 void *
ami_allocmem(dmat,map,segp,isize,nent,iname)149 ami_allocmem(dmat, map, segp, isize, nent, iname)
150 	bus_dma_tag_t dmat;
151 	bus_dmamap_t *map;
152 	bus_dma_segment_t *segp;
153 	size_t isize, nent;
154 	const char *iname;
155 {
156 	size_t total = isize * nent;
157 	caddr_t p;
158 	int error, rseg;
159 
160 	/* XXX this is because we might have no dmamem_load_raw */
161 	if ((error = bus_dmamem_alloc(dmat, total, PAGE_SIZE, 0, segp, 1,
162 	    &rseg, BUS_DMA_NOWAIT))) {
163 		printf(": cannot allocate %s%s (%d)\n",
164 		    iname, nent==1? "": "s", error);
165 		return (NULL);
166 	}
167 
168 	if ((error = bus_dmamem_map(dmat, segp, rseg, total, &p,
169 	    BUS_DMA_NOWAIT))) {
170 		printf(": cannot map %s%s (%d)\n",
171 		    iname, nent==1? "": "s", error);
172 		return (NULL);
173 	}
174 
175 	bzero(p, total);
176 	if ((error = bus_dmamap_create(dmat, total, 1,
177 	    total, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, map))) {
178 		printf(": cannot create %s dmamap (%d)\n", iname, error);
179 		return (NULL);
180 	}
181 	if ((error = bus_dmamap_load(dmat, *map, p, total, NULL,
182 	    BUS_DMA_NOWAIT))) {
183 		printf(": cannot load %s dma map (%d)\n", iname, error);
184 		return (NULL);
185 	}
186 
187 	return (p);
188 }
189 
190 void
ami_freemem(dmat,map,segp,isize,nent,iname)191 ami_freemem(dmat, map, segp, isize, nent, iname)
192 	bus_dma_tag_t dmat;
193 	bus_dmamap_t *map;
194 	bus_dma_segment_t *segp;
195 	size_t isize, nent;
196 	const char *iname;
197 {
198 	bus_dmamem_free(dmat, segp, 1);
199 	bus_dmamap_destroy(dmat, *map);
200 	*map = NULL;
201 }
202 
203 void
ami_dispose(sc)204 ami_dispose(sc)
205 	struct ami_softc *sc;
206 {
207 	register struct ami_ccb *ccb;
208 
209 	/* traverse the ccbs and destroy the maps */
210 	for (ccb = &sc->sc_ccbs[AMI_MAXCMDS - 1]; ccb > sc->sc_ccbs; ccb--)
211 		if (ccb->ccb_dmamap)
212 			bus_dmamap_destroy(sc->dmat, ccb->ccb_dmamap);
213 	ami_freemem(sc->dmat, &sc->sc_sgmap, sc->sc_sgseg,
214 	    sizeof(struct ami_sgent) * AMI_SGEPERCMD, AMI_MAXCMDS, "sglist");
215 	ami_freemem(sc->dmat, &sc->sc_cmdmap, sc->sc_cmdseg,
216 	    sizeof(struct ami_iocmd), AMI_MAXCMDS + 1, "command");
217 }
218 
219 
220 void
ami_copyhds(sc,sizes,props,stats)221 ami_copyhds(sc, sizes, props, stats)
222 	struct ami_softc *sc;
223 	const u_int32_t *sizes;
224 	const u_int8_t *props, *stats;
225 {
226 	int i;
227 
228 	for (i = 0; i < sc->sc_nunits; i++) {
229 		sc->sc_hdr[i].hd_present = 1;
230 		sc->sc_hdr[i].hd_is_logdrv = 1;
231 		sc->sc_hdr[i].hd_size = letoh32(sizes[i]);
232 		sc->sc_hdr[i].hd_prop = props[i];
233 		sc->sc_hdr[i].hd_stat = stats[i];
234 		if (sc->sc_hdr[i].hd_size > 0x200000) {
235 			sc->sc_hdr[i].hd_heads = 255;
236 			sc->sc_hdr[i].hd_secs = 63;
237 		} else {
238 			sc->sc_hdr[i].hd_heads = 64;
239 			sc->sc_hdr[i].hd_secs = 32;
240 		}
241 	}
242 }
243 
244 int
ami_attach(sc)245 ami_attach(sc)
246 	struct ami_softc *sc;
247 {
248 	/* struct ami_rawsoftc *rsc; */
249 	struct ami_ccb	*ccb;
250 	struct ami_iocmd *cmd;
251 	struct ami_sgent *sg;
252 	bus_dmamap_t idatamap;
253 	bus_dma_segment_t idataseg[1];
254 	const char *p;
255 	void	*idata;
256 	int	error;
257 
258 	if (!(idata = ami_allocmem(sc->dmat, &idatamap, idataseg,
259 	    NBPG, 1, "init data"))) {
260 		ami_freemem(sc->dmat, &idatamap, idataseg,
261 		    NBPG, 1, "init data");
262 		return 1;
263 	}
264 
265 	sc->sc_cmds = ami_allocmem(sc->dmat, &sc->sc_cmdmap, sc->sc_cmdseg,
266 	    sizeof(struct ami_iocmd), AMI_MAXCMDS+1, "command");
267 	if (!sc->sc_cmds) {
268 		ami_dispose(sc);
269 		ami_freemem(sc->dmat, &idatamap,
270 		    idataseg, NBPG, 1, "init data");
271 		return 1;
272 	}
273 	sc->sc_sgents = ami_allocmem(sc->dmat, &sc->sc_sgmap, sc->sc_sgseg,
274 	    sizeof(struct ami_sgent) * AMI_SGEPERCMD, AMI_MAXCMDS+1, "sglist");
275 	if (!sc->sc_sgents) {
276 		ami_dispose(sc);
277 		ami_freemem(sc->dmat, &idatamap,
278 		    idataseg, NBPG, 1, "init data");
279 		return 1;
280 	}
281 
282 	TAILQ_INIT(&sc->sc_ccbq);
283 	TAILQ_INIT(&sc->sc_ccbdone);
284 	TAILQ_INIT(&sc->sc_free_ccb);
285 
286 	/* 0th command is a mailbox */
287 	for (ccb = &sc->sc_ccbs[AMI_MAXCMDS-1],
288 	     cmd = sc->sc_cmds  + sizeof(*cmd) * AMI_MAXCMDS,
289 	     sg = sc->sc_sgents + sizeof(*sg)  * AMI_MAXCMDS * AMI_SGEPERCMD;
290 	     cmd >= (struct ami_iocmd *)sc->sc_cmds;
291 	     cmd--, ccb--, sg -= AMI_SGEPERCMD) {
292 
293 		cmd->acc_id = cmd - (struct ami_iocmd *)sc->sc_cmds;
294 		if (cmd->acc_id) {
295 			error = bus_dmamap_create(sc->dmat,
296 			    AMI_MAXFER, AMI_MAXOFFSETS, AMI_MAXFER, 0,
297 			    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
298 			    &ccb->ccb_dmamap);
299 			if (error) {
300 				printf(": cannot create ccb dmamap (%d)\n",
301 				    error);
302 				ami_dispose(sc);
303 				ami_freemem(sc->dmat, &idatamap,
304 				    idataseg, NBPG, 1, "init data");
305 				return (1);
306 			}
307 			ccb->ccb_sc = sc;
308 			ccb->ccb_cmd = cmd;
309 			ccb->ccb_state = AMI_CCB_FREE;
310 			ccb->ccb_cmdpa = htole32(sc->sc_cmdseg[0].ds_addr +
311 			    cmd->acc_id * sizeof(*cmd));
312 			ccb->ccb_sglist = sg;
313 			ccb->ccb_sglistpa = htole32(sc->sc_sgseg[0].ds_addr +
314 			    cmd->acc_id * sizeof(*sg) * AMI_SGEPERCMD);
315 			TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link);
316 		} else {
317 			sc->sc_mbox = cmd;
318 			sc->sc_mbox_pa = sc->sc_cmdseg[0].ds_addr;
319 			AMI_DPRINTF(AMI_D_CMD, ("mbox_pa=%llx ",
320 			    sc->sc_mbox_pa));
321 		}
322 	}
323 
324 	timeout_set(&sc->sc_poll_tmo, (void (*)(void *))ami_intr, sc);
325 
326 	(sc->sc_init)(sc);
327 	{
328 		paddr_t	pa = idataseg[0].ds_addr;
329 		ami_lock_t lock;
330 
331 		lock = AMI_LOCK_AMI(sc);
332 
333 		ccb = ami_get_ccb(sc);
334 		cmd = ccb->ccb_cmd;
335 
336 		/* try FC inquiry first */
337 		cmd->acc_cmd = AMI_FCOP;
338 		cmd->acc_io.aio_channel = AMI_FC_EINQ3;
339 		cmd->acc_io.aio_param = AMI_FC_EINQ3_SOLICITED_FULL;
340 		cmd->acc_io.aio_data = htole32(pa);
341 		if (ami_cmd(ccb, 0, 1) == 0) {
342 			struct ami_fc_einquiry *einq = idata;
343 			struct ami_fc_prodinfo *pi = idata;
344 
345 			sc->sc_nunits = einq->ain_nlogdrv;
346 			ami_copyhds(sc, einq->ain_ldsize, einq->ain_ldprop,
347 			    einq->ain_ldstat);
348 
349 			ccb = ami_get_ccb(sc);
350 			cmd = ccb->ccb_cmd;
351 
352 			cmd->acc_cmd = AMI_FCOP;
353 			cmd->acc_io.aio_channel = AMI_FC_PRODINF;
354 			cmd->acc_io.aio_param = 0;
355 			cmd->acc_io.aio_data = htole32(pa);
356 			if (ami_cmd(ccb, 0, 1) == 0) {
357 				sc->sc_maxunits = AMI_BIG_MAX_LDRIVES;
358 
359 				bcopy (pi->api_fwver, sc->sc_fwver, 16);
360 				sc->sc_fwver[15] = '\0';
361 				bcopy (pi->api_biosver, sc->sc_biosver, 16);
362 				sc->sc_biosver[15] = '\0';
363 				sc->sc_channels = pi->api_channels;
364 				sc->sc_targets = pi->api_fcloops;
365 				sc->sc_memory = letoh16(pi->api_ramsize);
366 				sc->sc_maxcmds = pi->api_maxcmd;
367 				p = "FC loop";
368 			}
369 		}
370 
371 		if (sc->sc_maxunits == 0) {
372 			struct ami_inquiry *inq = idata;
373 
374 			ccb = ami_get_ccb(sc);
375 			cmd = ccb->ccb_cmd;
376 
377 			cmd->acc_cmd = AMI_EINQUIRY;
378 			cmd->acc_io.aio_channel = 0;
379 			cmd->acc_io.aio_param = 0;
380 			cmd->acc_io.aio_data = htole32(pa);
381 			if (ami_cmd(ccb, 0, 1) != 0) {
382 				ccb = ami_get_ccb(sc);
383 				cmd = ccb->ccb_cmd;
384 
385 				cmd->acc_cmd = AMI_INQUIRY;
386 				cmd->acc_io.aio_channel = 0;
387 				cmd->acc_io.aio_param = 0;
388 				cmd->acc_io.aio_data = htole32(pa);
389 				if (ami_cmd(ccb, 0, 1) != 0) {
390 					AMI_UNLOCK_AMI(sc, lock);
391 					printf(": cannot do inquiry\n");
392 					ami_dispose(sc);
393 					ami_freemem(sc->dmat, &idatamap,
394 					    idataseg, NBPG, 1, "init data");
395 					return (1);
396 				}
397 			}
398 
399 			sc->sc_maxunits = AMI_MAX_LDRIVES;
400 			sc->sc_nunits = inq->ain_nlogdrv;
401 			ami_copyhds(sc, inq->ain_ldsize, inq->ain_ldprop,
402 			    inq->ain_ldstat);
403 
404 			bcopy (inq->ain_fwver, sc->sc_fwver, 4);
405 			sc->sc_fwver[4] = '\0';
406 			bcopy (inq->ain_biosver, sc->sc_biosver, 4);
407 			sc->sc_biosver[4] = '\0';
408 			sc->sc_channels = inq->ain_channels;
409 			sc->sc_targets = inq->ain_targets;
410 			sc->sc_memory = inq->ain_ramsize;
411 			sc->sc_maxcmds = inq->ain_maxcmd;
412 			p = "target";
413 		}
414 
415 		AMI_UNLOCK_AMI(sc, lock);
416 
417 		if (sc->sc_maxcmds > AMI_MAXCMDS)
418 			sc->sc_maxcmds = 1 /* AMI_MAXCMDS */;
419 	}
420 	ami_freemem(sc->dmat, &idatamap, idataseg, NBPG, 1, "init data");
421 
422 	/* hack for hp netraid version encoding */
423 	if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' &&
424 	    sc->sc_fwver[1] < ' ' && sc->sc_fwver[0] < ' ' &&
425 	    'A' <= sc->sc_biosver[2] && sc->sc_biosver[2] <= 'Z' &&
426 	    sc->sc_biosver[1] < ' ' && sc->sc_biosver[0] < ' ') {
427 
428 		snprintf(sc->sc_fwver, sizeof sc->sc_fwver, "%c.%02d.%02d",
429 		    sc->sc_fwver[2], sc->sc_fwver[1], sc->sc_fwver[0]);
430 		snprintf(sc->sc_biosver, sizeof sc->sc_biosver, "%c.%02d.%02d",
431 		    sc->sc_biosver[2], sc->sc_biosver[1], sc->sc_biosver[0]);
432 	}
433 
434 	printf(": FW %s, BIOS v%s, %dMB RAM\n"
435 	     "%s: %d channels, %d %ss, %d logical drives\n",
436 	    sc->sc_fwver, sc->sc_biosver, sc->sc_memory,
437 	    sc->sc_dev.dv_xname,
438 	    sc->sc_channels, sc->sc_targets, p, sc->sc_nunits);
439 
440 	/* TODO: fetch & print cache strategy */
441 	/* TODO: fetch & print scsi and raid info */
442 
443 	sc->sc_link.device = &ami_dev;
444 	sc->sc_link.openings = sc->sc_maxcmds;
445 	sc->sc_link.adapter_softc = sc;
446 	sc->sc_link.adapter = &ami_switch;
447 	sc->sc_link.adapter_target = sc->sc_maxunits;
448 	sc->sc_link.adapter_buswidth = sc->sc_maxunits;
449 
450 	config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
451 #if 0
452 	rsc = malloc(sizeof(struct ami_rawsoftc) * sc->sc_channels,
453 	    M_DEVBUF, M_NOWAIT);
454 	if (!rsc) {
455 		printf("%s: no memory for raw interface\n",
456 		    sc->sc_dev.dv_xname);
457 		return (0);
458 	}
459 
460 	bzero(rsc, sizeof(struct ami_rawsoftc) * sc->sc_channels);
461 	for (sc->sc_rawsoftcs = rsc;
462 	     rsc < &sc->sc_rawsoftcs[sc->sc_channels]; rsc++) {
463 
464 		/* TODO fetch and print channel properties */
465 
466 		rsc->sc_softc = sc;
467 		rsc->sc_channel = rsc - sc->sc_rawsoftcs;
468 		rsc->sc_link.device = &ami_raw_dev;
469 		rsc->sc_link.openings = sc->sc_maxcmds;
470 		rsc->sc_link.adapter_softc = rsc;
471 		rsc->sc_link.adapter = &ami_raw_switch;
472 		/* TODO fetch it from the controller */
473 		rsc->sc_link.adapter_target = sc->sc_targets;
474 		rsc->sc_link.adapter_buswidth = sc->sc_targets;
475 
476 		config_found(&sc->sc_dev, &rsc->sc_link, scsiprint);
477 	}
478 #endif
479 	return 0;
480 }
481 
482 int
ami_quartz_init(sc)483 ami_quartz_init(sc)
484 	struct ami_softc *sc;
485 {
486 	bus_space_write_4(sc->iot, sc->ioh, AMI_QIDB, 0);
487 	bus_space_barrier(sc->iot, sc->ioh,
488 		    AMI_QIDB, 4, BUS_SPACE_BARRIER_WRITE);
489 
490 	return 0;
491 }
492 
493 int
ami_quartz_exec(sc,cmd)494 ami_quartz_exec(sc, cmd)
495 	struct ami_softc *sc;
496 	struct ami_iocmd *cmd;
497 {
498 	u_int32_t qidb;
499 
500 	bus_space_barrier(sc->iot, sc->ioh,
501 	    AMI_QIDB, 4, BUS_SPACE_BARRIER_READ);
502 	qidb = bus_space_read_4(sc->iot, sc->ioh, AMI_QIDB);
503 	if (qidb & (AMI_QIDB_EXEC | AMI_QIDB_ACK)) {
504 		AMI_DPRINTF(AMI_D_CMD, ("qidb1=%x ", qidb));
505 		return (EBUSY);
506 	}
507 
508 	/* do not scramble the busy mailbox */
509 	if (sc->sc_mbox->acc_busy) {
510 		AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
511 		return (EBUSY);
512 	}
513 
514 	*sc->sc_mbox = *cmd;
515 	bus_dmamap_sync(sc->dmat, sc->sc_cmdmap, 0, sizeof(*cmd),
516 	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
517 
518 	qidb = sc->sc_mbox_pa | AMI_QIDB_EXEC;
519 	AMI_DPRINTF(AMI_D_CMD, ("qidb2=%x ", qidb));
520 	bus_space_write_4(sc->iot, sc->ioh, AMI_QIDB, qidb);
521 	bus_space_barrier(sc->iot, sc->ioh,
522 	    AMI_QIDB, 4, BUS_SPACE_BARRIER_WRITE);
523 	return (0);
524 }
525 
526 int
ami_quartz_done(sc,mbox)527 ami_quartz_done(sc, mbox)
528 	struct ami_softc *sc;
529 	struct ami_iocmd *mbox;
530 {
531 	u_int32_t qdb;
532 
533 	bus_space_barrier(sc->iot, sc->ioh,
534 	    AMI_QIDB, 4, BUS_SPACE_BARRIER_READ);
535 	qdb = bus_space_read_4(sc->iot, sc->ioh, AMI_QIDB);
536 	if (qdb & (AMI_QIDB_EXEC | AMI_QIDB_ACK)) {
537 		AMI_DPRINTF(AMI_D_CMD, ("qidb3=%x ", qdb));
538 		return (0);
539 	}
540 
541 	/* do not scramble the busy mailbox */
542 	if (sc->sc_mbox->acc_busy) {
543 		AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
544 		return (0);
545 	}
546 
547 	bus_space_barrier(sc->iot, sc->ioh,
548 	    AMI_QODB, 4, BUS_SPACE_BARRIER_READ);
549 	qdb = bus_space_read_4(sc->iot, sc->ioh, AMI_QODB);
550 	if (qdb == AMI_QODB_READY) {
551 
552 		bus_dmamap_sync(sc->dmat, sc->sc_cmdmap, 0, sizeof(*mbox),
553 		    BUS_DMASYNC_POSTWRITE);
554 		*mbox = *sc->sc_mbox;
555 
556 		/* ack interrupt */
557 		bus_space_write_4(sc->iot, sc->ioh, AMI_QODB, AMI_QODB_READY);
558 		bus_space_barrier(sc->iot, sc->ioh,
559 		    AMI_QODB, 4, BUS_SPACE_BARRIER_WRITE);
560 
561 		qdb = sc->sc_mbox_pa | AMI_QIDB_ACK;
562 		bus_space_write_4(sc->iot, sc->ioh, AMI_QIDB, qdb);
563 		bus_space_barrier(sc->iot, sc->ioh,
564 		    AMI_QIDB, 4, BUS_SPACE_BARRIER_WRITE);
565 		return (1);
566 	}
567 
568 	AMI_DPRINTF(AMI_D_CMD, ("qodb=%x ", qdb));
569 
570 	return (0);
571 }
572 
573 int
ami_schwartz_init(sc)574 ami_schwartz_init(sc)
575 	struct ami_softc *sc;
576 {
577 	u_int32_t a = (u_int32_t)sc->sc_mbox_pa;
578 
579 	bus_space_write_4(sc->iot, sc->ioh, AMI_SMBADDR, a);
580 	/* XXX 40bit address ??? */
581 	bus_space_write_1(sc->iot, sc->ioh, AMI_SMBENA, 0);
582 
583 	bus_space_write_1(sc->iot, sc->ioh, AMI_SCMD, AMI_SCMD_ACK);
584 	bus_space_write_1(sc->iot, sc->ioh, AMI_SIEM, AMI_SEIM_ENA |
585 	    bus_space_read_1(sc->iot, sc->ioh, AMI_SIEM));
586 
587 	return 0;
588 }
589 
590 int
ami_schwartz_exec(sc,cmd)591 ami_schwartz_exec(sc, cmd)
592 	struct ami_softc *sc;
593 	struct ami_iocmd *cmd;
594 {
595 	if (bus_space_read_1(sc->iot, sc->ioh, AMI_SMBSTAT) & AMI_SMBST_BUSY)
596 		return EBUSY;
597 
598 	*sc->sc_mbox = *cmd;
599 	bus_space_write_1(sc->iot, sc->ioh, AMI_SCMD, AMI_SCMD_EXEC);
600 	return 0;
601 }
602 
603 int
ami_schwartz_done(sc,mbox)604 ami_schwartz_done(sc, mbox)
605 	struct ami_softc *sc;
606 	struct ami_iocmd *mbox;
607 {
608 	u_int8_t stat;
609 #if 0
610 	/* do not scramble the busy mailbox */
611 	if (sc->sc_mbox->acc_busy)
612 		return (0);
613 #endif
614 	if (bus_space_read_1(sc->iot, sc->ioh, AMI_SMBSTAT) & AMI_SMBST_BUSY)
615 		return 0;
616 
617 	stat = bus_space_read_1(sc->iot, sc->ioh, AMI_ISTAT);
618 	if (stat & AMI_ISTAT_PEND) {
619 		bus_space_write_1(sc->iot, sc->ioh, AMI_ISTAT, stat);
620 
621 		*mbox = *sc->sc_mbox;
622 
623 		bus_space_write_1(sc->iot, sc->ioh, AMI_SCMD, AMI_SCMD_ACK);
624 
625 		return 1;
626 	}
627 
628 	return 0;
629 }
630 
631 int
ami_cmd(ccb,flags,wait)632 ami_cmd(ccb, flags, wait)
633 	struct ami_ccb *ccb;
634 	int flags, wait;
635 {
636 	struct ami_softc *sc = ccb->ccb_sc;
637 	bus_dmamap_t dmap = ccb->ccb_dmamap;
638 	int error = 0, i, s;
639 
640 	if (ccb->ccb_data) {
641 		struct ami_iocmd *cmd = ccb->ccb_cmd;
642 		bus_dma_segment_t *sgd;
643 
644 		error = bus_dmamap_load(sc->dmat, dmap, ccb->ccb_data,
645 		    ccb->ccb_len, NULL, flags);
646 		if (error) {
647 			if (error == EFBIG)
648 				printf("more than %d dma segs\n", AMI_MAXOFFSETS);
649 			else
650 				printf("error %d loading dma map\n", error);
651 
652 			ami_put_ccb(ccb);
653 			return (error);
654 		}
655 
656 		sgd = dmap->dm_segs;
657 		AMI_DPRINTF(AMI_D_DMA, ("data=%p/%u<0x%lx/%u",
658 		    ccb->ccb_data, ccb->ccb_len,
659 		    sgd->ds_addr, sgd->ds_len));
660 
661 		if(dmap->dm_nsegs > 1) {
662 			struct ami_sgent *sgl = ccb->ccb_sglist;
663 
664 			cmd->acc_mbox.amb_nsge = htole32(dmap->dm_nsegs);
665 			cmd->acc_mbox.amb_data = ccb->ccb_sglistpa;
666 
667 			for (i = 0; i < dmap->dm_nsegs; i++, sgd++) {
668 				sgl[i].asg_addr = htole32(sgd->ds_addr);
669 				sgl[i].asg_len  = htole32(sgd->ds_len);
670 				if (i)
671 					AMI_DPRINTF(AMI_D_DMA, (",0x%lx/%u",
672 					    sgd->ds_addr, sgd->ds_len));
673 			}
674 		} else {
675 			cmd->acc_mbox.amb_nsge = htole32(0);
676 			cmd->acc_mbox.amb_data = htole32(sgd->ds_addr);
677 		}
678 		AMI_DPRINTF(AMI_D_DMA, ("> "));
679 
680 		bus_dmamap_sync(sc->dmat, dmap, 0, dmap->dm_mapsize,
681 		    BUS_DMASYNC_PREWRITE);
682 	} else
683 		ccb->ccb_cmd->acc_mbox.amb_nsge = htole32(0);
684 	bus_dmamap_sync(sc->dmat, sc->sc_cmdmap, 0, sc->sc_cmdmap->dm_mapsize,
685 	    BUS_DMASYNC_PREWRITE);
686 
687 	s = splimp();
688 	if ((error = ami_start(ccb, wait))) {
689 		AMI_DPRINTF(AMI_D_DMA, ("error=%d ", error));
690 		__asm __volatile(".globl _bpamierr\n_bpamierr:");
691 		if (ccb->ccb_data)
692 			bus_dmamap_unload(sc->dmat, dmap);
693 		ami_put_ccb(ccb);
694 	} else if (wait) {
695 		AMI_DPRINTF(AMI_D_DMA, ("waiting "));
696 		if ((error = ami_complete(ccb)))
697 			ami_put_ccb(ccb);
698 	}
699 	splx(s);
700 
701 	return (error);
702 }
703 
704 int
ami_start(ccb,wait)705 ami_start(ccb, wait)
706 	struct ami_ccb *ccb;
707 	int wait;
708 {
709 	struct ami_softc *sc = ccb->ccb_sc;
710 	struct ami_iocmd *cmd = ccb->ccb_cmd;
711 	struct scsi_xfer *xs = ccb->ccb_xs;
712 	volatile struct ami_iocmd *mbox = sc->sc_mbox;
713 	int i;
714 
715 	AMI_DPRINTF(AMI_D_CMD, ("start(%d) ", cmd->acc_id));
716 
717 	if (ccb->ccb_state != AMI_CCB_READY) {
718 		printf("%s: ccb %d not ready <%d>\n",
719 		    sc->sc_dev.dv_xname, cmd->acc_id, ccb->ccb_state);
720 		return (EINVAL);
721 	}
722 
723 	if (xs)
724 		timeout_set(&xs->stimeout, ami_stimeout, ccb);
725 
726 	if (wait && mbox->acc_busy) {
727 
728 		for (i = 100000; i-- && mbox->acc_busy; DELAY(10));
729 
730 		if (mbox->acc_busy) {
731 			AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
732 			return (EAGAIN);
733 		}
734 	}
735 
736 	AMI_DPRINTF(AMI_D_CMD, ("exec "));
737 
738 	cmd->acc_busy = 1;
739 	cmd->acc_poll = 0;
740 	cmd->acc_ack = 0;
741 
742 	if (!(i = (sc->sc_exec)(sc, cmd))) {
743 		ccb->ccb_state = AMI_CCB_QUEUED;
744 		TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ccb_link);
745 		if (!wait) {
746 #ifdef AMI_POLLING
747 			if (!timeout_pending(&sc->sc_poll_tmo))
748 				timeout_add(&sc->sc_poll_tmo, 1);
749 #endif
750 			if (xs) {
751 				struct timeval tv;
752 				tv.tv_sec = xs->timeout / 1000;
753 				tv.tv_usec = 1000 * (xs->timeout % 1000);
754 				timeout_add(&xs->stimeout, tvtohz(&tv));
755 			}
756 		}
757 	} else if (!wait && xs) {
758 		AMI_DPRINTF(AMI_D_CMD, ("2queue1(%d) ", cmd->acc_id));
759 		ccb->ccb_state = AMI_CCB_PREQUEUED;
760 		timeout_add(&xs->stimeout, 1);
761 		return (0);
762 	}
763 
764 	return (i);
765 }
766 
767 void
ami_stimeout(v)768 ami_stimeout(v)
769 	void *v;
770 {
771 	struct ami_ccb *ccb = v;
772 	struct ami_softc *sc = ccb->ccb_sc;
773 	struct scsi_xfer *xs = ccb->ccb_xs;
774 	struct ami_iocmd *cmd = ccb->ccb_cmd;
775 	volatile struct ami_iocmd *mbox = sc->sc_mbox;
776 	ami_lock_t lock, s;
777 
778 	lock = AMI_LOCK_AMI(sc);
779 	switch (ccb->ccb_state) {
780 	case AMI_CCB_PREQUEUED:
781 		if (mbox->acc_busy) {
782 			timeout_add(&xs->stimeout, 1);
783 			break;
784 		}
785 
786 		AMI_DPRINTF(AMI_D_CMD, ("requeue(%d) ", cmd->acc_id));
787 
788 		ccb->ccb_state = AMI_CCB_READY;
789 		if (ami_start(ccb, 0)) {
790 			AMI_DPRINTF(AMI_D_CMD, ("requeue(%d) again\n", cmd->acc_id));
791 			ccb->ccb_state = AMI_CCB_PREQUEUED;
792 			timeout_add(&xs->stimeout, 1);
793 		}
794 		break;
795 
796 	case AMI_CCB_QUEUED:
797 		/* XXX need to kill all cmds in the queue and reset the card */
798 		printf("%s: timeout ccb %d\n",
799 		    sc->sc_dev.dv_xname, cmd->acc_id);
800 		AMI_DPRINTF(AMI_D_CMD, ("timeout(%d) ", cmd->acc_id));
801 		if (xs->cmd->opcode != PREVENT_ALLOW &&
802 		    xs->cmd->opcode != SYNCHRONIZE_CACHE) {
803 			bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap, 0,
804 			    ccb->ccb_dmamap->dm_mapsize,
805 			    (xs->flags & SCSI_DATA_IN) ?
806 			    BUS_DMASYNC_POSTREAD :
807 			    BUS_DMASYNC_POSTWRITE);
808 			bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);
809 		}
810 		s = splimp();
811 		TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link);
812 		ami_put_ccb(ccb);
813 		splx(s);
814 		xs->error = XS_TIMEOUT;
815 		xs->flags |= ITSDONE;
816 		scsi_done(xs);
817 		break;
818 	case AMI_CCB_FREE:
819 	case AMI_CCB_READY:
820 		panic("ami_stimeout(%d) botch", cmd->acc_id);
821 	}
822 	AMI_UNLOCK_AMI(sc, lock);
823 }
824 
825 int
ami_complete(ccb)826 ami_complete(ccb)
827 	struct ami_ccb *ccb;
828 {
829 	struct ami_softc *sc = ccb->ccb_sc;
830 	struct scsi_xfer *xs = ccb->ccb_xs;
831 	struct ami_iocmd mbox;
832 	int i, j, rv, status;
833 
834 	i = 1 * (xs? xs->timeout: 1000);
835 	AMI_DPRINTF(AMI_D_CMD, ("%d ", i));
836 	for (rv = 1, status = 0; !status && rv && i--; DELAY(1000))
837 		if ((sc->sc_done)(sc, &mbox)) {
838 			AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat));
839 			status = mbox.acc_status;
840 			for (j = 0; j < mbox.acc_nstat; j++ ) {
841 				int ready = mbox.acc_cmplidl[j];
842 
843 				AMI_DPRINTF(AMI_D_CMD, ("ready=%x ", ready));
844 
845 				if (!ami_done(sc, ready) &&
846 				    ccb->ccb_cmd->acc_id == ready)
847 					rv = 0;
848 			}
849 		}
850 
851 	if (status) {
852 		AMI_DPRINTF(AMI_D_CMD, ("aborted\n"));
853 	} else if (!rv) {
854 		AMI_DPRINTF(AMI_D_CMD, ("complete\n"));
855 	} else if (i < 0) {
856 		AMI_DPRINTF(AMI_D_CMD, ("timeout\n"));
857 	} else
858 		AMI_DPRINTF(AMI_D_CMD, ("screwed\n"));
859 
860 	return rv? rv : status;
861 }
862 
863 int
ami_done(sc,idx)864 ami_done(sc, idx)
865 	struct ami_softc *sc;
866 	int	idx;
867 {
868 	struct ami_ccb *ccb = &sc->sc_ccbs[idx - 1];
869 	struct scsi_xfer *xs = ccb->ccb_xs;
870 	ami_lock_t lock, s;
871 
872 	AMI_DPRINTF(AMI_D_CMD, ("done(%d) ", ccb->ccb_cmd->acc_id));
873 
874 	if (ccb->ccb_state != AMI_CCB_QUEUED) {
875 		printf("%s: unqueued ccb %d ready, state = %d\n",
876 		    sc->sc_dev.dv_xname, idx, ccb->ccb_state);
877 		return (1);
878 	}
879 
880 	lock = AMI_LOCK_AMI(sc);
881 	s = splimp();
882 	ccb->ccb_state = AMI_CCB_READY;
883 	TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link);
884 
885 	if (xs) {
886 		timeout_del(&xs->stimeout);
887 		if (xs->cmd->opcode != PREVENT_ALLOW &&
888 		    xs->cmd->opcode != SYNCHRONIZE_CACHE) {
889 			bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap, 0,
890 			    ccb->ccb_dmamap->dm_mapsize,
891 			    (xs->flags & SCSI_DATA_IN) ?
892 			    BUS_DMASYNC_POSTREAD :
893 			    BUS_DMASYNC_POSTWRITE);
894 			bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);
895 		}
896 		ccb->ccb_xs = NULL;
897 	} else {
898 		struct ami_iocmd *cmd = ccb->ccb_cmd;
899 
900 		switch (cmd->acc_cmd) {
901 		case AMI_INQUIRY:
902 		case AMI_EINQUIRY:
903 		case AMI_EINQUIRY3:
904 			bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap, 0,
905 			    ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
906 			bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);
907 			break;
908 		default:
909 			/* no data */
910 			break;
911 		}
912 	}
913 
914 	ami_put_ccb(ccb);
915 	splx(s);
916 
917 	if (xs) {
918 		xs->resid = 0;
919 		xs->flags |= ITSDONE;
920 		AMI_DPRINTF(AMI_D_CMD, ("scsi_done(%d) ", idx));
921 		scsi_done(xs);
922 	}
923 
924 	AMI_UNLOCK_AMI(sc, lock);
925 
926 	return (0);
927 }
928 
929 void
amiminphys(bp)930 amiminphys(bp)
931 	struct buf *bp;
932 {
933 	if (bp->b_bcount > AMI_MAXFER)
934 		bp->b_bcount = AMI_MAXFER;
935 	minphys(bp);
936 }
937 
938 void
ami_copy_internal_data(xs,v,size)939 ami_copy_internal_data(xs, v, size)
940 	struct scsi_xfer *xs;
941 	void *v;
942 	size_t size;
943 {
944 	size_t copy_cnt;
945 
946 	AMI_DPRINTF(AMI_D_MISC, ("ami_copy_internal_data "));
947 
948 	if (!xs->datalen)
949 		printf("uio move not yet supported\n");
950 	else {
951 		copy_cnt = MIN(size, xs->datalen);
952 		bcopy(v, xs->data, copy_cnt);
953 	}
954 }
955 
956 int
ami_scsi_raw_cmd(xs)957 ami_scsi_raw_cmd(xs)
958 	struct scsi_xfer *xs;
959 {
960 	struct scsi_link *link = xs->sc_link;
961 	struct ami_rawsoftc *rsc = link->adapter_softc;
962 	struct ami_softc *sc = rsc->sc_softc;
963 	u_int8_t channel = rsc->sc_channel, target = link->target;
964 	struct ami_ccb *ccb, *ccb1;
965 	struct ami_iocmd *cmd;
966 	struct ami_passthrough *ps;
967 	int error;
968 	ami_lock_t lock;
969 
970 	AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_raw_cmd "));
971 
972 	lock = AMI_LOCK_AMI(sc);
973 
974 	if (xs->cmdlen > AMI_MAX_CDB) {
975 		AMI_DPRINTF(AMI_D_CMD, ("CDB too big %p ", xs));
976 		bzero(&xs->sense, sizeof(xs->sense));
977 		xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
978 		xs->sense.flags = SKEY_ILLEGAL_REQUEST;
979 		xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
980 		xs->error = XS_SENSE;
981 		scsi_done(xs);
982 		AMI_UNLOCK_AMI(sc, lock);
983 		return (COMPLETE);
984 	}
985 
986 	xs->error = XS_NOERROR;
987 
988 	if ((ccb = ami_get_ccb(sc)) == NULL) {
989 		xs->error = XS_DRIVER_STUFFUP;
990 		scsi_done(xs);
991 		AMI_UNLOCK_AMI(sc, lock);
992 		return (COMPLETE);
993 	}
994 
995 	if ((ccb1 = ami_get_ccb(sc)) == NULL) {
996 		ami_put_ccb(ccb);
997 		xs->error = XS_DRIVER_STUFFUP;
998 		scsi_done(xs);
999 		AMI_UNLOCK_AMI(sc, lock);
1000 		return (COMPLETE);
1001 	}
1002 
1003 	ccb->ccb_xs = xs;
1004 	ccb->ccb_ccb1 = ccb1;
1005 	ccb->ccb_len  = xs->datalen;
1006 	ccb->ccb_data = xs->data;
1007 
1008 	ps = (struct ami_passthrough *)ccb1->ccb_cmd;
1009 	ps->apt_param = AMI_PTPARAM(AMI_TIMEOUT_6,1,0);
1010 	ps->apt_channel = channel;
1011 	ps->apt_target = target;
1012 	bcopy(xs->cmd, ps->apt_cdb, AMI_MAX_CDB);
1013 	ps->apt_ncdb = xs->cmdlen;
1014 	ps->apt_nsense = AMI_MAX_SENSE;
1015 
1016 	cmd = ccb->ccb_cmd;
1017 	cmd->acc_cmd = AMI_PASSTHRU;
1018 	cmd->acc_passthru.apt_data = ccb1->ccb_cmdpa;
1019 
1020 	if ((error = ami_cmd(ccb, ((xs->flags & SCSI_NOSLEEP)?
1021 	    BUS_DMA_NOWAIT : BUS_DMA_WAITOK), xs->flags & SCSI_POLL))) {
1022 
1023 		AMI_DPRINTF(AMI_D_CMD, ("failed %p ", xs));
1024 		if (xs->flags & SCSI_POLL) {
1025 			xs->error = XS_TIMEOUT;
1026 			AMI_UNLOCK_AMI(sc, lock);
1027 			return (TRY_AGAIN_LATER);
1028 		} else {
1029 			xs->error = XS_DRIVER_STUFFUP;
1030 			scsi_done(xs);
1031 			AMI_UNLOCK_AMI(sc, lock);
1032 			return (COMPLETE);
1033 		}
1034 	}
1035 
1036 
1037 	if (xs->flags & SCSI_POLL) {
1038 		scsi_done(xs);
1039 		AMI_UNLOCK_AMI(sc, lock);
1040 		return (COMPLETE);
1041 	}
1042 
1043 	AMI_UNLOCK_AMI(sc, lock);
1044 	return (SUCCESSFULLY_QUEUED);
1045 }
1046 
1047 int
ami_scsi_cmd(xs)1048 ami_scsi_cmd(xs)
1049 	struct scsi_xfer *xs;
1050 {
1051 	struct scsi_link *link = xs->sc_link;
1052 	struct ami_softc *sc = link->adapter_softc;
1053 	struct ami_ccb *ccb;
1054 	struct ami_iocmd *cmd;
1055 	struct scsi_inquiry_data inq;
1056 	struct scsi_sense_data sd;
1057 	struct {
1058 		struct scsi_mode_header hd;
1059 		struct scsi_blk_desc bd;
1060 		union scsi_disk_pages dp;
1061 	} mpd;
1062 	struct scsi_read_cap_data rcd;
1063 	u_int8_t target = link->target;
1064 	u_int32_t blockno, blockcnt;
1065 	struct scsi_rw *rw;
1066 	struct scsi_rw_big *rwb;
1067 	int error, flags;
1068 	ami_lock_t lock;
1069 
1070 	AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd "));
1071 
1072 	lock = AMI_LOCK_AMI(sc);
1073 	if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present ||
1074 	    link->lun != 0) {
1075 		AMI_DPRINTF(AMI_D_CMD, ("no taget %d ", target));
1076 		/* XXX should be XS_SENSE and sense filled out */
1077 		xs->error = XS_DRIVER_STUFFUP;
1078 		xs->flags |= ITSDONE;
1079 		scsi_done(xs);
1080 		AMI_UNLOCK_AMI(sc, lock);
1081 		return (COMPLETE);
1082 	}
1083 
1084 	error = 0;
1085 	xs->error = XS_NOERROR;
1086 
1087 	switch (xs->cmd->opcode) {
1088 	case TEST_UNIT_READY:
1089 	case START_STOP:
1090 #if 0
1091 	case VERIFY:
1092 #endif
1093 		AMI_DPRINTF(AMI_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode,
1094 		    target));
1095 		break;
1096 
1097 	case REQUEST_SENSE:
1098 		AMI_DPRINTF(AMI_D_CMD, ("REQUEST SENSE tgt %d ", target));
1099 		bzero(&sd, sizeof sd);
1100 		sd.error_code = 0x70;
1101 		sd.segment = 0;
1102 		sd.flags = SKEY_NO_SENSE;
1103 		*(u_int32_t*)sd.info = htole32(0);
1104 		sd.extra_len = 0;
1105 		ami_copy_internal_data(xs, &sd, sizeof sd);
1106 		break;
1107 
1108 	case INQUIRY:
1109 		AMI_DPRINTF(AMI_D_CMD, ("INQUIRY tgt %d ", target));
1110 		bzero(&inq, sizeof inq);
1111 		inq.device = T_DIRECT;
1112 		inq.dev_qual2 = 0;
1113 		inq.version = 2;
1114 		inq.response_format = 2;
1115 		inq.additional_length = 32;
1116 		strlcpy(inq.vendor, "AMI    ", sizeof inq.vendor);
1117 		snprintf(inq.product, sizeof inq.product, "Host drive  #%02d",
1118 		    target);
1119 		strlcpy(inq.revision, "   ", sizeof inq.revision);
1120 		ami_copy_internal_data(xs, &inq, sizeof inq);
1121 		break;
1122 
1123 	case MODE_SENSE:
1124 		AMI_DPRINTF(AMI_D_CMD, ("MODE SENSE tgt %d ", target));
1125 
1126 		bzero(&mpd, sizeof mpd);
1127 		switch (((struct scsi_mode_sense *)xs->cmd)->page) {
1128 		case 4:
1129 			/* scsi_disk.h says this should be 0x16 */
1130 			mpd.dp.rigid_geometry.pg_length = 0x16;
1131 			mpd.hd.data_length = sizeof mpd.hd + sizeof mpd.bd +
1132 			    mpd.dp.rigid_geometry.pg_length;
1133 			mpd.hd.blk_desc_len = sizeof mpd.bd;
1134 
1135 			mpd.hd.dev_spec = 0;	/* writeprotect ? XXX */
1136 			_lto3b(AMI_SECTOR_SIZE, mpd.bd.blklen);
1137 			mpd.dp.rigid_geometry.pg_code = 4;
1138 			_lto3b(sc->sc_hdr[target].hd_size /
1139 			    sc->sc_hdr[target].hd_heads /
1140 			    sc->sc_hdr[target].hd_secs,
1141 			    mpd.dp.rigid_geometry.ncyl);
1142 			mpd.dp.rigid_geometry.nheads =
1143 			    sc->sc_hdr[target].hd_heads;
1144 			ami_copy_internal_data(xs, (u_int8_t *)&mpd,
1145 			    sizeof mpd);
1146 			break;
1147 
1148 		default:
1149 			printf("%s: mode sense page %d not simulated\n",
1150 			    sc->sc_dev.dv_xname,
1151 			    ((struct scsi_mode_sense *)xs->cmd)->page);
1152 			xs->error = XS_DRIVER_STUFFUP;
1153 		}
1154 		break;
1155 
1156 	case READ_CAPACITY:
1157 		AMI_DPRINTF(AMI_D_CMD, ("READ CAPACITY tgt %d ", target));
1158 		bzero(&rcd, sizeof rcd);
1159 		_lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr);
1160 		_lto4b(AMI_SECTOR_SIZE, rcd.length);
1161 		ami_copy_internal_data(xs, &rcd, sizeof rcd);
1162 		break;
1163 
1164 	case PREVENT_ALLOW:
1165 		AMI_DPRINTF(AMI_D_CMD, ("PREVENT/ALLOW "));
1166 		AMI_UNLOCK_AMI(sc, lock);
1167 		return (COMPLETE);
1168 
1169 	case SYNCHRONIZE_CACHE:
1170 		AMI_DPRINTF(AMI_D_CMD, ("SYNCHRONIZE CACHE "));
1171 		error++;
1172 	case READ_COMMAND:
1173 		if (!error) {
1174 			AMI_DPRINTF(AMI_D_CMD, ("READ "));
1175 			error++;
1176 		}
1177 	case READ_BIG:
1178 		if (!error) {
1179 			AMI_DPRINTF(AMI_D_CMD, ("READ BIG "));
1180 			error++;
1181 		}
1182 	case WRITE_COMMAND:
1183 		if (!error) {
1184 			AMI_DPRINTF(AMI_D_CMD, ("WRITE "));
1185 			error++;
1186 		}
1187 	case WRITE_BIG:
1188 		if (!error) {
1189 			AMI_DPRINTF(AMI_D_CMD, ("WRITE BIG "));
1190 			error++;
1191 		}
1192 
1193 		flags = xs->flags;
1194 		if (xs->cmd->opcode != SYNCHRONIZE_CACHE) {
1195 			/* A read or write operation. */
1196 			if (xs->cmdlen == 6) {
1197 				rw = (struct scsi_rw *)xs->cmd;
1198 				blockno = _3btol(rw->addr) &
1199 				    (SRW_TOPADDR << 16 | 0xffff);
1200 				blockcnt = rw->length ? rw->length : 0x100;
1201 			} else {
1202 				rwb = (struct scsi_rw_big *)xs->cmd;
1203 				blockno = _4btol(rwb->addr);
1204 				blockcnt = _2btol(rwb->length);
1205 				/* TODO: reflect DPO & FUA flags */
1206 				if (xs->cmd->opcode == WRITE_BIG &&
1207 				    rwb->byte2 & 0x18)
1208 					flags |= 0;
1209 			}
1210 			if (blockno >= sc->sc_hdr[target].hd_size ||
1211 			    blockno + blockcnt > sc->sc_hdr[target].hd_size) {
1212 				printf("%s: out of bounds %u-%u >= %u\n",
1213 				    sc->sc_dev.dv_xname, blockno, blockcnt,
1214 				    sc->sc_hdr[target].hd_size);
1215 				xs->error = XS_DRIVER_STUFFUP;
1216 				scsi_done(xs);
1217 				AMI_UNLOCK_AMI(sc, lock);
1218 				return (COMPLETE);
1219 			}
1220 		}
1221 
1222 		if ((ccb = ami_get_ccb(sc)) == NULL) {
1223 			AMI_DPRINTF(AMI_D_CMD, ("no more ccbs "));
1224 			xs->error = XS_DRIVER_STUFFUP;
1225 			scsi_done(xs);
1226 			AMI_UNLOCK_AMI(sc, lock);
1227 		__asm __volatile(".globl _bpamiccb\n_bpamiccb:");
1228 			return (COMPLETE);
1229 		}
1230 
1231 		ccb->ccb_xs = xs;
1232 		ccb->ccb_ccb1 = NULL;
1233 		ccb->ccb_len  = xs->datalen;
1234 		ccb->ccb_data = xs->data;
1235 		cmd = ccb->ccb_cmd;
1236 		cmd->acc_mbox.amb_nsect = htole16(blockcnt);
1237 		cmd->acc_mbox.amb_lba = htole32(blockno);
1238 		cmd->acc_mbox.amb_ldn = target;
1239 		cmd->acc_mbox.amb_data = 0;
1240 
1241 		switch (xs->cmd->opcode) {
1242 		case SYNCHRONIZE_CACHE:
1243 			cmd->acc_cmd = AMI_FLUSH;
1244 			if (xs->timeout < 30000)
1245 				xs->timeout = 30000;	/* at least 30sec */
1246 			break;
1247 		case READ_COMMAND: case READ_BIG:
1248 			cmd->acc_cmd = AMI_READ;
1249 			break;
1250 		case WRITE_COMMAND: case WRITE_BIG:
1251 			cmd->acc_cmd = AMI_WRITE;
1252 			break;
1253 		}
1254 
1255 		if ((error = ami_cmd(ccb, ((flags & SCSI_NOSLEEP)?
1256 		    BUS_DMA_NOWAIT : BUS_DMA_WAITOK), flags & SCSI_POLL))) {
1257 
1258 			AMI_DPRINTF(AMI_D_CMD, ("failed %p ", xs));
1259 		__asm __volatile(".globl _bpamifail\n_bpamifail:");
1260 			if (flags & SCSI_POLL) {
1261 				xs->error = XS_TIMEOUT;
1262 				AMI_UNLOCK_AMI(sc, lock);
1263 				return (TRY_AGAIN_LATER);
1264 			} else {
1265 				xs->error = XS_DRIVER_STUFFUP;
1266 				scsi_done(xs);
1267 				AMI_UNLOCK_AMI(sc, lock);
1268 				return (COMPLETE);
1269 			}
1270 		}
1271 
1272 		AMI_UNLOCK_AMI(sc, lock);
1273 		if (flags & SCSI_POLL)
1274 			return (COMPLETE);
1275 		else
1276 			return (SUCCESSFULLY_QUEUED);
1277 
1278 	default:
1279 		AMI_DPRINTF(AMI_D_CMD, ("unknown opc %d ", xs->cmd->opcode));
1280 		xs->error = XS_DRIVER_STUFFUP;
1281 	}
1282 
1283 	AMI_UNLOCK_AMI(sc, lock);
1284 	return (COMPLETE);
1285 }
1286 
1287 int
ami_intr(v)1288 ami_intr(v)
1289 	void *v;
1290 {
1291 	struct ami_softc *sc = v;
1292 	struct ami_iocmd mbox;
1293 	int i, s, rv = 0;
1294 	ami_lock_t lock;
1295 
1296 	if (TAILQ_EMPTY(&sc->sc_ccbq))
1297 		return (0);
1298 
1299 	AMI_DPRINTF(AMI_D_INTR, ("intr "));
1300 
1301 	lock = AMI_LOCK_AMI(sc);
1302 	s = splimp();	/* XXX need to do this to mask timeouts */
1303 	while ((sc->sc_done)(sc, &mbox)) {
1304 		AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat));
1305 		for (i = 0; i < mbox.acc_nstat; i++ ) {
1306 			int ready = mbox.acc_cmplidl[i];
1307 
1308 			AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready));
1309 
1310 			if (!ami_done(sc, ready))
1311 				rv |= 1;
1312 		}
1313 	}
1314 
1315 #ifdef AMI_POLLING
1316 	if (!TAILQ_EMPTY(&sc->sc_ccbq) && !timeout_pending(&sc->sc_poll_tmo)) {
1317 		AMI_DPRINTF(AMI_D_INTR, ("tmo "));
1318 		timeout_add(&sc->sc_poll_tmo, 2);
1319 	}
1320 #endif
1321 
1322 	splx(s);
1323 	AMI_UNLOCK_AMI(sc, lock);
1324 	AMI_DPRINTF(AMI_D_INTR, ("exit "));
1325 	return (rv);
1326 }
1327