Annotation of sys/dev/ic/cac.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cac.c,v 1.23 2006/11/28 23:59:45 dlg 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
142: cac_init(struct cac_softc *sc, int startfw)
143: {
144: struct scsibus_attach_args saa;
145: struct cac_controller_info cinfo;
146: int error, rseg, size, i;
147: bus_dma_segment_t seg[1];
148: struct cac_ccb *ccb;
149:
150: SIMPLEQ_INIT(&sc->sc_ccb_free);
151: SIMPLEQ_INIT(&sc->sc_ccb_queue);
152:
153: size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
154:
155: if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1,
156: &rseg, BUS_DMA_NOWAIT)) != 0) {
157: printf("%s: unable to allocate CCBs, error = %d\n",
158: sc->sc_dv.dv_xname, error);
159: return (-1);
160: }
161:
162: if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size,
163: &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
164: printf("%s: unable to map CCBs, error = %d\n",
165: sc->sc_dv.dv_xname, error);
166: return (-1);
167: }
168:
169: if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
170: BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
171: printf("%s: unable to create CCB DMA map, error = %d\n",
172: sc->sc_dv.dv_xname, error);
173: return (-1);
174: }
175:
176: if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
177: size, NULL, BUS_DMA_NOWAIT)) != 0) {
178: printf("%s: unable to load CCB DMA map, error = %d\n",
179: sc->sc_dv.dv_xname, error);
180: return (-1);
181: }
182:
183: sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
184: memset(sc->sc_ccbs, 0, size);
185: ccb = (struct cac_ccb *)sc->sc_ccbs;
186:
187: for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
188: /* Create the DMA map for this CCB's data */
189: error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
190: CAC_SG_SIZE, CAC_MAX_XFER, 0,
191: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
192: &ccb->ccb_dmamap_xfer);
193:
194: if (error) {
195: printf("%s: can't create ccb dmamap (%d)\n",
196: sc->sc_dv.dv_xname, error);
197: break;
198: }
199:
200: ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
201: SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
202: }
203:
204: /* Start firmware background tasks, if needed. */
205: if (startfw) {
206: if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
207: 0, 0, CAC_CCB_DATA_IN, NULL)) {
208: printf("%s: CAC_CMD_START_FIRMWARE failed\n",
209: sc->sc_dv.dv_xname);
210: return (-1);
211: }
212: }
213:
214: if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
215: CAC_CCB_DATA_IN, NULL)) {
216: printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
217: sc->sc_dv.dv_xname);
218: return (-1);
219: }
220:
221: if (!cinfo.num_drvs) {
222: printf("%s: no volumes defined\n", sc->sc_dv.dv_xname);
223: return (-1);
224: }
225:
226: sc->sc_nunits = cinfo.num_drvs;
227: sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info),
228: M_DEVBUF, M_NOWAIT);
229: if (sc->sc_dinfos == NULL) {
230: printf("%s: cannot allocate memory for drive_info\n",
231: sc->sc_dv.dv_xname);
232: return (-1);
233: }
234: bzero(sc->sc_dinfos, cinfo.num_drvs * sizeof(struct cac_drive_info));
235:
236: sc->sc_link.adapter_softc = sc;
237: sc->sc_link.adapter = &cac_switch;
238: sc->sc_link.adapter_target = cinfo.num_drvs;
239: sc->sc_link.adapter_buswidth = cinfo.num_drvs;
240: sc->sc_link.device = &cac_dev;
241: sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits;
242: if (sc->sc_link.openings < 4 )
243: sc->sc_link.openings = 4;
244:
245: bzero(&saa, sizeof(saa));
246: saa.saa_sc_link = &sc->sc_link;
247:
248: config_found(&sc->sc_dv, &saa, scsiprint);
249:
250: /* Set our `shutdownhook' before we start any device activity. */
251: if (cac_sdh == NULL)
252: cac_sdh = shutdownhook_establish(cac_shutdown, NULL);
253:
254: (*sc->sc_cl->cl_intr_enable)(sc, 1);
255:
256: return (0);
257: }
258:
259: int
260: cac_flush(sc)
261: struct cac_softc *sc;
262: {
263: u_int8_t buf[512];
264:
265: memset(buf, 0, sizeof(buf));
266: buf[0] = 1;
267: return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
268: CAC_CCB_DATA_OUT, NULL);
269: }
270:
271: /*
272: * Shut down all `cac' controllers.
273: */
274: void
275: cac_shutdown(void *cookie)
276: {
277: extern struct cfdriver cac_cd;
278: struct cac_softc *sc;
279: int i;
280:
281: for (i = 0; i < cac_cd.cd_ndevs; i++) {
282: if ((sc = (struct cac_softc *)device_lookup(&cac_cd, i)) == NULL)
283: continue;
284: cac_flush(sc);
285: }
286: }
287:
288: /*
289: * Handle an interrupt from the controller: process finished CCBs and
290: * dequeue any waiting CCBs.
291: */
292: int
293: cac_intr(v)
294: void *v;
295: {
296: struct cac_softc *sc = v;
297: struct cac_ccb *ccb;
298: int istat, ret = 0;
299:
300: if (!(istat = (sc->sc_cl->cl_intr_pending)(sc)))
301: return 0;
302:
303: if (istat & CAC_INTR_FIFO_NEMPTY)
304: while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) {
305: ret = 1;
306: cac_ccb_done(sc, ccb);
307: }
308: cac_ccb_start(sc, NULL);
309:
310: return (ret);
311: }
312:
313: /*
314: * Execute a [polled] command.
315: */
316: int
317: cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
318: int drive, int blkno, int flags, struct scsi_xfer *xs)
319: {
320: struct cac_ccb *ccb;
321: struct cac_sgb *sgb;
322: int i, rv, size, nsegs;
323:
324: #ifdef CAC_DEBUG
325: printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ",
326: command, drive, blkno, data, datasize, flags, xs);
327: #endif
328:
329: if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) {
330: printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
331: return (ENOMEM);
332: }
333:
334: if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
335: bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
336: (void *)data, datasize, NULL, BUS_DMA_NOWAIT);
337:
338: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
339: ccb->ccb_dmamap_xfer->dm_mapsize,
340: (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
341: BUS_DMASYNC_PREWRITE);
342:
343: sgb = ccb->ccb_seg;
344: nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
345: if (nsegs > CAC_SG_SIZE)
346: panic("cac_cmd: nsegs botch");
347:
348: size = 0;
349: for (i = 0; i < nsegs; i++, sgb++) {
350: size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
351: sgb->length =
352: htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
353: sgb->addr =
354: htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
355: }
356: } else {
357: size = datasize;
358: nsegs = 0;
359: }
360:
361: ccb->ccb_hdr.drive = drive;
362: ccb->ccb_hdr.priority = 0;
363: ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
364: sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
365:
366: ccb->ccb_req.next = 0;
367: ccb->ccb_req.command = command;
368: ccb->ccb_req.error = 0;
369: ccb->ccb_req.blkno = htole32(blkno);
370: ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
371: ccb->ccb_req.sgcount = nsegs;
372: ccb->ccb_req.reserved = 0;
373:
374: ccb->ccb_flags = flags;
375: ccb->ccb_datasize = size;
376: ccb->ccb_xs = xs;
377:
378: if (!xs || xs->flags & SCSI_POLL) {
379:
380: /* Synchronous commands musn't wait. */
381: if ((*sc->sc_cl->cl_fifo_full)(sc)) {
382: cac_ccb_free(sc, ccb);
383: rv = -1;
384: } else {
385: ccb->ccb_flags |= CAC_CCB_ACTIVE;
386: (*sc->sc_cl->cl_submit)(sc, ccb);
387: rv = cac_ccb_poll(sc, ccb, 2000);
388: }
389: } else
390: rv = cac_ccb_start(sc, ccb);
391:
392: return (rv);
393: }
394:
395: /*
396: * Wait for the specified CCB to complete. Must be called at splbio.
397: */
398: int
399: cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
400: {
401: struct cac_ccb *ccb;
402: int t = timo * 10;
403:
404: do {
405: for (; t--; DELAY(100))
406: if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
407: break;
408: if (t < 0) {
409: printf("%s: timeout\n", sc->sc_dv.dv_xname);
410: return (EBUSY);
411: }
412: cac_ccb_done(sc, ccb);
413: } while (ccb != wantccb);
414:
415: return (0);
416: }
417:
418: /*
419: * Enqueue the specified command (if any) and attempt to start all enqueued
420: * commands. Must be called at splbio.
421: */
422: int
423: cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
424: {
425: if (ccb != NULL)
426: SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
427:
428: while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL &&
429: !(*sc->sc_cl->cl_fifo_full)(sc)) {
430: SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
431: ccb->ccb_flags |= CAC_CCB_ACTIVE;
432: (*sc->sc_cl->cl_submit)(sc, ccb);
433: }
434:
435: return (0);
436: }
437:
438: /*
439: * Process a finished CCB.
440: */
441: void
442: cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
443: {
444: struct scsi_xfer *xs = ccb->ccb_xs;
445: int error = 0;
446:
447: if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) {
448: printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs);
449: if (xs) {
450: xs->error = XS_DRIVER_STUFFUP;
451: scsi_done(xs);
452: }
453: return;
454: }
455:
456: if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
457: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
458: ccb->ccb_dmamap_xfer->dm_mapsize,
459: ccb->ccb_flags & CAC_CCB_DATA_IN ?
460: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
461: bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
462: }
463:
464: if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
465: printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname);
466: if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
467: error = 1;
468: printf("%s: hard error\n", sc->sc_dv.dv_xname);
469: }
470: if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
471: error = 1;
472: printf("%s: invalid request\n", sc->sc_dv.dv_xname);
473: }
474:
475: cac_ccb_free(sc, ccb);
476: if (xs) {
477: if (error)
478: xs->error = XS_DRIVER_STUFFUP;
479: else
480: xs->resid = 0;
481:
482: xs->flags |= ITSDONE;
483: scsi_done(xs);
484: }
485: }
486:
487: /*
488: * Allocate a CCB.
489: */
490: struct cac_ccb *
491: cac_ccb_alloc(struct cac_softc *sc, int nosleep)
492: {
493: struct cac_ccb *ccb;
494:
495: if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL)
496: SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
497: else
498: ccb = NULL;
499: return (ccb);
500: }
501:
502: /*
503: * Put a CCB onto the freelist.
504: */
505: void
506: cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb)
507: {
508:
509: ccb->ccb_flags = 0;
510: SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
511: }
512:
513: int
514: cac_get_dinfo(sc, target)
515: struct cac_softc *sc;
516: int target;
517: {
518: if (sc->sc_dinfos[target].ncylinders)
519: return (0);
520:
521: if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target],
522: sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) {
523: printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
524: sc->sc_dv.dv_xname);
525: return (-1);
526: }
527:
528: return (0);
529: }
530:
531: void
532: cacminphys(bp)
533: struct buf *bp;
534: {
535: if (bp->b_bcount > CAC_MAX_XFER)
536: bp->b_bcount = CAC_MAX_XFER;
537: minphys(bp);
538: }
539:
540: void
541: cac_copy_internal_data(xs, v, size)
542: struct scsi_xfer *xs;
543: void *v;
544: size_t size;
545: {
546: size_t copy_cnt;
547:
548: if (!xs->datalen)
549: printf("uio move is not yet supported\n");
550: else {
551: copy_cnt = MIN(size, xs->datalen);
552: bcopy(v, xs->data, copy_cnt);
553: }
554: }
555:
556: int
557: cac_scsi_cmd(xs)
558: struct scsi_xfer *xs;
559: {
560: struct scsi_link *link = xs->sc_link;
561: struct cac_softc *sc = link->adapter_softc;
562: struct cac_drive_info *dinfo;
563: struct scsi_inquiry_data inq;
564: struct scsi_sense_data sd;
565: struct scsi_read_cap_data rcd;
566: u_int8_t target = link->target;
567: u_int32_t blockno, blockcnt, size;
568: struct scsi_rw *rw;
569: struct scsi_rw_big *rwb;
570: int op, flags, s, error, poll;
571: const char *p;
572:
573: if (target >= sc->sc_nunits || link->lun != 0) {
574: xs->error = XS_DRIVER_STUFFUP;
575: return (COMPLETE);
576: }
577:
578: s = splbio();
579: xs->error = XS_NOERROR;
580: xs->free_list.le_next = NULL;
581: dinfo = &sc->sc_dinfos[target];
582:
583: switch (xs->cmd->opcode) {
584: case TEST_UNIT_READY:
585: case START_STOP:
586: #if 0
587: case VERIFY:
588: #endif
589: break;
590:
591: case REQUEST_SENSE:
592: bzero(&sd, sizeof sd);
593: sd.error_code = 0x70;
594: sd.segment = 0;
595: sd.flags = SKEY_NO_SENSE;
596: *(u_int32_t*)sd.info = htole32(0);
597: sd.extra_len = 0;
598: cac_copy_internal_data(xs, &sd, sizeof sd);
599: break;
600:
601: case INQUIRY:
602: if (cac_get_dinfo(sc, target)) {
603: xs->error = XS_DRIVER_STUFFUP;
604: break;
605: }
606: bzero(&inq, sizeof inq);
607: inq.device = T_DIRECT;
608: inq.dev_qual2 = 0;
609: inq.version = 2;
610: inq.response_format = 2;
611: inq.additional_length = 32;
612: strlcpy(inq.vendor, "Compaq ", sizeof inq.vendor);
613: switch (CAC_GET1(dinfo->mirror)) {
614: case 0: p = "RAID0"; break;
615: case 1: p = "RAID4"; break;
616: case 2: p = "RAID1"; break;
617: case 3: p = "RAID5"; break;
618: default:p = "<UNK>"; break;
619: }
620: snprintf(inq.product, sizeof inq.product, "%s vol #%02d",
621: p, target);
622: strlcpy(inq.revision, " ", sizeof inq.revision);
623: cac_copy_internal_data(xs, &inq, sizeof inq);
624: break;
625:
626: case READ_CAPACITY:
627: if (cac_get_dinfo(sc, target)) {
628: xs->error = XS_DRIVER_STUFFUP;
629: break;
630: }
631: bzero(&rcd, sizeof rcd);
632: _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
633: CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
634: _lto4b(CAC_SECTOR_SIZE, rcd.length);
635: cac_copy_internal_data(xs, &rcd, sizeof rcd);
636: break;
637:
638: case PREVENT_ALLOW:
639: break;
640:
641: case SYNCHRONIZE_CACHE:
642: if (cac_flush(sc))
643: xs->error = XS_DRIVER_STUFFUP;
644: break;
645:
646: case READ_COMMAND:
647: case READ_BIG:
648: case WRITE_COMMAND:
649: case WRITE_BIG:
650:
651: flags = 0;
652: /* A read or write operation. */
653: if (xs->cmdlen == 6) {
654: rw = (struct scsi_rw *)xs->cmd;
655: blockno = _3btol(rw->addr) &
656: (SRW_TOPADDR << 16 | 0xffff);
657: blockcnt = rw->length ? rw->length : 0x100;
658: } else {
659: rwb = (struct scsi_rw_big *)xs->cmd;
660: blockno = _4btol(rwb->addr);
661: blockcnt = _2btol(rwb->length);
662: }
663: size = CAC_GET2(dinfo->ncylinders) *
664: CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
665: if (blockno >= size || blockno + blockcnt > size) {
666: printf("%s: out of bounds %u-%u >= %u\n",
667: sc->sc_dv.dv_xname, blockno, blockcnt, size);
668: xs->error = XS_DRIVER_STUFFUP;
669: scsi_done(xs);
670: break;
671: }
672:
673: switch (xs->cmd->opcode) {
674: case READ_COMMAND:
675: case READ_BIG:
676: op = CAC_CMD_READ;
677: flags = CAC_CCB_DATA_IN;
678: break;
679: case WRITE_COMMAND:
680: case WRITE_BIG:
681: op = CAC_CMD_WRITE;
682: flags = CAC_CCB_DATA_OUT;
683: break;
684: }
685:
686: poll = xs->flags & SCSI_POLL;
687: if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
688: target, blockno, flags, xs))) {
689:
690: if (error == ENOMEM) {
691: splx(s);
692: return (TRY_AGAIN_LATER);
693: } else if (poll) {
694: splx(s);
695: return (TRY_AGAIN_LATER);
696: } else {
697: xs->error = XS_DRIVER_STUFFUP;
698: scsi_done(xs);
699: break;
700: }
701: }
702:
703: splx(s);
704:
705: if (poll)
706: return (COMPLETE);
707: else
708: return (SUCCESSFULLY_QUEUED);
709:
710: default:
711: SC_DEBUG(link, SDEV_DB1, ("unsupported scsi command %#x "
712: "tgt %d ", xs->cmd->opcode, target));
713: xs->error = XS_DRIVER_STUFFUP;
714: }
715: splx(s);
716:
717: return (COMPLETE);
718: }
719:
720: /*
721: * Board specific linkage shared between multiple bus types.
722: */
723:
724: int
725: cac_l0_fifo_full(struct cac_softc *sc)
726: {
727:
728: return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
729: }
730:
731: void
732: cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
733: {
734: #ifdef CAC_DEBUG
735: printf("submit-%x ", ccb->ccb_paddr);
736: #endif
737: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
738: sc->sc_dmamap->dm_mapsize,
739: BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
740: cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
741: }
742:
743: struct cac_ccb *
744: cac_l0_completed(sc)
745: struct cac_softc *sc;
746: {
747: struct cac_ccb *ccb;
748: paddr_t off;
749:
750: if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
751: return NULL;
752: #ifdef CAC_DEBUG
753: printf("compl-%x ", off);
754: #endif
755: if (off & 3 && ccb->ccb_req.error == 0)
756: ccb->ccb_req.error = CAC_RET_CMD_INVALID;
757:
758: off = (off & ~3) - sc->sc_ccbs_paddr;
759: ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
760:
761: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
762: sc->sc_dmamap->dm_mapsize,
763: BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
764:
765: return (ccb);
766: }
767:
768: int
769: cac_l0_intr_pending(struct cac_softc *sc)
770: {
771:
772: return (cac_inl(sc, CAC_REG_INTR_PENDING));
773: }
774:
775: void
776: cac_l0_intr_enable(struct cac_softc *sc, int state)
777: {
778:
779: cac_outl(sc, CAC_REG_INTR_MASK,
780: state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
781: }
CVSweb