|
|
1.1 root 1: /*
2: * Adaptech 1542 SCSI driver for 386bsd
3: *
4: * Pace Willisson [email protected] March 28, 1992
5: *
6: * Placed in the public domain with NO WARRANTIES, not even the
7: * implied warranties for MERCHANTABILITY or FITNESS FOR A
8: * PARTICULAR PURPOSE.
9: *
10: *
11: * This is a very early version - use with care.
12: *
13: * Here is the config info:
14: *
15: * controller as0 at isa? port 0x330 bio irq 11 drq 5 vector asintr
16: * disk dk6 at as0 drive 0
17: *
18: * Also, don't forget to update sys/i386/conf/files.i386.
19: *
20: * So far, used with:
21: *
22: * CDC WREN 5 600 Megabyte magnetic disk
23: * EXABYTE EXB-8200 8mm tape drive
24: * SONY CDU-541 cdrom
25: *
26: * The the tape stuff still needs a lot of working concerning
27: * file marks, end of tape handling and rewinding, but I have
28: * extracted tar tapes to a file system mounted on the CDC disk.
29: *
30: * minor number bits:
31: *
32: * 7 6 5 4 3 2 1 0
33: * +-----+ partition number
34: * +-----+ scsi target number
35: * +--+ unused (should be 0)
36: *
37: * For tape drives, set the partition number to 0 for regular,
38: * 1 for no rewind.
39: *
40: * Only supports LUN 0.
41: *
42: * To use with a read-write disk, first use diskpart to create
43: * a disktab entry, then use disklabel. Since I don't have
44: * the boot programs done yet, I faked it with:
45: *
46: * # cd /usr/mdec
47: * # cp wdboot asboot
48: * # cp bootwd bootas
49: *
50: * Now you can run disklabel, newfs, etc.
51: *
52: * Please send patches and names other perpherials that work to
53: * [email protected]. If you have trouble that you can't fix, please
54: * wait for the next release before contacting me.
55: */
56:
57: #include "as.h"
58: #if NAS > 0
59:
60: #include "param.h"
61: #include "dkbad.h"
62: #include "systm.h"
63: #include "conf.h"
64: #include "file.h"
65: #include "stat.h"
66: #include "ioctl.h"
67: #include "disklabel.h"
68: #include "buf.h"
69: #include "uio.h"
70: #include "i386/isa/isa_device.h"
71: #include "i386/isa/icu.h"
72: #include "syslog.h"
73: #include "vm/vm.h"
74: #include "kernel.h"
75:
76: #include "asreg.h"
77:
78: int asstrategy ();
79: int asabort ();
80: extern int hz;
81:
82: int asverbose = 0;
83:
84:
85: /* target id 7 is the controller itself */
86: #define NTARGETS 7
87:
88: struct mailbox_entry mailboxes[NTARGETS * 2] = {0};
89:
90: #define b_cylin b_resid /* fake cylinder number for disksort */
91:
92: /* maximum scatter list size for Adaptech controller */
93: #define NSCATTER 17
94:
95: /* this array must reside in contiguous physical memory */
96: struct asinfo {
97: dev_t dev;
98: struct buf requests;
99: struct mailbox_entry *mailbox;
100: int active;
101: struct ccb ccb;
102: unsigned int ccb_phys;
103: char scatter_list[NSCATTER * 6];
104:
105: struct disklabel label;
106: struct dos_partition dospart[NDOSPART];
107: int have_label;
108:
109: int scsi_lock;
110: struct buf *scsi_bp;
111: int scsi_cdb_len;
112: unsigned char scsi_cdb[MAXCDB];
113:
114: int tape; /* sequential */
115: int disk; /* nonsequential */
116: int read_only; /* CDROM */
117: int removable; /* unsupported and tested */
118: char vendor[9];
119: char model[17];
120: char revision[5];
121: int bs; /* device block size */
122:
123: int open_lock;
124: int open;
125: int units_open;
126:
127: int wlabel;
128:
129: int retry_count;
130: int start_time;
131: int restart_pending;
132:
133: } asinfo[NTARGETS] = {0};
134:
135: #define dev_part(dev) (minor (dev) & 7)
136: #define dev_target(dev) ((minor (dev) >> 3) & 7)
137: #define dev_rewind(dev) ((minor (dev) & 1) == 0)
138:
139: #define makeasdev(major, target, part) \
140: makedev ((major), ((target) << 3) | (part))
141:
142: int as_port;
143:
144: int asprobe(struct isa_device *), asattach(struct isa_device *),
145: asintr(dev_t);
146:
147: struct isa_driver asdriver = {
148: asprobe, asattach, "as",
149: };
150:
151: int
152: asprobe (struct isa_device *dvp)
153: {
154: int val;
155:
156: as_port = dvp->id_iobase;
157:
158: outb (as_port + AS_CONTROL, AS_CONTROL_SRST);
159: DELAY (30000);
160: val = inb (as_port + AS_STATUS);
161:
162: if (val == (AS_STATUS_INIT | AS_STATUS_IDLE))
163: return (1);
164: as_port = 0;
165: return (0);
166: }
167:
168: asattach (struct isa_device *dvp)
169: {
170: int i;
171: unsigned int physaddr;
172: int val;
173: int s;
174:
175: for (i = 0; i < NTARGETS; i++) {
176: asinfo[i].mailbox = &mailboxes[i];
177: asinfo[i].ccb_phys = vtophys (&asinfo[i].ccb);
178: }
179:
180: isa_dmacascade(dvp->id_drq);
181:
182: physaddr = vtophys (mailboxes);
183:
184: s = splbio ();
185: if (as_put_byte (AS_CMD_MAILBOX_INIT) < 0
186: || as_put_byte (NTARGETS) < 0
187: || as_put_byte (physaddr >> 16) < 0
188: || as_put_byte (physaddr >> 8) < 0
189: || as_put_byte (physaddr) < 0) {
190: splx (s);
191: return (EIO);
192: }
193: splx (s);
194: DELAY (300);
195: val = inb (as_port + AS_STATUS);
196:
197: if (val & AS_STATUS_INIT)
198: printf ("as: mailbox init error: 0x%x\n", val);
199: }
200:
201: int
202: ascmd (as, bp, direction, count, retrycount)
203: struct asinfo *as;
204: struct buf *bp;
205: int direction;
206: int count;
207: int retrycount;
208: {
209: int err;
210:
211: do {
212: if (asverbose)
213: printf ("ascmd ");
214: bp->b_bcount = count;
215: bp->b_error = 0;
216: bp->b_flags &= ~(B_READ | B_ERROR | B_DONE);
217: if (direction == B_READ)
218: bp->b_flags |= B_READ;
219:
220: bp->b_dev = as->dev;
221: bp->b_blkno = 0;
222:
223: as->scsi_bp = bp;
224: /* scsi_cdb, scsi_cdb_len set up by caller */
225:
226: asstrategy (bp);
227: err = biowait (bp);
228: as->scsi_bp = NULL;
229:
230: } while (err && --retrycount);
231:
232: return (err);
233: }
234:
235: asstring (dest, src, size)
236: char *dest;
237: char *src;
238: int size;
239: {
240: size--;
241: bcopy (src, dest, size);
242: while (size > 0 && dest[size - 1] == ' ')
243: size--;
244: dest[size] = 0;
245: }
246:
247: asopen (dev, flag)
248: dev_t dev;
249: int flag;
250: {
251: struct asinfo *as;
252: unsigned int physaddr;
253: struct buf *bp = NULL;
254: int retry;
255: unsigned char *cdb;
256: char *p, *q;
257: int n;
258: int error;
259: char vendor[9];
260: char model[17];
261: int disksize;
262:
263: if (as_port == 0 || dev_target (dev) >= NTARGETS)
264: return (ENXIO);
265:
266: as = &asinfo[dev_target (dev)];
267: as->dev = dev;
268:
269: while (as->open_lock)
270: if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsiopen", 0))
271: return (error);
272:
273: if (as->open) {
274: if (as->tape)
275: return (EBUSY);
276:
277: if (as->have_label == 0 && dev_part (dev) != 3)
278: return (ENXIO);
279:
280: as->units_open |= 1 << dev_part (dev);
281: return (0);
282: }
283:
284: as->open_lock = 1;
285:
286: /* it seems like we might have to block here in case someone
287: * opens the device just after someone else closes
288: */
289: while (as->scsi_lock)
290: if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsicmd", 0))
291: return (error);
292:
293: as->scsi_lock = 1;
294:
295: error = EIO;
296:
297: as->have_label = 0;
298: as->tape = 0;
299: as->disk = 0;
300: as->read_only = 0;
301: as->removable = 0;
302: bcopy(as->vendor, vendor, sizeof(vendor));
303: bcopy(as->model, model, sizeof(model));
304: as->vendor[0] = 0;
305: as->model[0] = 0;
306: as->revision[0] = 0;
307:
308: bp = geteblk (DEV_BSIZE);
309:
310: if (asverbose) {
311: printf ("openbuf = 0x%x phys 0x%x\n",
312: bp->b_un.b_addr, vtophys (bp->b_un.b_addr));
313: printf ("mailboxes = 0x%x\n", mailboxes);
314: }
315:
316: /* first, find out if a device is present, and just what it is */
317: as->scsi_cdb_len = 6;
318: cdb = as->scsi_cdb;
319: bzero (cdb, 6);
320: cdb[0] = 0x12; /* INQUIRY */
321: cdb[4] = 255; /* allocation length */
322: if (error = ascmd (as, bp, B_READ, DEV_BSIZE, 2))
323: /* does not respond to inquiry, obviously not CCS, give up */
324: goto done;
325:
326:
327: /* blather on console about it */
328: p = bp->b_un.b_addr;
329: if (asverbose) {
330: printf ("inquiry: ");
331: for (n = 0; n < 20; n++)
332: printf ("%x ", p[n] & 0xff);
333: printf ("\n");
334: for (n = 0; n < 40; n++) {
335: if (p[n] >= ' ' && p[n] < 0177)
336: printf ("%c", p[n]);
337: else
338: printf (".");
339: }
340: printf ("\n");
341: }
342:
343: switch (p[0]) {
344: case 0: /* normal disk */
345: case 4: /* write once disk */
346: as->disk = 1;
347: break;
348: case 5: /* read only disk */
349: as->read_only = 1;
350: as->disk = 1;
351: break;
352: case 1: /* tape */
353: as->tape = 1;
354: break;
355: case 0x7f:
356: printf ("logical unit not present\n");
357: goto done;
358: default:
359: printf ("unknown peripheral device type: 0x%x\n", p[0]);
360: goto done;
361: }
362:
363: as->removable = (p[1] & 0x80) ? 1 : 0;
364:
365: n = p[4] & 0xff;
366: if (n >= 31) {
367: asstring (as->vendor, p + 8, sizeof as->vendor);
368: asstring (as->model, p + 16, sizeof as->model);
369: asstring (as->revision, p + 32, sizeof as->revision);
370: }
371:
372: if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
373: bcmp(as->model,model, sizeof(model)) != 0) {
374: printf("as%d: attached tgt %d <%s %s %s> ", 0, dev_target(dev),
375: as->vendor, as->model, as->revision);
376: if (as->read_only) printf("readonly ");
377: if (!as->removable) printf("winchester ");
378: if (as->tape) printf("tape ");
379: if (as->disk) printf("disk ");
380: printf("\n");
381: }
382:
383: /* probe for desired block size */
384:
385: /* assume default of 512, except if CDROM (2048) */
386: if (as->read_only)
387: as->bs = 2048;
388: else
389: as->bs = 512;
390:
391: bzero(cdb, 6);
392: cdb[0] = 0x1A; /* SCSI_MDSENSE */
393: cdb[4] = 255;
394: if (as->tape && ascmd (as, bp, B_READ, 12, 2) == 0) {
395: int minblk, maxblk;
396:
397: #ifdef notdef
398: /* blather about device more */
399: if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
400: bcmp(as->model,model, sizeof(model)) != 0) {
401: p = bp->b_un.b_addr;
402: printf("as%d: data len %d medium %d speed/bufmode 0x%x desc len %d\n",
403: dev_target(dev), p[0], p[1], p[2], p[3]);
404: printf("as%d: density %d nblocks %d block len %d\n",
405: dev_target(dev), p[4],
406: (long)p[5]*65536+p[6]*256+p[7],
407: (long)p[9]*65536+p[10]*256+p[11]);
408: }
409: #endif
410:
411: /* obtain possible block sizes */
412: bzero(cdb, 6);
413: cdb[0] = 0x05; /* SCSI_RDLIMITS; */
414: if (ascmd (as, bp, B_READ, 12, 2) == 0) {
415: p = bp->b_un.b_addr;
416: minblk = p[4]*256+p[5];
417: maxblk = p[1]*65536+p[2]*256+p[3];
418: #ifdef notdef
419: if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 ||
420: bcmp(as->model,model, sizeof(model)) != 0) {
421: printf("as%d: limits: min block len %ld max block len %ld\n",
422: dev_target(dev), minblk, maxblk);
423: }
424: #endif
425: if ( minblk == maxblk )
426: as->bs = minblk;
427: else if (as->tape)
428: as->bs = 1;
429: }
430: }
431:
432: if (as->tape && dev_part(dev)) {
433: error = EIO;
434: goto done;
435: }
436:
437: as->scsi_cdb_len = 10;
438: bzero(cdb, 10);
439: cdb[0] = 0x25; /* SCSI_READCAPACITY */
440: disksize = 0;
441: if (as->disk && ascmd (as, bp, B_READ, 12, 2) == 0) {
442: p = bp->b_un.b_addr;
443: disksize = ntohl(*(long *)p);
444: as->bs = ntohl(*(long *)(p+4));
445:
446: }
447:
448: if(asverbose)
449: printf("block size %d disksize %d ", as->bs, disksize);
450:
451:
452: /* for standard disk, negotiate block size */
453: if (as->read_only == 0 && as->disk) {
454: /* do mode select to set the logical block size */
455: as->scsi_cdb_len = 6;
456: cdb = as->scsi_cdb;
457: bzero (cdb, 6);
458: cdb[0] = 0x15; /* MODE SELECT */
459: cdb[4] = 12; /* parameter list length */
460:
461: p = bp->b_un.b_addr;
462: bzero (p, 12);
463: p[3] = 8; /* block descriptor length */
464: n = as->bs == 1 ? 0 : as->bs;
465: p[9] = n >> 16;
466: p[10] = n >> 8;
467: p[11] = n;
468:
469: (void) ascmd (as, bp, B_WRITE, 12, 2);
470: }
471:
472: /* device online and ready? */
473: as->scsi_cdb_len = 6;
474: bzero(cdb, 6);
475: cdb[0] = 0x00; /* SCSI_UNITRDY */
476: if (error = ascmd (as, bp, B_READ, 12, 2)) {
477: printf("as%d: drive not online\n", dev_target(dev));
478: goto done;
479: }
480:
481: if (as->disk && as->read_only == 0) {
482: /* read disk label */
483: bzero ((caddr_t)&as->label, sizeof as->label);
484: as->label.d_secsize = as->bs;
485: as->label.d_secpercyl = 64*32;
486: as->label.d_type = DTYPE_SCSI;
487:
488:
489: /* read label using "d" partition */
490: if ((p = readdisklabel (
491: makeasdev (major (dev), dev_target (dev), 3),
492: asstrategy, &as->label, as->dospart, 0, 0)) == NULL){
493: as->have_label = 1;
494: } else {
495: if (disksize) {
496: as->label.d_subtype = DSTYPE_GEOMETRY;
497: as->label.d_npartitions = 3;
498: /* partition 0 holds bios, partition 1 ESDI */
499: as->label.d_partitions[2].p_size = disksize;
500: as->label.d_partitions[2].p_offset = 0;
501: }
502: if (asverbose || dev_part (dev) != 3)
503: printf ("error reading label: %s\n", p);
504: if (dev_part (dev) != 3) {
505: error = EINVAL;
506: goto done;
507: }
508: }
509: }
510:
511: /* may want to set logical block size here ? */
512: error = 0;
513:
514: done:
515: if (bp) {
516: bp->b_flags |= B_INVAL | B_AGE;
517: brelse (bp);
518: }
519:
520: if (error == 0)
521: as->open = 1;
522:
523: as->open_lock = 0;
524: as->scsi_lock = 0;
525: wakeup (as);
526:
527: return (error);
528: }
529:
530: asclose (dev, flag)
531: dev_t dev;
532: {
533: struct asinfo *as;
534: int error = 0;
535: unsigned char *cdb;
536: struct buf *bp;
537: int n;
538:
539: as = &asinfo[dev_target (dev)];
540:
541: while (as->open_lock)
542: if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsiclose", 0))
543: return (error);
544:
545: as->open_lock = 1;
546:
547: if (as->tape) {
548: while (as->scsi_lock)
549: if (error = tsleep ((caddr_t)as, PZERO|PCATCH,
550: "scsicmd", 0))
551: return (error);
552:
553: as->scsi_lock = 1;
554:
555: bp = geteblk (DEV_BSIZE);
556:
557: if (0 && (flag & FWRITE) != 0) {
558: /* presume user will use tape again */
559: as->scsi_cdb_len = 6;
560: cdb = as->scsi_cdb;
561: bzero (cdb, 6);
562: cdb[0] = 0x10; /* write filemarks */
563: cdb[4] = 1; /* one of them */
564: error = ascmd (as, bp, B_READ, 0, 1);
565: }
566: if (dev_rewind (dev) || error) {
567: if ( error == 0 && (flag & FWRITE) != 0) {
568: /* presumption error correction */
569: as->scsi_cdb_len = 6;
570: cdb = as->scsi_cdb;
571: bzero (cdb, 6);
572: cdb[0] = 0x10; /* write filemarks */
573: cdb[4] = 1; /* one of them */
574: error |= ascmd (as, bp, B_READ, 0, 1);
575: }
576: as->scsi_cdb_len = 6;
577: cdb = as->scsi_cdb;
578: bzero (cdb, 6);
579: cdb[0] = 0x1; /* rewind */
580: cdb[1] = 1; /* don't wait until done */
581: error |= ascmd (as, bp, B_READ, 0, 1);
582: }
583: #ifdef notdef
584: } else {
585: cdb[0] = 0x11; /* backspace */
586: cdb[1] = 1; /* look at filemarks (instead of blocks) */
587: n = -1;
588: cdb[2] = n >> 16;
589: cdb[3] = n >> 8;
590: cdb[4] = n;
591: error = ascmd (as, bp, B_READ, 0, 1);
592: }
593: #endif
594:
595: bp->b_flags |= B_INVAL | B_AGE;
596: brelse (bp);
597:
598: as->scsi_lock = 0;
599: }
600:
601: as->units_open &= ~(1 << dev_part (dev));
602:
603: if (as->units_open == 0)
604: as->open = 0;
605:
606: as->open_lock = 0;
607:
608: wakeup (as);
609:
610: return (error);
611: }
612:
613: int
614: asioctl (dev, cmd, addr, flag)
615: dev_t dev;
616: int cmd;
617: caddr_t addr;
618: int flag;
619: {
620: struct scsicmd *cmdp;
621: struct asinfo *as;
622: int ccblen;
623: struct buf *bp;
624: int error = 0;
625: int direction;
626: struct disklabel *dl;
627: int old_wlabel;
628:
629: as = &asinfo[dev_target (dev)];
630:
631: switch (cmd) {
632: case DIOCGDINFO:
633: *(struct disklabel *)addr = as->label;
634: break;
635:
636: case DIOCSDINFO:
637: if ((flag & FWRITE) == 0) {
638: error = EBADF;
639: break;
640: }
641: dl = (struct disklabel *)addr;
642: if (error = setdisklabel(&as->label, dl, 0, as->dospart))
643: break;
644: as->have_label = 1;
645: break;
646:
647: case DIOCWLABEL:
648: if ((flag & FWRITE) == 0) {
649: error = EBADF;
650: break;
651: }
652: as->wlabel = *(int *)addr;
653: break;
654:
655: case DIOCWDINFO:
656: if ((flag & FWRITE) == 0) {
657: error = EBADF;
658: break;
659: }
660:
661: dl = (struct disklabel *)addr;
662:
663: if (error = setdisklabel (&as->label, dl, 0, as->dospart))
664: break;
665:
666: as->have_label = 1;
667:
668: old_wlabel = as->wlabel;
669: as->wlabel = 1;
670: error = writedisklabel(dev, asstrategy, &as->label,
671: as->dospart);
672: as->wlabel = old_wlabel;
673: break;
674:
675: case SCSICMD:
676: cmdp = (struct scsicmd *)addr;
677:
678: /* limited by max sizeof of geteblk */
679: if (cmdp->datalen >= 8192
680: || cmdp->cdblen >= MAXCDB) {
681: error = EINVAL;
682: break;
683: }
684:
685: ccblen = cmdp->ccblen;
686: if (ccblen > sizeof (struct ccb))
687: ccblen = sizeof (struct ccb);
688:
689: while (as->scsi_lock)
690: if (error = tsleep ((caddr_t)as, PZERO|PCATCH,
691: "scsicmd", 0))
692: break;
693:
694: as->scsi_lock = 1;
695:
696: bp = geteblk (cmdp->datalen);
697:
698: as->scsi_cdb_len = cmdp->cdblen;
699: if (error = copyin (cmdp->cdb, as->scsi_cdb, cmdp->cdblen))
700: goto done;
701:
702: direction = cmdp->readflag ? B_READ : B_WRITE;
703:
704: if (direction == B_WRITE)
705: if (error = copyin (cmdp->data,
706: bp->b_un.b_addr, cmdp->datalen))
707: goto done;
708:
709: ascmd (as, bp, direction, cmdp->datalen, 1);
710:
711: copyout (&as->ccb, cmdp->ccb, ccblen);
712: if (direction == B_READ)
713: copyout (bp->b_un.b_addr, cmdp->data, cmdp->datalen);
714: done:
715: bp->b_flags |= B_INVAL | B_AGE;
716: brelse (bp);
717: as->scsi_lock = 0;
718: wakeup (as);
719: break;
720: default:
721: error = ENOTTY;
722: break;
723: }
724: return (error);
725: }
726:
727: int
728: asstrategy (bp)
729: struct buf *bp;
730: {
731: struct asinfo *as;
732: int s;
733:
734: if (asverbose)
735: printf ("asstrategy %d %d ", bp->b_blkno, bp->b_bcount);
736: s = splbio ();
737:
738: as = &asinfo[dev_target (bp->b_dev)];
739:
740: if (as->tape) {
741: bp->av_forw = NULL;
742: if (as->requests.b_actf)
743: as->requests.b_actl->av_forw = bp;
744: else
745: as->requests.b_actf = bp;
746: as->requests.b_actl = bp;
747: } else {
748: if (bp != as->scsi_bp
749: && as->have_label == 0
750: && dev_part (bp->b_dev) != 3)
751: goto bad;
752:
753: bp->b_cylin = bp->b_blkno;
754: disksort (&as->requests, bp);
755: }
756:
757: if (as->active == 0)
758: asstart (as);
759:
760: splx (s);
761: return;
762:
763: bad:
764: bp->b_flags |= B_ERROR;
765: biodone (bp);
766: }
767:
768: asrestart (as)
769: struct asinfo *as;
770: {
771: int s;
772: s = splbio ();
773: as->restart_pending = 0;
774: as->retry_count++;
775: asstart (as);
776: splx (s);
777: }
778:
779: asstart (as)
780: struct asinfo *as;
781: {
782: struct buf *bp;
783: int blknum;
784: unsigned int physaddr;
785: struct ccb *ccb;
786: unsigned char *cdb;
787: int target;
788: char *p;
789: int n;
790: char *sp;
791: int nscatter;
792: int thistime;
793: int nbytes;
794: struct partition *part;
795: int blkno;
796: int nblocks;
797: int total;
798: int bs = as->bs;
799:
800:
801: if (as->restart_pending) {
802: as->restart_pending = 0;
803: untimeout (asrestart, as);
804: }
805:
806: again:
807: if ((bp = as->requests.b_actf) == NULL)
808: return;
809:
810: bp->b_error = 0;
811:
812: if (asverbose)
813: printf ("asstart %x ", bp);
814:
815: if (as->mailbox->cmd != 0) {
816: /* this can't happen, unless the card flakes */
817: printf ("asstart: mailbox not available\n");
818: bp->b_error = EIO;
819: goto bad;
820: }
821:
822: if (as->retry_count == 0) {
823: as->start_time = time.tv_sec;
824: } else {
825: if (time.tv_sec - as->start_time > 60) {
826: printf ("as: command timed out\n");
827: bp->b_error = EIO;
828: goto done;
829: }
830: }
831:
832: if (bp != as->scsi_bp) {
833: if (bp->b_bcount == 0)
834: goto done;
835:
836: if ((bp->b_bcount % bs) != 0) {
837: printf("as: partial block read\n");
838: bp->b_error = EIO;
839: goto bad;
840: }
841: }
842:
843: if (bp != as->scsi_bp) {
844:
845: blkno = bp->b_blkno;
846: nblocks = bp->b_bcount / bs;
847:
848: if (as->have_label && dev_part(bp->b_dev) != 3) {
849: part = &as->label.d_partitions[dev_part (bp->b_dev)];
850:
851: if (blkno > part->p_size) {
852: bp->b_error = EINVAL;
853: goto bad;
854: }
855: if (blkno == part->p_size) {
856: bp->b_resid = bp->b_bcount;
857: goto done;
858: }
859:
860: if (blkno + nblocks >= part->p_size)
861: nblocks = part->p_size - blkno;
862:
863: blkno += part->p_offset;
864: } else
865: blkno = (blkno * DEV_BSIZE)/bs;
866: if(asverbose)
867: printf("trans %d ", blkno);
868: if (nblocks > 255)
869: nblocks = 255;
870: total = nblocks * bs;
871: if(asverbose)
872: printf("total %d nblocks %d ", total, nblocks);
873: /*bp->b_bcount = total; /* XXX partial tape block read - wrong */
874: } else {
875: #ifdef nomore
876: if (as->fixed == 0) {
877: total = bp->b_bcount;
878: } else {
879: total = bp->b_bcount;
880: blkno = bp->b_blkno;
881: nblocks = bp->b_bcount / as->fixed;
882: }
883: #else
884: total = bp->b_bcount;
885: #endif
886: }
887:
888: p = bp->b_un.b_addr;
889: n = 0;
890: sp = as->scatter_list;
891: nscatter = 0;
892: while (n < total && nscatter < NSCATTER) {
893: thistime = page_size - ((vm_offset_t)p - trunc_page (p));
894:
895: if (n + thistime > total)
896: thistime = total - n;
897:
898: physaddr = vtophys (p);
899:
900: if (asverbose)
901: printf ("%d bytes to %x (%x)\n",
902: thistime, p, physaddr);
903: sp[0] = thistime >> 16;
904: sp[1] = thistime >> 8;
905: sp[2] = thistime;
906: sp[3] = physaddr >> 16;
907: sp[4] = physaddr >> 8;
908: sp[5] = physaddr;
909:
910: p += thistime;
911: n += thistime;
912: sp += 6;
913: nscatter++;
914: }
915:
916: if (nscatter == NSCATTER) {
917: printf("out of range, cannot happen?");
918: bp->b_error = ENXIO;
919: goto bad;
920: }
921:
922: ccb = &as->ccb;
923:
924: /* this only needed to make debugging easier */
925: bzero ((caddr_t)ccb, sizeof *ccb);
926:
927: if (nscatter)
928: ccb->ccb_opcode = 4; /* scatter cmd, return resid */
929: else
930: ccb->ccb_opcode = 3;
931: target = dev_target (bp->b_dev);
932: ccb->ccb_addr_and_control = target << 5;
933: if (bp->b_bcount != 0)
934: ccb->ccb_addr_and_control |= (bp->b_flags & B_READ) ? 8 : 0x10;
935: else
936: ccb->ccb_addr_and_control |= 0x18;
937:
938: nbytes = nscatter * 6;
939: ccb->ccb_data_len_msb = nbytes >> 16;
940: ccb->ccb_data_len_mid = nbytes >> 8;
941: ccb->ccb_data_len_lsb = nbytes;
942:
943: ccb->ccb_requst_sense_allocation_len = MAXSENSE;
944:
945: physaddr = vtophys (as->scatter_list);
946: ccb->ccb_data_ptr_msb = physaddr >> 16;
947: ccb->ccb_data_ptr_mid = physaddr >> 8;
948: ccb->ccb_data_ptr_lsb = physaddr;
949:
950: ccb->ccb_link_msb = 0;
951: ccb->ccb_link_mid = 0;
952: ccb->ccb_link_lsb = 0;
953: ccb->ccb_link_id = 0;
954: ccb->ccb_host_status = 0;
955: ccb->ccb_target_status = 0;
956: ccb->ccb_zero1 = 0;
957: ccb->ccb_zero2 = 0;
958:
959: cdb = ccb->ccb_cdb;
960: if (bp == as->scsi_bp) {
961: ccb->ccb_scsi_command_len = as->scsi_cdb_len;
962: bcopy (as->scsi_cdb, cdb, as->scsi_cdb_len);
963: } else if (as->tape) {
964: ccb->ccb_scsi_command_len = 6;
965: cdb[0] = (bp->b_flags & B_READ) ? 8 : 0xa;
966: if (as->bs == 1) {
967: cdb[1] = 0; /* logical unit 0, variable block size */
968: cdb[2] = bp->b_bcount >> 16;
969: cdb[3] = bp->b_bcount >> 8;
970: cdb[4] = bp->b_bcount;
971: } else {
972: cdb[1] = 1; /* fixed block size */
973: cdb[2] = nblocks >> 16;
974: cdb[3] = nblocks >> 8;
975: cdb[4] = nblocks;
976: }
977: cdb[5] = 0; /* control byte (used in linking) */
978: } else {
979: ccb->ccb_scsi_command_len = 10;
980: cdb[0] = (bp->b_flags & B_READ) ? 0x28 : 0x2a;
981: cdb[1] = 0;
982: *(long *) (cdb+2) = htonl(blkno);
983: *(short *) (cdb+7) = htons(nblocks);
984: cdb[9] = 0; /* control byte (used in linking) */
985: }
986:
987: #ifdef notdef
988: if (asverbose) {
989: printf ("ccb: ");
990: for (n = 0; n < 48; n++)
991: printf ("%02x ", ((unsigned char *)ccb)[n]);
992: printf ("\n");
993: }
994: #endif
995:
996: physaddr = vtophys (ccb);
997: as->mailbox->msb = physaddr >> 16;
998: as->mailbox->mid = physaddr >> 8;
999: as->mailbox->lsb = physaddr;
1000: as->mailbox->cmd = 1;
1001:
1002: /* tell controller to look in its mailbox */
1003: as_put_byte (AS_CMD_START_SCSI_COMMAND);
1004: as->active = 1;
1005: timeout (asabort, as, hz * 60 * 2);
1006: return;
1007:
1008: bad:
1009: bp->b_flags |= B_ERROR;
1010: done:
1011: asdone (as, 0);
1012: goto again;
1013: }
1014:
1015: asabort (as)
1016: struct asinfo *as;
1017: {
1018: int s;
1019: int physaddr;
1020: struct buf *bp;
1021:
1022: s = splbio ();
1023: if (as->active) {
1024: printf ("asabort %d\n", as - asinfo);
1025: physaddr = vtophys (&as->ccb);
1026: as->mailbox->msb = physaddr >> 16;
1027: as->mailbox->mid = physaddr >> 8;
1028: as->mailbox->lsb = physaddr;
1029: as->mailbox->cmd = 2;
1030: as_put_byte (AS_CMD_START_SCSI_COMMAND);
1031:
1032: as->active = 0;
1033: bp = as->requests.b_actf;
1034: if (bp) {
1035: bp->b_flags |= B_ERROR;
1036: asdone (as, 1);
1037: }
1038: }
1039: splx (s);
1040: }
1041:
1042: asintr (dev_t dev)
1043: {
1044: int didwork;
1045: int i, j;
1046: struct mailbox_entry *mp;
1047: unsigned int physaddr;
1048: int val;
1049:
1050: outb (as_port + AS_CONTROL, AS_CONTROL_IRST);
1051: #ifdef notdef
1052: if (asverbose)
1053: printf ("asintr %x ", cpl);
1054: #endif
1055: again:
1056: didwork = 0;
1057: for (i = NTARGETS; i < NTARGETS * 2; i++) {
1058: mp = &mailboxes[i];
1059:
1060: if ((val = mp->cmd) == 0)
1061: continue;
1062:
1063: didwork = 1;
1064:
1065: physaddr = (mp->msb << 16)
1066: | (mp->mid << 8)
1067: | mp->lsb;
1068:
1069: for (j = 0; j < NTARGETS; j++) {
1070: if (asinfo[j].ccb_phys == physaddr) {
1071: mp->cmd = 0;
1072: asintr1 (&asinfo[j], val);
1073: break;
1074: }
1075: }
1076: if (j == NTARGETS) {
1077: printf ("as: unknown mailbox paddr 0x%x\n", physaddr);
1078: mp->cmd = 0;
1079: }
1080: }
1081:
1082: if (didwork)
1083: goto again;
1084: }
1085:
1086: asintr1 (as, val)
1087: struct asinfo *as;
1088: int val;
1089: {
1090: struct buf *bp;
1091: struct ccb *ccb;
1092: int n;
1093: int bad;
1094: char *msg;
1095: char msgbuf[100];
1096: unsigned char *sp;
1097: int i,key;
1098:
1099: if (asverbose)
1100: printf ("asintr1 %x ", val);
1101: if (as->active == 0) {
1102: printf ("as: stray intr 0x%x\n", as->dev);
1103: return;
1104: }
1105:
1106: as->active = 0;
1107: untimeout (asabort, as);
1108:
1109: bp = as->requests.b_actf;
1110: ccb = &as->ccb;
1111:
1112: if (bp == as->scsi_bp) {
1113: /* no fancy error recovery in this case */
1114: if (asverbose)
1115: printf ("asintr1:scsicmd ");
1116: #if 0
1117: if (val != 1)
1118: bp->b_flags |= B_ERROR;
1119: goto next;
1120: #endif
1121: }
1122:
1123: bad = 0;
1124: msg = NULL;
1125:
1126: if (val != 1 && val != 4) {
1127: bad = 1;
1128: sprintf (msgbuf, "funny mailbox message 0x%x\n", val);
1129: msg = msgbuf;
1130: goto wrapup;
1131: }
1132:
1133: if (ccb->ccb_host_status != 0) {
1134: bad = 1;
1135: sprintf (msgbuf, "controller error 0x%x",
1136: ccb->ccb_host_status);
1137: msg = msgbuf;
1138: goto wrapup;
1139: }
1140:
1141: if (ccb->ccb_target_status == 0)
1142: /* good transfer */
1143: goto wrapup;
1144:
1145: if (ccb->ccb_target_status == 8) {
1146: /* target rejected command because it is busy
1147: * and wants us to try again later. We'll wait 1 second
1148: */
1149: as->restart_pending = 1;
1150: timeout (asrestart, as, hz);
1151: return;
1152: }
1153:
1154: if (ccb->ccb_target_status != 2) {
1155: bad = 1;
1156: sprintf (msgbuf, "target error 0x%x",
1157: ccb->ccb_target_status);
1158: msg = msgbuf;
1159: goto wrapup;
1160: }
1161:
1162: /* normal path for errors */
1163:
1164: sp = ccb_sense (ccb);
1165: /* check for extended sense information */
1166: if ((sp[0] & 0x7f) != 0x70) {
1167: /* none */
1168: bad = 1;
1169: sprintf (msgbuf, "scsi error 0x%x", sp[0] & 0x7f);
1170: msg = msgbuf;
1171: goto wrapup;
1172: }
1173:
1174: if (as->tape && (sp[2] & 0xf) == 0) {
1175: if (sp[2] & 0xe0) {
1176: /* either we read a file mark, the early warning EOT,
1177: * or the block size did not match. In any case, the
1178: * normal residue handling will work (I think)
1179: */
1180: goto wrapup;
1181: }
1182: }
1183:
1184: bad = 1;
1185:
1186: switch (key = sp[2] & 0xf) {
1187: case 1:
1188: msg = "soft error";
1189: bad = 0;
1190: break;
1191: case 2:
1192: msg = "not ready";
1193: break;
1194: case 3:
1195: msg = "hard error";
1196: break;
1197: case 4:
1198: msg = "target hardware error";
1199: break;
1200: case 5:
1201: msg = "illegal request";
1202: break;
1203: case 6:
1204: msg = "unit attention error";
1205: break;
1206: case 7:
1207: msg = "write protect error";
1208: break;
1209: case 0xd:
1210: msg = "volume overflow";
1211: break;
1212: default:
1213: sprintf (msgbuf, "scsi extended error 0x%x", sp[2] & 0xf);
1214: msg = msgbuf;
1215: break;
1216: }
1217:
1218: wrapup:
1219:
1220: if (bad && msg == NULL)
1221: msg = "unknown error";
1222:
1223: if (msg && key != 6) {
1224: diskerr (bp, "as", msg,
1225: LOG_PRINTF,
1226: -1, /* number of successful blks */
1227: as->have_label ? &as->label : NULL);
1228: printf ("\n");
1229: }
1230:
1231: if (bad && key != 6) {
1232: bp->b_flags |= B_ERROR;
1233: printf ("scsi sense: ");
1234: sp = ccb_sense (ccb);
1235: for (i = 0; i < 30; i++)
1236: printf ("%x ", sp[i] & 0xff);
1237: printf ("\n");
1238: }
1239:
1240: bp->b_resid = (ccb->ccb_data_len_msb << 16)
1241: | (ccb->ccb_data_len_mid << 8)
1242: | ccb->ccb_data_len_lsb;
1243: if (bp != as->scsi_bp && bp->b_resid != 0)
1244: printf ("scsi resid = %d\n", bp->b_resid);
1245:
1246: next:
1247: asdone (as, 1);
1248: }
1249:
1250: asdone (as, restart)
1251: struct asinfo *as;
1252: int restart;
1253: {
1254: struct buf *bp;
1255:
1256: bp = as->requests.b_actf;
1257: as->requests.b_actf = bp->av_forw;
1258: biodone (bp);
1259: as->retry_count = 0;
1260: if (restart && as->requests.b_actf)
1261: asstart (as);
1262: }
1263:
1264: int
1265: assize (dev)
1266: dev_t dev;
1267: {
1268: struct asinfo *as;
1269: struct disklabel *lp;
1270: int val;
1271:
1272: if (as_port == 0 || dev_target (dev) >= NTARGETS)
1273: return (ENXIO);
1274:
1275: as = &asinfo[dev_target (dev)];
1276:
1277: if (as->open == 0
1278: && asopen (dev, FREAD, S_IFBLK, NULL) != 0)
1279: return (0);
1280:
1281: if (as->have_label == 0)
1282: return (0);
1283:
1284: lp = &as->label;
1285: val = lp->d_partitions[dev_part (dev)].p_size
1286: * lp->d_secsize / DEV_BSIZE;
1287: (void) asclose(dev, FREAD, S_IFBLK, NULL);
1288: return (val);
1289: }
1290:
1291: int
1292: as_put_byte (val)
1293: int val;
1294: {
1295: int i;
1296:
1297: for (i = 100; i > 0; i--) {
1298: if ((inb (as_port + AS_STATUS) & AS_STATUS_CDF) == 0)
1299: break;
1300: DELAY (100);
1301: }
1302: if (i == 0) {
1303: printf ("as: put byte timed out\n");
1304: return (-1);
1305: }
1306: outb (as_port + AS_DATA_OUT, val);
1307: return (0);
1308: }
1309:
1310: int
1311: as_get_byte (as)
1312: {
1313: int i;
1314:
1315: for (i = 100; i > 0; i--) {
1316: if ((inb (as_port + AS_STATUS) & AS_STATUS_DF) != 0)
1317: break;
1318: DELAY (100);
1319: }
1320: if (i == 0) {
1321: printf ("as_get_byte timed out\n");
1322: return (-1);
1323: }
1324: return (inb (as_port + AS_DATA_OUT) & 0xff);
1325: }
1326: #endif /* NAS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.