|
|
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.