This source file includes following definitions.
- cac_init
- cac_flush
- cac_shutdown
- cac_intr
- cac_cmd
- cac_ccb_poll
- cac_ccb_start
- cac_ccb_done
- cac_ccb_alloc
- cac_ccb_free
- cac_get_dinfo
- cacminphys
- cac_copy_internal_data
- cac_scsi_cmd
- cac_l0_fifo_full
- cac_l0_submit
- cac_l0_completed
- cac_l0_intr_pending
- cac_l0_intr_enable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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;
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
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
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
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
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
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
290
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
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
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
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
420
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
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
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
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
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
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 }