|
|
1.1 ! root 1: /* Copyright (c) 1994 NeXT Computer, Inc. All rights reserved. ! 2: * ! 3: * AMD_x86.m - architecture-specific methods for AMD SCSI driver ! 4: * ! 5: * HISTORY ! 6: * 21 Oct 94 Doug Mitchell at NeXT ! 7: * Created. ! 8: */ ! 9: ! 10: #import <driverkit/generalFuncs.h> ! 11: #import <driverkit/kernelDriver.h> ! 12: #import <driverkit/i386/IOPCIDeviceDescription.h> ! 13: #import <kernserv/prototypes.h> ! 14: #import <mach/kern_return.h> ! 15: #import "AMD_x86.h" ! 16: #import "pciconf.h" ! 17: #import "AMD_Regs.h" ! 18: #import "AMD_Chip.h" ! 19: #import "bringup.h" ! 20: #import "AMD_ddm.h" ! 21: #import "configKeys.h" ! 22: #import <mach/mach_interface.h> ! 23: ! 24: #define TEST_DEBUG 0 /* low level I/O test before registerDevice */ ! 25: #define TEST_IPL_BUG 0 /* test IPL bug */ ! 26: ! 27: #if TEST_DEBUG ! 28: static void testDebug(id driver); ! 29: #endif TEST_DEBUG ! 30: ! 31: #if TEST_IPL_BUG ! 32: static void testIplBug(); ! 33: #endif TEST_IPL_BUG ! 34: ! 35: #ifdef DEBUG ! 36: AMD_SCSI *amd_g; ! 37: #endif DEBUG ! 38: ! 39: static int _atoi(const char *ip) ! 40: { ! 41: unsigned rtn = 0; ! 42: ! 43: while(*ip) { ! 44: if((*ip < '0') || (*ip > '9')) { ! 45: return rtn; ! 46: } ! 47: rtn *= 10; ! 48: rtn += (*ip - '0'); ! 49: ip++; ! 50: } ! 51: return rtn; ! 52: } ! 53: ! 54: /* ! 55: * Get I/O port range and IRQ from PCI config space. Set appropriate ! 56: * values in deviceDescription. Returns base address in *baseAddr. ! 57: * Returns YES if successful, else NO. ! 58: */ ! 59: static BOOL parseConfigSpace( ! 60: id deviceDescription, ! 61: const char *title, ! 62: unsigned regSize, // in bytes ! 63: IOEISAPortAddress *baseAddr) // RETURNED ! 64: { ! 65: IOPCIConfigSpace configSpace; ! 66: IORange portRange; ! 67: unsigned *basePtr = 0; ! 68: int irq; ! 69: int i; ! 70: BOOL foundBase = NO; ! 71: IOReturn irtn; ! 72: ! 73: /* ! 74: * First get our configSpace register set. ! 75: */ ! 76: bzero(&configSpace, sizeof(IOPCIConfigSpace)); ! 77: if(irtn = [IODirectDevice getPCIConfigSpace:&configSpace ! 78: withDeviceDescription:deviceDescription]) { ! 79: IOLog("%s: Can\'t get configSpace (%s); ABORTING\n", ! 80: title, [IODirectDevice stringFromReturn:irtn]); ! 81: return NO; ! 82: } ! 83: basePtr = configSpace.BaseAddress; ! 84: irq = configSpace.InterruptLine; ! 85: if((basePtr[0] == 0) || (irq == 0)) { ! 86: IOLog("%s: Bogus config info (IRQ %d, Base 0x%x)\n", ! 87: title, irq, (unsigned)basePtr); ! 88: return NO; ! 89: } ! 90: ! 91: /* ! 92: * Scan all 6 base address registers, make sure there is exactly one ! 93: * I/O address. ! 94: */ ! 95: for(i=0; i<PCI_NUM_BASE_ADDRESS; i++) { ! 96: if(basePtr[i] & PCI_BASE_IO_BIT) { ! 97: if(foundBase) { ! 98: IOLog("%s: Multiple I/O Port Bases Found\n", title); ! 99: return NO; ! 100: } ! 101: foundBase = YES; ! 102: portRange.start = PCI_BASE_IO(basePtr[i]); ! 103: } ! 104: } ! 105: if(!foundBase) { ! 106: IOLog("%s: No I/O Port Base Found\n", title); ! 107: return NO; ! 108: } ! 109: portRange.size = regSize; ! 110: *baseAddr = portRange.start; ! 111: ddm_init("irq %d base 0x%x\n", irq, *baseAddr, 3,4,5); ! 112: ! 113: /* ! 114: * OK, retweeze our device description. ! 115: */ ! 116: irtn = [deviceDescription setInterruptList:&irq num:1]; ! 117: if(irtn) { ! 118: IOLog("%s: Can\'t set interruptList to IRQ %d (%s)\n", ! 119: title, irq, [IODirectDevice stringFromReturn:irtn]); ! 120: return NO; ! 121: } ! 122: irtn = [deviceDescription setPortRangeList:&portRange num:1]; ! 123: if(irtn) { ! 124: IOLog("%s: Can\'t set portRangeList to port 0x%x (%s)\n", ! 125: title, portRange.start, ! 126: [IODirectDevice stringFromReturn:irtn]); ! 127: return NO; ! 128: } ! 129: return YES; ! 130: } ! 131: ! 132: /* ! 133: * Obtain a YES/NO type parameter from the config table. ! 134: */ ! 135: static int getConfigParam( ! 136: id configTable, ! 137: const char *paramName) ! 138: { ! 139: const char *value; ! 140: int rtn = 0; // default if not present in table ! 141: ! 142: value = [configTable valueForStringKey:paramName]; ! 143: if(value) { ! 144: if(strcmp(value, "YES") == 0) { ! 145: rtn = 1; ! 146: } ! 147: [configTable freeString:value]; ! 148: } ! 149: return rtn; ! 150: } ! 151: ! 152: @implementation AMD_SCSI(Architecture) ! 153: ! 154: - archInit : deviceDescription ! 155: { ! 156: id configTable; ! 157: const char *value = NULL; ! 158: kern_return_t krtn; ! 159: vm_offset_t startPage, endPage; ! 160: unsigned ival; ! 161: IOReturn irtn; ! 162: unsigned char lun; ! 163: ! 164: #if TEST_IPL_BUG ! 165: testIplBug(); ! 166: #endif TEST_IPL_BUG ! 167: ! 168: ddm_init("AMD archInit\n", ! 169: 1,2,3,4,5); ! 170: scState = SCS_UNINITIALIZED; ! 171: ! 172: /* ! 173: * Obtain I/O port base, busType dependent. ! 174: */ ! 175: levelIRQ = NO; ! 176: configTable = [deviceDescription configTable]; ! 177: value = [configTable valueForStringKey:"Bus Type"]; ! 178: if(value == NULL) { ! 179: IOLog("AMD53C974: No Bus Type in config Table\n"); ! 180: goto abort; ! 181: } ! 182: if(strcmp(value, "PCI") == 0) { ! 183: busType = BT_PCI; ! 184: if(parseConfigSpace(deviceDescription, ! 185: "AMD53C974", ! 186: AMD_PCI_REGISTER_SPACE, ! 187: &ioBase) == NO) { ! 188: [configTable freeString:value]; ! 189: goto abort; ! 190: } ! 191: ioBase += AMD_PCI_REGISTER_OFFSET; ! 192: if(irtn = [deviceDescription getPCIdevice : &deviceNumber ! 193: function : &functionNumber ! 194: bus : &busNumber]) { ! 195: IOLog("AMD53C974: Can't find device using " ! 196: "getPCIdevice (%s)\n", ! 197: [self stringFromReturn:irtn]); ! 198: goto abort; ! 199: } ! 200: levelIRQ = YES; ! 201: IOLog("AMD53C974: found at bus %d device %d function %d " ! 202: "irq %d\n", ! 203: busNumber, deviceNumber, functionNumber, ! 204: [deviceDescription interrupt]); ! 205: } ! 206: else { ! 207: IOLog("AMD53C974: Bad Bus Type (%s) in config table\n", ! 208: value); ! 209: [configTable freeString:value]; ! 210: goto abort; ! 211: } ! 212: [configTable freeString:value]; ! 213: ! 214: if (![self probeChip]) { ! 215: IOLog("AMD53C974 Host Adaptor Not found at Port 0x%x\n", ! 216: ioBase); ! 217: goto abort; ! 218: } ! 219: ! 220: #if DEBUG ! 221: amd_g = self; ! 222: #endif DEBUG ! 223: ! 224: if ([super initFromDeviceDescription:deviceDescription] == nil) { ! 225: goto abort; ! 226: } ! 227: ioThreadRunning = 1; ! 228: ! 229: /* ! 230: * Initialize local variables. Note that activeArray and ! 231: * perTarget arrays are zeroed by objc runtime. ! 232: */ ! 233: queue_init(&disconnectQ); ! 234: queue_init(&commandQ); ! 235: queue_init(&pendingQ); ! 236: commandLock = [[NXLock alloc] init]; ! 237: activeCmd = NULL; ! 238: [self resetStats]; ! 239: nextQueueTag = QUEUE_TAG_NONTAGGED + 1; ! 240: ! 241: /* ! 242: * Allocate some physically contiguous memory for the Memory ! 243: * Descriptor List. ! 244: */ ! 245: mdlFree = IOMalloc(MDL_SIZE * 2 * sizeof(vm_address_t)); ! 246: startPage = trunc_page(mdlFree); ! 247: endPage = trunc_page(((vm_offset_t)&mdlFree[MDL_SIZE]) - 1); ! 248: if(startPage != endPage) { ! 249: mdl = mdlFree + MDL_SIZE; ! 250: } ! 251: else { ! 252: mdl = mdlFree; ! 253: } ! 254: ddm_init("&mdl[0] = 0x%x &mdl[%d] = 0x%x\n", mdl, MDL_SIZE - 1, ! 255: &mdl[MDL_SIZE - 1], 4,5); ! 256: irtn = IOPhysicalFromVirtual(IOVmTaskSelf(), ! 257: (vm_offset_t)mdl, ! 258: &mdlPhys); ! 259: if(irtn) { ! 260: IOLog("AMD53C974: can't get physical address of MDL\n"); ! 261: goto abort; ! 262: } ! 263: ! 264: /* ! 265: * get tagged command queueing, sync mode, fast mode enables from ! 266: * configTable. ! 267: */ ! 268: cmdQueueEnable = getConfigParam(configTable, CMD_QUEUE_ENABLE); ! 269: syncModeEnable = getConfigParam(configTable, SYNC_ENABLE); ! 270: fastModeEnable = getConfigParam(configTable, FAST_ENABLE); ! 271: extendTiming = getConfigParam(configTable, EXTENDED_TIMING); ! 272: ! 273: /* ! 274: * Get clock rate, in MHz. ! 275: */ ! 276: scsiClockRate = AMD_DEFAULT_CLOCK; ! 277: value = [configTable valueForStringKey:SCSI_CLOCK_RATE]; ! 278: if(value) { ! 279: ival = _atoi(value); ! 280: if(ival) { ! 281: scsiClockRate = ival; ! 282: ddm_init("SCSI Clock Rate = %d MHz\n", ! 283: ival, 2,3,4,5); ! 284: } ! 285: [configTable freeString:value]; ! 286: } ! 287: ! 288: autoSenseEnable = AUTO_SENSE_ENABLE; // from bringup.h ! 289: ! 290: /* ! 291: * Get internal version of interruptPort; set the port queue ! 292: * length to the maximum size. ! 293: */ ! 294: interruptPortKern = IOConvertPort([self interruptPort], ! 295: IO_KernelIOTask, ! 296: IO_Kernel); ! 297: krtn = port_set_backlog(task_self(), [self interruptPort], ! 298: PORT_BACKLOG_MAX); ! 299: if(krtn) { ! 300: IOLog("%s: error %d on port_set_backlog()\n", ! 301: [self name], krtn); ! 302: /* Oh well... */ ! 303: } ! 304: ! 305: /* ! 306: * Initialize the chip and reset the bus. ! 307: */ ! 308: if([self hwReset:NULL]) { ! 309: goto abort; ! 310: } ! 311: ! 312: /* ! 313: * Reserve our devices. hostId is init'd at chip level in hwReset. ! 314: */ ! 315: for(lun=0; lun<SCSI_NLUNS; lun++) { ! 316: [self reserveTarget:hostId ! 317: lun:lun ! 318: forOwner:self]; ! 319: } ! 320: ! 321: /* ! 322: * OK, we're ready to roll. ! 323: */ ! 324: ! 325: #if TEST_DEBUG ! 326: ! 327: /* ! 328: * Before we call registerDevice and bring all kinds of uncontrolled ! 329: * I/O... ! 330: */ ! 331: testDebug(self); ! 332: #endif TEST_DEBUG ! 333: ! 334: [self registerDevice]; ! 335: ! 336: return self; ! 337: ! 338: abort: ! 339: return [self free]; ! 340: } ! 341: ! 342: /* ! 343: * Ensure DMA machine is in idle quiescent state. ! 344: */ ! 345: - (void)dmaIdle ! 346: { ! 347: unsigned cmd = DC_CMD_IDLE | DC_MDL; ! 348: ! 349: /* ! 350: * MDL and dir bits need to be the same as they will for a ! 351: * (potentially) upcoming DMA command. ! 352: */ ! 353: if(activeCmd) { ! 354: if(activeCmd->scsiReq->read) { ! 355: cmd |= DC_DIR_READ; ! 356: } ! 357: else { ! 358: cmd |= DC_DIR_WRITE; ! 359: } ! 360: } ! 361: /* else direction is don't care */ ! 362: ! 363: /* ! 364: * FIXME - should we do a DMA blast here? ! 365: */ ! 366: WRITE_REGL(dmaCommand, cmd); ! 367: #if WRITE_DMA_COMMAND_TWICE ! 368: WRITE_REGL(dmaCommand, cmd); ! 369: #endif WRITE_DMA_COMMAND_TWICE ! 370: } ! 371: ! 372: #if DDM_DEBUG ! 373: static unsigned char *ddmPhys; ! 374: #endif DDM_DEBUG ! 375: ! 376: /* ! 377: * Start DMA transfer at activeCmd->currentPtr for activeCmd->currentByteCount. ! 378: * Note: this method is not strictly architecture-dependent and ! 379: * chip-independent. I think it's best to do all of this work in one place, ! 380: * and an AMD chip for a different bus will definitely have a lot of changes ! 381: * here. ! 382: */ ! 383: - (sc_status_t)dmaStart ! 384: { ! 385: unsigned byteCount = activeCmd->currentByteCount; ! 386: unsigned char cvalue; ! 387: unsigned pages; ! 388: vm_offset_t virtAddr; ! 389: unsigned physAddr; ! 390: unsigned page; ! 391: unsigned offset; ! 392: IOReturn irtn; ! 393: unsigned cmd; ! 394: ! 395: ddm_thr("dmaStart\n", 1,2,3,4,5); ! 396: ASSERT(activeCmd != NULL); ! 397: [self dmaIdle]; ! 398: ! 399: /* ! 400: * Set up SCSI block transfer count registers. ! 401: */ ! 402: cvalue = byteCount & 0xff; ! 403: WRITE_REG(startXfrCntLow, cvalue); ! 404: cvalue = (byteCount >> 8) & 0xff; ! 405: WRITE_REG(startXfrCntMid, cvalue); ! 406: cvalue = (byteCount >> 16) & 0xff; ! 407: WRITE_REG(startXfrCntHi, cvalue); ! 408: ! 409: /* ! 410: * Set up a memory descriptor list. ! 411: */ ! 412: virtAddr = (vm_offset_t)activeCmd->currentPtr; ! 413: pages = (AMD_ROUND_PAGE(virtAddr + byteCount) - ! 414: AMD_TRUNC_PAGE(virtAddr)) / AMD_DMA_PAGE_SIZE; ! 415: for(page=0; page<pages; page++) { ! 416: if(page == 0) { ! 417: /* ! 418: * Special case, this one is allowed a page offset. ! 419: */ ! 420: offset = virtAddr & AMD_DMA_PAGE_MASK; ! 421: WRITE_REGL(dmaStartAddrs, offset); ! 422: ddm_dma(" page 0 offset 0x%x\n", offset, 2,3,4,5); ! 423: virtAddr = virtAddr & ~AMD_DMA_PAGE_MASK; ! 424: } ! 425: irtn = IOPhysicalFromVirtual(activeCmd->client, ! 426: virtAddr, ! 427: &physAddr); ! 428: if(irtn) { ! 429: IOLog("%s: Can't get physical address (%s)\n", ! 430: [self name], [self stringFromReturn:irtn]); ! 431: return SR_IOST_MEMF; ! 432: } ! 433: ddm_dma(" mdl[%d] = 0x%x\n", page, mdl[page], 3,4,5); ! 434: mdl[page] = physAddr; ! 435: virtAddr += AMD_DMA_PAGE_SIZE; ! 436: #if DDM_DEBUG ! 437: if(page == 0) { ! 438: ddmPhys = (unsigned char *)(physAddr + offset); ! 439: } ! 440: #endif DDM_DEBUG ! 441: } ! 442: ! 443: /* ! 444: * Load byte count and address of MDL into DMA engine, and go. ! 445: */ ! 446: ddm_dma(" dmaStartCount = 0x%x\n", byteCount, 2,3,4,5); ! 447: WRITE_REGL(dmaStartCount, byteCount); ! 448: WRITE_REGL(dmaStartMdlAddrs, mdlPhys); ! 449: if(activeCmd->scsiReq->read) { ! 450: cmd = DC_CMD_START | DC_MDL | DC_DIR_READ; ! 451: } ! 452: else { ! 453: cmd = DC_CMD_START | DC_MDL | DC_DIR_WRITE; ! 454: } ! 455: WRITE_REGL(dmaCommand, cmd); ! 456: #if WRITE_DMA_COMMAND_TWICE ! 457: WRITE_REGL(dmaCommand, cmd); ! 458: #endif WRITE_DMA_COMMAND_TWICE ! 459: WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO | SCMD_ENABLEDMA); ! 460: scState = SCS_DMAING; ! 461: return SR_IOST_GOOD; ! 462: } ! 463: ! 464: /* ! 465: * Terminate a DMA, including FIFO flush if necessary. Returns number of ! 466: * bytes transferred. ! 467: */ ! 468: - (unsigned)dmaTerminate ! 469: { ! 470: unsigned char fifoDepth = 0; ! 471: unsigned cmd; ! 472: int tries; ! 473: unsigned status; ! 474: unsigned bytesXfrd; ! 475: unsigned scsiXfrCnt; ! 476: unsigned value; ! 477: ! 478: ASSERT(activeCmd != NULL); ! 479: ! 480: /* ! 481: * Get resid count from SCSI block. ! 482: */ ! 483: scsiXfrCnt = READ_REG(currXfrCntLow); ! 484: value = READ_REG(currXfrCntMid); ! 485: scsiXfrCnt += (value << 8); ! 486: value = READ_REG(currXfrCntHi); ! 487: scsiXfrCnt += (value << 16); ! 488: ! 489: fifoDepth = READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK; ! 490: if((activeCmd->scsiReq->read) && (scsiXfrCnt != 0)) { ! 491: /* ! 492: * Make sure SCSI fifo is empty. The manual says we ! 493: * might have to wait a while. ! 494: */ ! 495: if(fifoDepth) { ! 496: IODelay(1000); ! 497: fifoDepth = READ_REG(currFifoState) & ! 498: FS_FIFO_LEVEL_MASK; ! 499: switch(fifoDepth) { ! 500: case 0: ! 501: ddm_dma("dmaTerminate: fifo cleared\n", ! 502: 1,2,3,4,5); ! 503: break; // normal, OK ! 504: case 1: ! 505: IOLog("%s: Odd Byte Disconnect on target %d\n", ! 506: [self name], ! 507: activeCmd->scsiReq->target); ! 508: break; ! 509: default: ! 510: IOLog("%s: SCSI FIFO hung\n", [self name]); ! 511: break; ! 512: ! 513: /* ! 514: * I'm not sure what to do about these ! 515: * errors... ! 516: */ ! 517: } ! 518: } ! 519: if(activeCmd->scsiReq->read) { ! 520: cmd = DC_CMD_BLAST | DC_MDL | DC_DIR_READ; ! 521: } ! 522: else { ! 523: cmd = DC_CMD_BLAST | DC_MDL | DC_DIR_WRITE; ! 524: } ! 525: ddm_dma(" ...sending DMA blast\n", 1,2,3,4,5); ! 526: WRITE_REGL(dmaCommand, cmd); ! 527: #if WRITE_DMA_COMMAND_TWICE ! 528: WRITE_REGL(dmaCommand, cmd); ! 529: #endif WRITE_DMA_COMMAND_TWICE ! 530: ! 531: /* ! 532: * Unfortunately, we have to poll for this one. No interrupt. ! 533: * FIXME - documentation is unclear on this. 6.7.6, the ! 534: * description of dmaStatus, says DS_BLAST_COMPLETE is only ! 535: * complete for "SCSI Disconnect and Reselect Operation". ! 536: * That doesn't make a whole lot of sense to me... ! 537: */ ! 538: for(tries=0; tries<500; tries++) { ! 539: status = READ_REGL(dmaStatus); ! 540: if(status & DS_BLAST_COMPLETE) { ! 541: break; ! 542: } ! 543: IODelay(100); ! 544: } ! 545: ! 546: ddm_dma("DMA blast : tries = %d fifoDepth = %d\n", ! 547: tries, fifoDepth, 3,4,5); ! 548: } ! 549: ! 550: /* ! 551: * Obtain number of bytes transferred. ! 552: */ ! 553: bytesXfrd = activeCmd->currentByteCount - ! 554: (scsiXfrCnt + fifoDepth); ! 555: ddm_chip("dmaTerminate: currentByteCount 0x%x, bytesXfrd 0x%x\n", ! 556: activeCmd->currentByteCount, bytesXfrd, 3,4,5); ! 557: #if 0 ! 558: { ! 559: unsigned char *vp = activeCmd->buffer; ! 560: ! 561: ddm_init("ddmPhys = %02x %02x %02x %02x %02x\n", ! 562: ddmPhys[0], ddmPhys[1], ddmPhys[2], ddmPhys[3], ddmPhys[4]); ! 563: ddm_init(" %02x %02x %02x %02x %02x\n", ! 564: ddmPhys[5], ddmPhys[6], ddmPhys[7], ddmPhys[8], ddmPhys[9]); ! 565: ddm_init("virt = %02x %02x %02x %02x %02x\n", ! 566: vp[0], vp[1], vp[2], vp[3], vp[4]); ! 567: ddm_init(" %02x %02x %02x %02x %02x\n", ! 568: vp[5], vp[6], vp[7], vp[8], vp[9]); ! 569: } ! 570: #endif 0 ! 571: [self dmaIdle]; ! 572: return bytesXfrd; ! 573: } ! 574: ! 575: @end ! 576: ! 577: #if TEST_DEBUG ! 578: ! 579: /* ! 580: * Do some simple I/O before IODisk starts probing us. ! 581: */ ! 582: int loopTest = 0; ! 583: int target = 0; ! 584: ! 585: #define DO_INIT_SLEEP 0 ! 586: #define DO_TUR 1 ! 587: #define DO_READ 1 ! 588: #define TEST_READ_SIZE 1 // in sectors ! 589: #define DO_TEST_ALIGN 0 ! 590: #define TEST_DISCONNECT 1 ! 591: ! 592: static void testDebug(id driver) ! 593: { ! 594: IOSCSIRequest scsiReq; ! 595: sc_status_t srtn; ! 596: unsigned char *rbuf; ! 597: int block = 100000; ! 598: ! 599: ddm_init("testDebug\n", 1,2,3,4,5); ! 600: if(DO_INIT_SLEEP) { ! 601: IOLog("Sleeping for 10 seconds for DDM view\n"); ! 602: IOSleep(10000); ! 603: } ! 604: if(DO_READ) { ! 605: if(DO_TEST_ALIGN) { ! 606: rbuf = IOMallocLow(TEST_READ_SIZE * 512); ! 607: if(rbuf == NULL) { ! 608: IOLog("IOMallocLow returned NULL!\n"); ! 609: rbuf = IOMalloc(TEST_READ_SIZE * 512); ! 610: } ! 611: } ! 612: else { ! 613: rbuf = IOMalloc(TEST_READ_SIZE * 512); ! 614: } ! 615: } ! 616: do { ! 617: if(DO_TUR) { ! 618: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 619: scsiReq.target = target; ! 620: scsiReq.cmdQueueDisable = 1; ! 621: ! 622: /* ! 623: * cdb = all zeroes = test unit ready ! 624: */ ! 625: scsiReq.timeoutLength = 4; ! 626: srtn = [driver executeRequest:&scsiReq ! 627: buffer:NULL ! 628: client:(vm_task_t)0]; ! 629: IOLog("testDebug: TUR result = %s\n", ! 630: IOFindNameForValue(scsiReq.driverStatus, ! 631: IOScStatusStrings)); ! 632: } ! 633: ! 634: if(DO_READ) { ! 635: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 636: unsigned i; ! 637: ! 638: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 639: scsiReq.target = target; ! 640: scsiReq.cmdQueueDisable = 1; ! 641: scsiReq.disconnect = TEST_DISCONNECT; ! 642: for(i=0; i<(TEST_READ_SIZE * 512); i++) { ! 643: rbuf[i] = i; ! 644: } ! 645: cdbp->c6_opcode = 8; ! 646: cdbp->c6_len = TEST_READ_SIZE; ! 647: cdbp->c6_lba0 = block; ! 648: /* ! 649: * Force a disconnect eventually ! 650: */ ! 651: if(block == 0) { ! 652: block = 100000; ! 653: } ! 654: else { ! 655: block = 0; ! 656: } ! 657: scsiReq.maxTransfer = TEST_READ_SIZE * 512; ! 658: scsiReq.read = YES; ! 659: scsiReq.timeoutLength = 10; ! 660: srtn = [driver executeRequest:&scsiReq ! 661: buffer:rbuf ! 662: client:IOVmTaskSelf()]; ! 663: if(scsiReq.driverStatus == 0) { ! 664: ddm_init("rbuf = %02x %02x %02x %02x %02x\n", ! 665: rbuf[0],rbuf[1],rbuf[2],rbuf[3],rbuf[4]); ! 666: ddm_init(" %02x %02x %02x %02x %02x\n", ! 667: rbuf[5],rbuf[6],rbuf[7],rbuf[8],rbuf[9]); ! 668: } ! 669: IOLog("testDebug: Read result = %s\n", ! 670: IOFindNameForValue(scsiReq.driverStatus, ! 671: IOScStatusStrings)); ! 672: } ! 673: IOSleep(5000); ! 674: } while(loopTest); ! 675: ! 676: } ! 677: ! 678: #endif TEST_DEBUG ! 679: ! 680: #if TEST_IPL_BUG ! 681: ! 682: #define IPL_TEST_LOOPS 1000000 // # of loops ! 683: #define IPL_TEST_TIME 0 // us delay per loop ! 684: ! 685: static void testIplBug() { ! 686: int loopNum; ! 687: ns_time_t curTime, lastTime; ! 688: unsigned usTime; ! 689: ! 690: IOGetTimestamp(&lastTime); ! 691: for(loopNum=0; loopNum<IPL_TEST_LOOPS; loopNum++) { ! 692: if(IPL_TEST_TIME) { ! 693: IODelay(IPL_TEST_TIME); ! 694: } ! 695: IOGetTimestamp(&curTime); ! 696: usTime = (unsigned)((curTime - lastTime) / 1000ULL); ! 697: if(usTime > 1000) { ! 698: ddm_intr("usTime %d loopNum %d curTime 0x%x lastTime " ! 699: "0x%x\n", ! 700: usTime, loopNum, ! 701: (unsigned)(curTime & 0xffffffffULL), ! 702: (unsigned)(lastTime & 0xffffffffULL), 5); ! 703: } ! 704: lastTime = curTime; ! 705: ! 706: } ! 707: ddm_intr("testIplBug complete; IPL_TEST_TIME %d\n", IPL_TEST_TIME, ! 708: 2,3,4,5); ! 709: ! 710: /* ! 711: * Calibrate the IODelay call... ! 712: * ! 713: for(loopNum=0; loopNum<500; loopNum++) { ! 714: IODelay(IPL_TEST_TIME); ! 715: ddm_intr("IODelay(%d) calibration\n", IPL_TEST_TIME, 2,3,4,5); ! 716: } ! 717: */ ! 718: } ! 719: ! 720: #endif TEST_IPL_BUG
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.