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