|
|
1.1 ! root 1: /* ! 2: * This is the generic SCSI part of the ! 3: * Adaptec AHA154x host adapter driver for the AT. ! 4: * ! 5: * $Log: scsi.c,v $ ! 6: * Revision 1.1 92/07/17 15:24:43 bin ! 7: * Initial revision ! 8: * ! 9: * Revision 1.10 92/01/17 03:51:13 hal ! 10: * Cleanup for 3.2.1. ! 11: * ! 12: * Revision 1.9 91/11/11 12:32:58 hal ! 13: * Get SD_HDS and SD_SPT from tboot. ! 14: * ! 15: * Revision 1.8 91/10/25 14:50:39 hal ! 16: * Make DMA channel patchable. ! 17: * ! 18: * Revision 1.7 91/10/22 13:40:36 hal ! 19: * Use sys on kernel header includes. ! 20: * ! 21: * Revision 1.6 91/06/10 13:28:11 hal ! 22: * Refix startup problem with HDGETA. Text cleanup. ! 23: * ! 24: * Revision 1.5 91/06/10 12:58:04 hal ! 25: * Partial fix for HDGETA failing if partition table absent. ! 26: * ! 27: * Revision 1.4 91/06/03 13:50:06 hal ! 28: * Add HDSETA. ! 29: * ! 30: * Revision 1.3 91/05/08 11:00:30 root ! 31: * Make number of heads - SD_HDS - patchable for Tandy. ! 32: * ! 33: * Revision 1.2 91/05/01 04:50:11 root ! 34: * Debug code and d_time/sw_active imbalance fixed. ! 35: * ! 36: * Revision 1.1 91/04/30 11:02:22 root ! 37: * Shipped with COH 3.1.0 ! 38: * ! 39: */ ! 40: ! 41: #include <sys/coherent.h> ! 42: #include <sys/fdisk.h> ! 43: #include <sys/hdioctl.h> ! 44: #include <sys/sdioctl.h> ! 45: #include <sys/buf.h> ! 46: #include <sys/con.h> ! 47: #include <sys/stat.h> ! 48: #include <errno.h> ! 49: #include <sys/scsiwork.h> ! 50: #include <sys/typed.h> ! 51: ! 52: extern saddr_t sds; ! 53: extern short n_atdr; ! 54: ! 55: /* ! 56: * Configurable parameters ! 57: * ! 58: * Adaptec ROM translates at 64 heads, except the Tandy version, which ! 59: * uses 16 heads. Kernel variable SD_HDS is patchable for this reason. ! 60: */ ! 61: #define DEF_AHA_HDS 64 ! 62: #define DEF_AHA_SPT 32 ! 63: ! 64: int SD_HDS = 0; ! 65: int SD_SPT = 0; ! 66: ! 67: #define NDRIVE (8 * 4) /* 8 SCSI ids and 4 LUNs */ ! 68: #define SDMAJOR 13 /* Major Device Number */ ! 69: ! 70: /* ! 71: * user configurable parameters ! 72: */ ! 73: int SDIRQ = 11; /* Interrupt */ ! 74: int SDBASE = 0x0330; /* Port base */ ! 75: int SDDMA = 5; /* Used for first party DMA */ ! 76: ! 77: /* ! 78: * LUN --------++ ! 79: * device macros Special-+ || ! 80: * minor device bits are of the form: 76543210 ! 81: * ||| || ! 82: * SCSI ID--+++ || ! 83: * Partition ----++ ! 84: * Partition mapping: ! 85: * ! 86: * Description Special Bit Partition # Device Type ! 87: * ----------- ----------- ----------- ------ ---- ! 88: * partition a 0 00 /dev/sd??a disk ! 89: * partition b 0 01 /dev/sd??b disk ! 90: * partition c 0 10 /dev/sd??c disk ! 91: * partition d 0 11 /dev/sd??d disk ! 92: * partition table 1 00 /dev/sd??x disk ! 93: * no rewind tape 1 01 /dev/sd??n tape ! 94: * UNALLOCATED 1 10 --- ???? ! 95: * rewind tape device 1 11 /dev/sd?? tape ! 96: */ ! 97: #define DRIVENO(minor) (((minor) >> 2) & 0x1F) /* SCSI ID + LUN */ ! 98: #define SCSIID(minor) (((minor) >> 4) & 0x7) /* SCSI ID */ ! 99: #define LUN(minor) (((minor) >> 2) & 0x3) /* Logical Unit Number */ ! 100: #define PARTITION(minor) ((minor) & 0x3) /* Partition */ ! 101: #define sdmkdev(maj, s, drv) makedev((maj), ((s)|((drv)<<2))) ! 102: ! 103: /* ! 104: * Driver configuration. ! 105: */ ! 106: void sdload(); ! 107: void sdunload(); ! 108: void sdopen(); ! 109: void sdclose(); ! 110: void sdread(); ! 111: void sdwrite(); ! 112: int sdioctl(); ! 113: void sdblock(); ! 114: int sdwatch(); ! 115: int nulldev(); ! 116: int nonedev(); ! 117: ! 118: CON sdcon = { ! 119: DFBLK|DFCHR, /* Flags */ ! 120: SDMAJOR, /* Major index */ ! 121: sdopen, /* Open */ ! 122: sdclose, /* Close */ ! 123: sdblock, /* Block */ ! 124: sdread, /* Read */ ! 125: sdwrite, /* Write */ ! 126: sdioctl, /* Ioctl */ ! 127: nulldev, /* Powerfail */ ! 128: sdwatch, /* Timeout */ ! 129: sdload, /* Load */ ! 130: sdunload /* Unload */ ! 131: }; ! 132: ! 133: /* ! 134: * host adapter routines ! 135: */ ! 136: int aha_load(); /* initialize host adapter, DMA */ ! 137: void aha_unload(); /* shutdown the host adapter */ ! 138: int aha_start(); /* see if there's work */ ! 139: int aha_command(); ! 140: ! 141: /* ! 142: * Partition Parameters - copied from disk. ! 143: * ! 144: * There are NPARTN positions for the user partitions in array PPARM, ! 145: * plus 1 additional position to span the entire drive. ! 146: * Array pparmp[] contains a pointer to a kalloc()'ed PPARM ! 147: * entry if the drive actually exists, is a disk drive and if someone ! 148: * has attmpted to read a partition table from the drive. ! 149: */ ! 150: typedef struct fdisk_s PPARM[NPARTN + 1]; /* 4 partitions + whole drive */ ! 151: static PPARM *pparmp[NDRIVE]; /* one per possible drive */ ! 152: #define WHOLE_DRIVE NPARTN /* index for whole drive */ ! 153: #define PNULL ((PPARM *)0) ! 154: ! 155: /* ! 156: * Per disk controller data. ! 157: * Only one host adapter; no more, no less. ! 158: */ ! 159: static ! 160: scsi_work_t sd; ! 161: ! 162: static BUF dbuf; /* For raw I/O */ ! 163: static int sw_active; ! 164: ! 165: /** ! 166: * ! 167: * void ! 168: * sdload() - load routine. ! 169: * ! 170: * Action: The controller is reset and the interrupt vector is grabbed. ! 171: * The drive characteristics are set up at this time. ! 172: */ ! 173: static void ! 174: sdload() ! 175: { ! 176: FIFO *ffp; ! 177: typed_space *tp; ! 178: extern typed_space boot_gift; ! 179: ! 180: /* ! 181: * Initialize Drive Controller. ! 182: */ ! 183: sw_active = 0; ! 184: if (aha_load(SDDMA, SDIRQ, SDBASE, &sd) < 0) { ! 185: u.u_error = ENXIO; ! 186: return; ! 187: } ! 188: ! 189: /* ! 190: * Set values for # of heads and # of sectors per track. ! 191: * ! 192: * AHA translation mode uses the same # of heads ! 193: * and the same # of sectors per track for all drives. ! 194: * ! 195: * If these values are already patched, leave them alone. ! 196: * Otherwise, look in the data area written by tboot. ! 197: * If nothing from tboot, use default values. ! 198: */ ! 199: if (SD_HDS == 0 || SD_SPT == 0) { ! 200: /* heads & spt not both patched */ ! 201: SD_HDS = DEF_AHA_HDS; ! 202: SD_SPT = DEF_AHA_SPT; ! 203: if (F_NULL != (ffp = fifo_open(&boot_gift, 0))) { ! 204: if (T_NULL != (tp = fifo_read(ffp))) { ! 205: BIOS_DISK *bdp = (BIOS_DISK *)tp->ts_data; ! 206: if ((T_BIOS_DISK == tp->ts_type) && ! 207: (n_atdr == bdp->dp_drive) ) { ! 208: /* got values from tboot */ ! 209: SD_HDS = bdp->dp_heads; ! 210: SD_SPT = bdp->dp_sectors; ! 211: } ! 212: } ! 213: fifo_close(ffp); ! 214: } ! 215: } ! 216: printf(" SD_HDS=%d SD_SPT=%d\n", SD_HDS, SD_SPT); ! 217: ! 218: /* aha_device_info(); */ /* enable after this gets fixed */ ! 219: } ! 220: ! 221: /** ! 222: * ! 223: * void ! 224: * sdunload() - unload routine. ! 225: */ ! 226: static void ! 227: sdunload() ! 228: { ! 229: register int i; ! 230: ! 231: if (sw_active > 0) ! 232: printf("aha154x: sdunload() athough %d active\n", sw_active); ! 233: aha_unload(SDIRQ); ! 234: for (i = 0; i < NDRIVE; ++i) ! 235: if (pparmp[i] != PNULL) ! 236: kfree(pparmp[i]); /* free any partition tables */ ! 237: } ! 238: ! 239: /* ! 240: * int ! 241: * sdgetpartitions(dev) - load partition table for specified drive ! 242: * ! 243: * - return 1 on success and 0 on failure ! 244: */ ! 245: int sdgetpartitions(dev) ! 246: dev_t dev; ! 247: { ! 248: register int i; ! 249: scsi_cmd_t sc; ! 250: unsigned char *buffer; ! 251: struct fdisk_s *fdp; ! 252: int d = DRIVENO(minor(dev)); ! 253: ! 254: pparmp[d] = kalloc(sizeof *pparmp[0]); ! 255: fdp = (struct fdisk_s *) pparmp[d]; /* point to first entry */ ! 256: buffer = kalloc(36+1); ! 257: if (buffer == NULL || pparmp[d] == PNULL) { ! 258: printf("aha154x: out of kernel memory\n"); ! 259: u.u_error = EKSPACE; ! 260: return 0; ! 261: } ! 262: kclear(pparmp[d], sizeof *pparmp[0]); ! 263: sc.unit = d; ! 264: sc.block = 0L; ! 265: sc.blklen = 0; ! 266: ! 267: sc.buffer = VTOP2(buffer, sds); ! 268: ++drvl[SDMAJOR].d_time; ! 269: #if 0 ! 270: sc.cmd = ScmdINQUIRY; ! 271: sc.buflen = 36; ! 272: aha_command(&sc); ! 273: aha_command(&sc); ! 274: buffer[36] = 0; ! 275: printf("SCSI Disk %s", &buffer[8]); ! 276: #endif ! 277: sc.cmd = ScmdREADCAPACITY; ! 278: sc.buflen = 8; ! 279: ! 280: for(i = 0; i < sc.buflen; ++i) ! 281: buffer[i] = 0; ! 282: aha_command(&sc); ! 283: aha_command(&sc); ! 284: #if VERBOSE ! 285: printf("buffer ="); ! 286: for(i = 0; i < sc.buflen; ++i) ! 287: printf(" %x", buffer[i]); ! 288: printf("\n"); ! 289: #endif ! 290: sc.block = (buffer[0]<<8) | buffer[1]; ! 291: sc.block <<= 16; ! 292: sc.block |= (buffer[2]<<8) | buffer[3]; ! 293: ! 294: sc.blklen = (buffer[6]<<8) | buffer[7]; ! 295: #if VERBOSE ! 296: printf("SCSI %D. blocks of size %d\n", sc.block, sc.blklen); ! 297: #endif ! 298: kfree(buffer); ! 299: fdp[WHOLE_DRIVE].p_size = sc.block; ! 300: --drvl[SDMAJOR].d_time; ! 301: return fdisk(sdmkdev(major(dev), SDEV, d), pparmp[d]); ! 302: } ! 303: ! 304: /** ! 305: * ! 306: * void ! 307: * sdopen(dev, mode) ! 308: * dev_t dev; ! 309: * int mode; ! 310: * ! 311: * Input: dev = disk device to be opened. ! 312: * mode = access mode [IPR,IPW, IPR+IPW]. ! 313: * ! 314: * Action: Validate the minor device. ! 315: * Update the paritition table if necessary. ! 316: */ ! 317: static void ! 318: sdopen(dev, mode) ! 319: register dev_t dev; ! 320: { ! 321: register int p; /* partition */ ! 322: register int d; /* drive (SCSI ID + LUN) */ ! 323: struct fdisk_s *fdp; /* one partition entry */ ! 324: ! 325: if (minor(dev) & SDEV) { ! 326: if (PARTITION(minor(dev)) != 0) { /* tape device ? */ ! 327: u.u_error = ENXIO; /* not yet! */ ! 328: devmsg(dev, "No tape yet"); ! 329: } else { ! 330: ++drvl[SDMAJOR].d_time; ! 331: ++sw_active; ! 332: } ! 333: return; ! 334: } ! 335: ! 336: d = DRIVENO(minor(dev)); ! 337: p = PARTITION(minor(dev)); ! 338: ! 339: /* ! 340: * If partition not defined read partition characteristics. ! 341: */ ! 342: if (pparmp[d] == PNULL) /* no entry yet for this drive ? */ ! 343: if (!sdgetpartitions(dev)) { ! 344: u.u_error = ENXIO; ! 345: return; ! 346: } ! 347: /* ! 348: * Ensure partition lies within drive boundaries and is non-zero size. ! 349: */ ! 350: fdp = (struct fdisk_s *) pparmp[d]; ! 351: if ((fdp[p].p_base+fdp[p].p_size) > fdp[WHOLE_DRIVE].p_size) { ! 352: u.u_error = EBADFMT; ! 353: } else if (fdp[p].p_size == 0) { ! 354: u.u_error = ENODEV; ! 355: } else { ! 356: ++drvl[SDMAJOR].d_time; ! 357: ++sw_active; ! 358: } ! 359: } ! 360: ! 361: void sdclose(dev) ! 362: { ! 363: --drvl[SDMAJOR].d_time; ! 364: --sw_active; ! 365: } ! 366: ! 367: /** ! 368: * ! 369: * void ! 370: * sdread(dev, iop) - write a block to the raw disk ! 371: * dev_t dev; ! 372: * IO * iop; ! 373: * ! 374: * Input: dev = disk device to be written to. ! 375: * iop = pointer to source I/O structure. ! 376: * ! 377: * Action: Invoke the common raw I/O processing code. ! 378: */ ! 379: static void ! 380: sdread(dev, iop) ! 381: dev_t dev; ! 382: IO *iop; ! 383: { ! 384: ioreq(&dbuf, iop, dev, BREAD, BFRAW|BFBLK|BFIOC); ! 385: } ! 386: ! 387: /** ! 388: * ! 389: * void ! 390: * sdwrite(dev, iop) - write a block to the raw disk ! 391: * dev_t dev; ! 392: * IO * iop; ! 393: * ! 394: * Input: dev = disk device to be written to. ! 395: * iop = pointer to source I/O structure. ! 396: * ! 397: * Action: Invoke the common raw I/O processing code. ! 398: */ ! 399: static void ! 400: sdwrite(dev, iop) ! 401: dev_t dev; ! 402: IO *iop; ! 403: { ! 404: ioreq(&dbuf, iop, dev, BWRITE, BFRAW|BFBLK|BFIOC); ! 405: } ! 406: ! 407: /** ! 408: * ! 409: * int ! 410: * sdioctl(dev, cmd, arg) ! 411: * dev_t dev; ! 412: * int cmd; ! 413: * char * vec; ! 414: * ! 415: * Input: dev = disk device to be operated on. ! 416: * cmd = input/output request to be performed. ! 417: * vec = (pointer to) optional argument. ! 418: * ! 419: * Action: Validate the minor device. ! 420: * Update the paritition table if necessary. ! 421: */ ! 422: static int ! 423: sdioctl(dev, cmd, vec) ! 424: register dev_t dev; ! 425: int cmd; ! 426: char * vec; ! 427: { ! 428: int d; ! 429: hdparm_t hdparm; ! 430: struct fdisk_s *fdp; ! 431: int do_getpt = 0; /* 1 if need to call sdgetpartitions() */ ! 432: ! 433: d = DRIVENO(minor(dev)); ! 434: ! 435: /* ! 436: * Identify input/output request. ! 437: */ ! 438: switch (cmd) { ! 439: ! 440: case HDGETA: ! 441: /* ! 442: * If haven't loaded partition table yet for this drive, ! 443: * try to do it now. Note sdgetpartitions() will fail ! 444: * if there is a new drive (e.g. no signature). But all ! 445: * we need is allocation of pparmp[d] and capacity read ! 446: * properly from the drive. ! 447: */ ! 448: if (pparmp[d] == PNULL) { ! 449: do_getpt = 1; /* REALLY just want Read Capacity */ ! 450: sdgetpartitions(dev); ! 451: if (pparmp[d] == NULL) { ! 452: u.u_error = ENXIO; ! 453: return -1; ! 454: } ! 455: } ! 456: fdp = (struct fdisk_s *) pparmp[d]; ! 457: *(short *)&hdparm.landc[0] = ! 458: *(short *)&hdparm.ncyl[0] = fdp[WHOLE_DRIVE].p_size ! 459: / (SD_HDS * SD_SPT); ! 460: hdparm.nhead = SD_HDS; ! 461: hdparm.nspt = SD_SPT; ! 462: kucopy(&hdparm, vec, sizeof hdparm); ! 463: /* ! 464: * I know it's ugly. But it gets around startup Catch-22. ! 465: * ! 466: * The fdisk command needs HDGETA. HDGETA invokes ! 467: * sdgetpartitions(), but we want to call it again ! 468: * after the partition table has been created by the fdisk ! 469: * command. ! 470: */ ! 471: if (do_getpt) { ! 472: kfree(pparmp[d]); ! 473: pparmp[d] = PNULL; /* force re-read of p. table */ ! 474: } ! 475: return 0; ! 476: case HDSETA: ! 477: /* ! 478: * Set hard disk attributes. ! 479: */ ! 480: fdp = (struct fdisk_s *) pparmp[d]; ! 481: ukcopy(vec, &hdparm, sizeof hdparm); ! 482: SD_HDS = hdparm.nhead; ! 483: SD_SPT = hdparm.nspt; ! 484: fdp[WHOLE_DRIVE].p_size = ! 485: (long)(*(short *)&hdparm.ncyl[0]) ! 486: * (long)SD_HDS * (long)SD_SPT; ! 487: ! 488: return 0; ! 489: case SCSI_HA_CMD: ! 490: return aha_ioctl(cmd, vec); ! 491: case SCSI_CMD: ! 492: return 0; ! 493: case SCSI_CMD_IN: ! 494: return 0; ! 495: case SCSI_CMD_OUT: ! 496: return 0; ! 497: ! 498: default: ! 499: u.u_error = EINVAL; ! 500: return -1; ! 501: } ! 502: } ! 503: ! 504: /** ! 505: * ! 506: * void ! 507: * sdblock(bp) - queue a block to the disk ! 508: * ! 509: * Input: bp = pointer to block to be queued. ! 510: * ! 511: * Action: Queue a block to the disk. ! 512: * Make sure that the transfer is within the disk partition. ! 513: */ ! 514: static void ! 515: sdblock(bp) ! 516: register BUF *bp; ! 517: { ! 518: register scsi_work_t *sw; ! 519: register int s; ! 520: struct fdisk_s *fdp; ! 521: ! 522: int p = PARTITION(minor(bp->b_dev)); ! 523: int drv = DRIVENO(minor(bp->b_dev)); ! 524: ! 525: if (minor(bp->b_dev) & SDEV) ! 526: p = WHOLE_DRIVE; ! 527: bp->b_resid = bp->b_count; ! 528: ! 529: fdp = (struct fdisk_s *) pparmp[drv]; ! 530: ! 531: /* ! 532: * Range check disk region. ! 533: */ ! 534: if (pparmp[drv] == PNULL) { ! 535: if (p == WHOLE_DRIVE) { ! 536: #if 0 ! 537: /* Why did we only allow people to access the first block of WHOLE_DRIVE? ! 538: in cases where there was not a valid partition table? */ ! 539: if ((bp->b_bno != 0) || (bp->b_count != BSIZE)) { ! 540: bp->b_flag |= BFERR; ! 541: bdone(bp); ! 542: return; ! 543: } ! 544: #endif ! 545: } else { ! 546: printf("aha154x: no partition table\n"); ! 547: bp->b_flag |= BFERR; ! 548: bdone(bp); ! 549: return; ! 550: } ! 551: } else if ((bp->b_bno + (bp->b_count/BSIZE)) > fdp[p].p_size) { ! 552: bp->b_flag |= BFERR; ! 553: bdone(bp); ! 554: return; ! 555: } ! 556: ! 557: bp->b_actf = NULL; ! 558: sw = (scsi_work_t *)kalloc(sizeof(*sw)); ! 559: if (sw == (scsi_work_t *)0) { ! 560: printf("aha154x: out of kernel memory\n"); ! 561: bp->b_flag |= BFERR; ! 562: bdone(bp); ! 563: return; ! 564: } ! 565: sw->sw_bp = bp; ! 566: sw->sw_drv = drv; ! 567: sw->sw_type = 0; ! 568: if (p != WHOLE_DRIVE) ! 569: sw->sw_bno = fdp[p].p_base + bp->b_bno; ! 570: else ! 571: sw->sw_bno = bp->b_bno; ! 572: sw->sw_retry = 1; ! 573: ! 574: #if VERBOSE ! 575: printf("sdblock: drv %x bno %x:%x bp=%x, flag = %o\n", ! 576: drv, (long)sw->sw_bno, bp, bp->b_flag); ! 577: #endif ! 578: ! 579: s = sphi(); ! 580: if (sd.sw_actf == NULL) ! 581: sd.sw_actf = sw; ! 582: else ! 583: sd.sw_actl->sw_actf = sw; ! 584: sd.sw_actl = sw; ! 585: spl(s); ! 586: ! 587: aha_start(); ! 588: } ! 589: ! 590: sdwatch() ! 591: { ! 592: register int i; ! 593: ! 594: if (i = aha_start()) ! 595: #if VERBOSE ! 596: printf("sdwatch: started %d actions\n", i); ! 597: #else ! 598: ; ! 599: #endif ! 600: if (i = aha_completed()) ! 601: #if VERBOSE ! 602: printf("sdwatch: completed %d actions\n", i); ! 603: #else ! 604: ; ! 605: #endif ! 606: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.