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