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