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