1 /*	$OpenBSD: cac.c,v 1.18 2004/05/04 16:59:31 grange Exp $	*/
2 /*	$NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $	*/
3 
4 /*
5  * Copyright (c) 2001,2003 Michael Shalayeff
6  * All rights reserved.
7  *
8  * The SCSI emulation layer is derived from gdt(4) driver,
9  * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*-
33  * Copyright (c) 2000 The NetBSD Foundation, Inc.
34  * All rights reserved.
35  *
36  * This code is derived from software contributed to The NetBSD Foundation
37  * by Andrew Doran.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgement:
49  *        This product includes software developed by the NetBSD
50  *        Foundation, Inc. and its contributors.
51  * 4. Neither the name of The NetBSD Foundation nor the names of its
52  *    contributors may be used to endorse or promote products derived
53  *    from this software without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
56  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
57  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
58  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
59  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
60  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
61  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
62  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
63  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
65  * POSSIBILITY OF SUCH DAMAGE.
66  */
67 
68 /*
69  * Driver for Compaq array controllers.
70  */
71 
72 /* #define	CAC_DEBUG */
73 
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/kernel.h>
77 #include <sys/device.h>
78 #include <sys/queue.h>
79 #include <sys/proc.h>
80 #include <sys/buf.h>
81 #include <sys/endian.h>
82 #include <sys/malloc.h>
83 #include <sys/pool.h>
84 
85 #include <machine/bus.h>
86 
87 #include <scsi/scsi_all.h>
88 #include <scsi/scsi_disk.h>
89 #include <scsi/scsiconf.h>
90 
91 #include <dev/ic/cacreg.h>
92 #include <dev/ic/cacvar.h>
93 
94 struct cfdriver cac_cd = {
95 	NULL, "cac", DV_DULL
96 };
97 
98 int     cac_scsi_cmd(struct scsi_xfer *);
99 void	cacminphys(struct buf *bp);
100 
101 struct scsi_adapter cac_switch = {
102 	cac_scsi_cmd, cacminphys, 0, 0,
103 };
104 
105 struct scsi_device cac_dev = {
106 	NULL, NULL, NULL, NULL
107 };
108 
109 struct	cac_ccb *cac_ccb_alloc(struct cac_softc *, int);
110 void	cac_ccb_done(struct cac_softc *, struct cac_ccb *);
111 void	cac_ccb_free(struct cac_softc *, struct cac_ccb *);
112 int	cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int);
113 int	cac_ccb_start(struct cac_softc *, struct cac_ccb *);
114 int	cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
115 	int drive, int blkno, int flags, struct scsi_xfer *xs);
116 int	cac_get_dinfo(struct cac_softc *sc, int target);
117 int	cac_flush(struct cac_softc *sc);
118 void	cac_shutdown(void *);
119 void	cac_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size);
120 
121 struct	cac_ccb *cac_l0_completed(struct cac_softc *);
122 int	cac_l0_fifo_full(struct cac_softc *);
123 void	cac_l0_intr_enable(struct cac_softc *, int);
124 int	cac_l0_intr_pending(struct cac_softc *);
125 void	cac_l0_submit(struct cac_softc *, struct cac_ccb *);
126 
127 void	*cac_sdh;	/* shutdown hook */
128 
129 const
130 struct cac_linkage cac_l0 = {
131 	cac_l0_completed,
132 	cac_l0_fifo_full,
133 	cac_l0_intr_enable,
134 	cac_l0_intr_pending,
135 	cac_l0_submit
136 };
137 
138 /*
139  * Initialise our interface to the controller.
140  */
141 int
cac_init(struct cac_softc * sc,int startfw)142 cac_init(struct cac_softc *sc, int startfw)
143 {
144 	struct cac_controller_info cinfo;
145 	int error, rseg, size, i;
146 	bus_dma_segment_t seg[1];
147 	struct cac_ccb *ccb;
148 
149 	SIMPLEQ_INIT(&sc->sc_ccb_free);
150 	SIMPLEQ_INIT(&sc->sc_ccb_queue);
151 
152         size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
153 
154 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1,
155 	    &rseg, BUS_DMA_NOWAIT)) != 0) {
156 		printf("%s: unable to allocate CCBs, error = %d\n",
157 		    sc->sc_dv.dv_xname, error);
158 		return (-1);
159 	}
160 
161 	if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size,
162 	    &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
163 		printf("%s: unable to map CCBs, error = %d\n",
164 		    sc->sc_dv.dv_xname, error);
165 		return (-1);
166 	}
167 
168 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
169 	    BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
170 		printf("%s: unable to create CCB DMA map, error = %d\n",
171 		    sc->sc_dv.dv_xname, error);
172 		return (-1);
173 	}
174 
175 	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
176 	    size, NULL, BUS_DMA_NOWAIT)) != 0) {
177 		printf("%s: unable to load CCB DMA map, error = %d\n",
178 		    sc->sc_dv.dv_xname, error);
179 		return (-1);
180 	}
181 
182 	sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
183 	memset(sc->sc_ccbs, 0, size);
184 	ccb = (struct cac_ccb *)sc->sc_ccbs;
185 
186 	for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
187 		/* Create the DMA map for this CCB's data */
188 		error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
189 		    CAC_SG_SIZE, CAC_MAX_XFER, 0,
190 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
191 		    &ccb->ccb_dmamap_xfer);
192 
193 		if (error) {
194 			printf("%s: can't create ccb dmamap (%d)\n",
195 			    sc->sc_dv.dv_xname, error);
196 			break;
197 		}
198 
199 		ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
200 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
201 	}
202 
203 	/* Start firmware background tasks, if needed. */
204 	if (startfw) {
205 		if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
206 		    0, 0, CAC_CCB_DATA_IN, NULL)) {
207 			printf("%s: CAC_CMD_START_FIRMWARE failed\n",
208 			    sc->sc_dv.dv_xname);
209 			return (-1);
210 		}
211 	}
212 
213 	if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
214 	    CAC_CCB_DATA_IN, NULL)) {
215 		printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
216 		    sc->sc_dv.dv_xname);
217 		return (-1);
218 	}
219 
220 	if (!cinfo.num_drvs) {
221 		printf("%s: no volumes defined\n", sc->sc_dv.dv_xname);
222 		return (-1);
223 	}
224 
225 	sc->sc_nunits = cinfo.num_drvs;
226 	sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info),
227 	    M_DEVBUF, M_NOWAIT);
228 	if (sc->sc_dinfos == NULL) {
229 		printf("%s: cannot allocate memory for drive_info\n",
230 		    sc->sc_dv.dv_xname);
231 		return (-1);
232 	}
233 	bzero(sc->sc_dinfos, cinfo.num_drvs * sizeof(struct cac_drive_info));
234 
235 	sc->sc_link.adapter_softc = sc;
236 	sc->sc_link.adapter = &cac_switch;
237 	sc->sc_link.adapter_target = cinfo.num_drvs;
238 	sc->sc_link.adapter_buswidth = cinfo.num_drvs;
239 	sc->sc_link.device = &cac_dev;
240 	sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits;
241 	if (sc->sc_link.openings < 4 )
242 		sc->sc_link.openings = 4;
243 
244 	config_found(&sc->sc_dv, &sc->sc_link, scsiprint);
245 
246 	/* Set our `shutdownhook' before we start any device activity. */
247 	if (cac_sdh == NULL)
248 		cac_sdh = shutdownhook_establish(cac_shutdown, NULL);
249 
250 	(*sc->sc_cl->cl_intr_enable)(sc, 1);
251 
252 	return (0);
253 }
254 
255 int
cac_flush(sc)256 cac_flush(sc)
257 	struct cac_softc *sc;
258 {
259 	u_int8_t buf[512];
260 
261 	memset(buf, 0, sizeof(buf));
262 	buf[0] = 1;
263 	return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
264 	    CAC_CCB_DATA_OUT, NULL);
265 }
266 
267 /*
268  * Shut down all `cac' controllers.
269  */
270 void
cac_shutdown(void * cookie)271 cac_shutdown(void *cookie)
272 {
273 	extern struct cfdriver cac_cd;
274 	struct cac_softc *sc;
275 	int i;
276 
277 	for (i = 0; i < cac_cd.cd_ndevs; i++) {
278 		if ((sc = (struct cac_softc *)device_lookup(&cac_cd, i)) == NULL)
279 			continue;
280 		cac_flush(sc);
281 	}
282 }
283 
284 /*
285  * Handle an interrupt from the controller: process finished CCBs and
286  * dequeue any waiting CCBs.
287  */
288 int
cac_intr(v)289 cac_intr(v)
290 	void *v;
291 {
292 	struct cac_softc *sc = v;
293 	struct cac_ccb *ccb;
294 	int istat, ret = 0;
295 
296 	if (!(istat = (sc->sc_cl->cl_intr_pending)(sc)))
297 		return 0;
298 
299 	if (istat & CAC_INTR_FIFO_NEMPTY)
300 		while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) {
301 			ret = 1;
302 			cac_ccb_done(sc, ccb);
303 		}
304 	cac_ccb_start(sc, NULL);
305 
306 	return (ret);
307 }
308 
309 /*
310  * Execute a [polled] command.
311  */
312 int
cac_cmd(struct cac_softc * sc,int command,void * data,int datasize,int drive,int blkno,int flags,struct scsi_xfer * xs)313 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
314 	int drive, int blkno, int flags, struct scsi_xfer *xs)
315 {
316 	struct cac_ccb *ccb;
317 	struct cac_sgb *sgb;
318 	int i, rv, size, nsegs;
319 
320 #ifdef CAC_DEBUG
321 	printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ",
322 	    command, drive, blkno, data, datasize, flags, xs);
323 #endif
324 
325 	if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) {
326 		printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
327 		return (ENOMEM);
328 	}
329 
330 	if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
331 		bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
332 		    (void *)data, datasize, NULL, BUS_DMA_NOWAIT);
333 
334 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
335 		    ccb->ccb_dmamap_xfer->dm_mapsize,
336 		    (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
337 		    BUS_DMASYNC_PREWRITE);
338 
339 		sgb = ccb->ccb_seg;
340 		nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
341 		if (nsegs > CAC_SG_SIZE)
342 			panic("cac_cmd: nsegs botch");
343 
344 		size = 0;
345 		for (i = 0; i < nsegs; i++, sgb++) {
346 			size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
347 			sgb->length =
348 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
349 			sgb->addr =
350 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
351 		}
352 	} else {
353 		size = datasize;
354 		nsegs = 0;
355 	}
356 
357 	ccb->ccb_hdr.drive = drive;
358 	ccb->ccb_hdr.priority = 0;
359 	ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
360 	    sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
361 
362 	ccb->ccb_req.next = 0;
363 	ccb->ccb_req.command = command;
364 	ccb->ccb_req.error = 0;
365 	ccb->ccb_req.blkno = htole32(blkno);
366 	ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
367 	ccb->ccb_req.sgcount = nsegs;
368 	ccb->ccb_req.reserved = 0;
369 
370 	ccb->ccb_flags = flags;
371 	ccb->ccb_datasize = size;
372 	ccb->ccb_xs = xs;
373 
374 	if (!xs || xs->flags & SCSI_POLL) {
375 
376 		/* Synchronous commands musn't wait. */
377 		if ((*sc->sc_cl->cl_fifo_full)(sc)) {
378 			cac_ccb_free(sc, ccb);
379 			rv = -1;
380 		} else {
381 			ccb->ccb_flags |= CAC_CCB_ACTIVE;
382 			(*sc->sc_cl->cl_submit)(sc, ccb);
383 			rv = cac_ccb_poll(sc, ccb, 2000);
384 		}
385 	} else
386 		rv = cac_ccb_start(sc, ccb);
387 
388 	return (rv);
389 }
390 
391 /*
392  * Wait for the specified CCB to complete.  Must be called at splbio.
393  */
394 int
cac_ccb_poll(struct cac_softc * sc,struct cac_ccb * wantccb,int timo)395 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
396 {
397 	struct cac_ccb *ccb;
398 	int t = timo * 10;
399 
400 	do {
401 		for (; t--; DELAY(100))
402 			if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
403 				break;
404 		if (t < 0) {
405 			printf("%s: timeout\n", sc->sc_dv.dv_xname);
406 			return (EBUSY);
407 		}
408 		cac_ccb_done(sc, ccb);
409 	} while (ccb != wantccb);
410 
411 	return (0);
412 }
413 
414 /*
415  * Enqueue the specified command (if any) and attempt to start all enqueued
416  * commands.  Must be called at splbio.
417  */
418 int
cac_ccb_start(struct cac_softc * sc,struct cac_ccb * ccb)419 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
420 {
421 	if (ccb != NULL)
422 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
423 
424 	while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL &&
425 	    !(*sc->sc_cl->cl_fifo_full)(sc)) {
426 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
427 		ccb->ccb_flags |= CAC_CCB_ACTIVE;
428 		(*sc->sc_cl->cl_submit)(sc, ccb);
429 	}
430 
431 	return (0);
432 }
433 
434 /*
435  * Process a finished CCB.
436  */
437 void
cac_ccb_done(struct cac_softc * sc,struct cac_ccb * ccb)438 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
439 {
440 	struct scsi_xfer *xs = ccb->ccb_xs;
441 	int error = 0;
442 
443 	if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) {
444 		printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs);
445 		if (xs) {
446 			xs->error = XS_DRIVER_STUFFUP;
447 			scsi_done(xs);
448 		}
449 		return;
450 	}
451 
452 	if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
453 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
454 		    ccb->ccb_dmamap_xfer->dm_mapsize,
455 		    ccb->ccb_flags & CAC_CCB_DATA_IN ?
456 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
457 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
458 	}
459 
460 	if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
461 		printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname);
462 	if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
463 		error = 1;
464 		printf("%s: hard error\n", sc->sc_dv.dv_xname);
465 	}
466 	if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
467 		error = 1;
468 		printf("%s: invalid request\n", sc->sc_dv.dv_xname);
469 	}
470 
471 	cac_ccb_free(sc, ccb);
472 	if (xs) {
473 		if (error)
474 			xs->error = XS_DRIVER_STUFFUP;
475 		else
476 			xs->resid = 0;
477 
478 		xs->flags |= ITSDONE;
479 		scsi_done(xs);
480 	}
481 }
482 
483 /*
484  * Allocate a CCB.
485  */
486 struct cac_ccb *
cac_ccb_alloc(struct cac_softc * sc,int nosleep)487 cac_ccb_alloc(struct cac_softc *sc, int nosleep)
488 {
489 	struct cac_ccb *ccb;
490 
491 	if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL)
492 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
493 	else
494 		ccb = NULL;
495 	return (ccb);
496 }
497 
498 /*
499  * Put a CCB onto the freelist.
500  */
501 void
cac_ccb_free(struct cac_softc * sc,struct cac_ccb * ccb)502 cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb)
503 {
504 
505 	ccb->ccb_flags = 0;
506 	SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
507 }
508 
509 int
cac_get_dinfo(sc,target)510 cac_get_dinfo(sc, target)
511 	struct cac_softc *sc;
512 	int target;
513 {
514 	if (sc->sc_dinfos[target].ncylinders)
515 		return (0);
516 
517 	if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target],
518 	    sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) {
519 		printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
520 		    sc->sc_dv.dv_xname);
521 		return (-1);
522 	}
523 
524 	return (0);
525 }
526 
527 void
cacminphys(bp)528 cacminphys(bp)
529 	struct buf *bp;
530 {
531 	if (bp->b_bcount > CAC_MAX_XFER)
532 		bp->b_bcount = CAC_MAX_XFER;
533 	minphys(bp);
534 }
535 
536 void
cac_copy_internal_data(xs,v,size)537 cac_copy_internal_data(xs, v, size)
538 	struct scsi_xfer *xs;
539 	void *v;
540 	size_t size;
541 {
542 	size_t copy_cnt;
543 
544 	if (!xs->datalen)
545 		printf("uio move is not yet supported\n");
546 	else {
547 		copy_cnt = MIN(size, xs->datalen);
548 		bcopy(v, xs->data, copy_cnt);
549 	}
550 }
551 
552 int
cac_scsi_cmd(xs)553 cac_scsi_cmd(xs)
554 	struct scsi_xfer *xs;
555 {
556 	struct scsi_link *link = xs->sc_link;
557 	struct cac_softc *sc = link->adapter_softc;
558 	struct cac_drive_info *dinfo;
559 	struct scsi_inquiry_data inq;
560 	struct scsi_sense_data sd;
561 	struct {
562 		struct scsi_mode_header hd;
563 		struct scsi_blk_desc bd;
564 		union scsi_disk_pages dp;
565 	} mpd;
566 	struct scsi_read_cap_data rcd;
567 	u_int8_t target = link->target;
568 	u_int32_t blockno, blockcnt, size;
569 	struct scsi_rw *rw;
570 	struct scsi_rw_big *rwb;
571 	int op, flags, s, error, poll;
572 	const char *p;
573 
574 	if (target >= sc->sc_nunits || link->lun != 0) {
575 		xs->error = XS_DRIVER_STUFFUP;
576 		return (COMPLETE);
577 	}
578 
579 	s = splbio();
580 	xs->error = XS_NOERROR;
581 	xs->free_list.le_next = NULL;
582 	dinfo = &sc->sc_dinfos[target];
583 
584 	switch (xs->cmd->opcode) {
585 	case TEST_UNIT_READY:
586 	case START_STOP:
587 #if 0
588 	case VERIFY:
589 #endif
590 		break;
591 
592 	case REQUEST_SENSE:
593 		bzero(&sd, sizeof sd);
594 		sd.error_code = 0x70;
595 		sd.segment = 0;
596 		sd.flags = SKEY_NO_SENSE;
597 		*(u_int32_t*)sd.info = htole32(0);
598 		sd.extra_len = 0;
599 		cac_copy_internal_data(xs, &sd, sizeof sd);
600 		break;
601 
602 	case INQUIRY:
603 		if (cac_get_dinfo(sc, target)) {
604 			xs->error = XS_DRIVER_STUFFUP;
605 			break;
606 		}
607 		bzero(&inq, sizeof inq);
608 		inq.device = T_DIRECT;
609 		inq.dev_qual2 = 0;
610 		inq.version = 2;
611 		inq.response_format = 2;
612 		inq.additional_length = 32;
613 		strlcpy(inq.vendor, "Compaq  ", sizeof inq.vendor);
614 		switch (CAC_GET1(dinfo->mirror)) {
615 		case 0: p = "RAID0";	break;
616 		case 1: p = "RAID4";	break;
617 		case 2: p = "RAID1";	break;
618 		case 3: p = "RAID5";	break;
619 		default:p = "<UNK>";	break;
620 		}
621 		snprintf(inq.product, sizeof inq.product, "%s volume  #%02d",
622 		    p, target);
623 		strlcpy(inq.revision, "   ", sizeof inq.revision);
624 		cac_copy_internal_data(xs, &inq, sizeof inq);
625 		break;
626 
627 	case MODE_SENSE:
628 		if (cac_get_dinfo(sc, target)) {
629 			xs->error = XS_DRIVER_STUFFUP;
630 			break;
631 		}
632 		bzero(&mpd, sizeof mpd);
633 		switch (((struct scsi_mode_sense *)xs->cmd)->page) {
634 		case 4:
635 			/* scsi_disk.h says this should be 0x16 */
636 			mpd.dp.rigid_geometry.pg_length = 0x16;
637 			mpd.hd.data_length = sizeof mpd.hd + sizeof mpd.bd +
638 			    mpd.dp.rigid_geometry.pg_length;
639 			mpd.hd.blk_desc_len = sizeof mpd.bd;
640 
641 			/* XXX */
642 			mpd.hd.dev_spec = 0;
643 			_lto3b(CAC_SECTOR_SIZE, mpd.bd.blklen);
644 			mpd.dp.rigid_geometry.pg_code = 4;
645 			_lto3b(CAC_GET2(dinfo->ncylinders),
646 			    mpd.dp.rigid_geometry.ncyl);
647 			mpd.dp.rigid_geometry.nheads =
648 			    CAC_GET1(dinfo->nheads);
649 			cac_copy_internal_data(xs, (u_int8_t *)&mpd,
650 			    sizeof mpd);
651 			break;
652 
653 		default:
654 			printf("%s: mode sense page %d not simulated\n",
655 			    sc->sc_dv.dv_xname,
656 			    ((struct scsi_mode_sense *)xs->cmd)->page);
657 			xs->error = XS_DRIVER_STUFFUP;
658 			splx(s);
659 			return (TRY_AGAIN_LATER);
660 		}
661 		break;
662 
663 	case READ_CAPACITY:
664 		if (cac_get_dinfo(sc, target)) {
665 			xs->error = XS_DRIVER_STUFFUP;
666 			break;
667 		}
668 		bzero(&rcd, sizeof rcd);
669 		_lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
670 		    CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
671 		_lto4b(CAC_SECTOR_SIZE, rcd.length);
672 		cac_copy_internal_data(xs, &rcd, sizeof rcd);
673 		break;
674 
675 	case PREVENT_ALLOW:
676 		break;
677 
678 	case SYNCHRONIZE_CACHE:
679 		if (cac_flush(sc))
680 			xs->error = XS_DRIVER_STUFFUP;
681 		break;
682 
683 	case READ_COMMAND:
684 	case READ_BIG:
685 	case WRITE_COMMAND:
686 	case WRITE_BIG:
687 
688 		flags = 0;
689 		/* A read or write operation. */
690 		if (xs->cmdlen == 6) {
691 			rw = (struct scsi_rw *)xs->cmd;
692 			blockno = _3btol(rw->addr) &
693 			    (SRW_TOPADDR << 16 | 0xffff);
694 			blockcnt = rw->length ? rw->length : 0x100;
695 		} else {
696 			rwb = (struct scsi_rw_big *)xs->cmd;
697 			blockno = _4btol(rwb->addr);
698 			blockcnt = _2btol(rwb->length);
699 		}
700 		size = CAC_GET2(dinfo->ncylinders) *
701 		    CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
702 		if (blockno >= size || blockno + blockcnt > size) {
703 			printf("%s: out of bounds %u-%u >= %u\n",
704 			    sc->sc_dv.dv_xname, blockno, blockcnt, size);
705 			xs->error = XS_DRIVER_STUFFUP;
706 			scsi_done(xs);
707 			break;
708 		}
709 
710 		switch (xs->cmd->opcode) {
711 		case READ_COMMAND:
712 		case READ_BIG:
713 			op = CAC_CMD_READ;
714 			flags = CAC_CCB_DATA_IN;
715 			break;
716 		case WRITE_COMMAND:
717 		case WRITE_BIG:
718 			op = CAC_CMD_WRITE;
719 			flags = CAC_CCB_DATA_OUT;
720 			break;
721 		}
722 
723 		poll = xs->flags & SCSI_POLL;
724 		if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
725 		    target, blockno, flags, xs))) {
726 
727 			if (error == ENOMEM) {
728 				xs->error = XS_BUSY;
729 				splx(s);
730 				return (TRY_AGAIN_LATER);
731 			} else if (poll) {
732 				xs->error = XS_TIMEOUT;
733 				splx(s);
734 				return (TRY_AGAIN_LATER);
735 			} else {
736 				xs->error = XS_DRIVER_STUFFUP;
737 				scsi_done(xs);
738 				break;
739 			}
740 		}
741 
742 		splx(s);
743 
744 		if (poll)
745 			return (COMPLETE);
746 		else
747 			return (SUCCESSFULLY_QUEUED);
748 
749 	default:
750 		xs->error = XS_DRIVER_STUFFUP;
751 	}
752 	splx(s);
753 
754 	return (COMPLETE);
755 }
756 
757 /*
758  * Board specific linkage shared between multiple bus types.
759  */
760 
761 int
cac_l0_fifo_full(struct cac_softc * sc)762 cac_l0_fifo_full(struct cac_softc *sc)
763 {
764 
765 	return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
766 }
767 
768 void
cac_l0_submit(struct cac_softc * sc,struct cac_ccb * ccb)769 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
770 {
771 #ifdef CAC_DEBUG
772 	printf("submit-%x ", ccb->ccb_paddr);
773 #endif
774 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
775 	    sc->sc_dmamap->dm_mapsize,
776 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
777 	cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
778 }
779 
780 struct cac_ccb *
cac_l0_completed(sc)781 cac_l0_completed(sc)
782 	struct cac_softc *sc;
783 {
784 	struct cac_ccb *ccb;
785 	paddr_t off;
786 
787 	if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
788 		return NULL;
789 #ifdef CAC_DEBUG
790 	printf("compl-%x ", off);
791 #endif
792 	if (off & 3 && ccb->ccb_req.error == 0)
793 		ccb->ccb_req.error = CAC_RET_CMD_INVALID;
794 
795 	off = (off & ~3) - sc->sc_ccbs_paddr;
796 	ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
797 
798 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
799 	    sc->sc_dmamap->dm_mapsize,
800 	    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
801 
802 	return (ccb);
803 }
804 
805 int
cac_l0_intr_pending(struct cac_softc * sc)806 cac_l0_intr_pending(struct cac_softc *sc)
807 {
808 
809 	return (cac_inl(sc, CAC_REG_INTR_PENDING));
810 }
811 
812 void
cac_l0_intr_enable(struct cac_softc * sc,int state)813 cac_l0_intr_enable(struct cac_softc *sc, int state)
814 {
815 
816 	cac_outl(sc, CAC_REG_INTR_MASK,
817 	    state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
818 }
819