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