home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Examples / DriverKit / AMDPCSCSIDriver / AMDPCSCSIDriver_reloc.tproj / AMD_x86.m < prev    next >
Text File  |  1996-04-03  |  17KB  |  726 lines

  1. /*     Copyright (c) 1994-1996 NeXT Software, 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.     if(pages > MDL_SIZE) {
  416.         IOLog("%s: DMA Transfer Count Exceeded (%d)\n",
  417.             [self name], byteCount);
  418.         return SR_IOST_MEMALL;
  419.     }
  420.     for(page=0; page<pages; page++) {
  421.         if(page == 0) {
  422.             /*
  423.              * Special case, this one is allowed a page offset.
  424.              */
  425.             offset = virtAddr & AMD_DMA_PAGE_MASK;
  426.             WRITE_REGL(dmaStartAddrs, offset);
  427.             ddm_dma("    page 0 offset 0x%x\n", offset, 2,3,4,5);
  428.             virtAddr = virtAddr & ~AMD_DMA_PAGE_MASK;
  429.         }
  430.         irtn = IOPhysicalFromVirtual(activeCmd->client,
  431.             virtAddr,
  432.             &physAddr);
  433.         if(irtn) {
  434.             IOLog("%s: Can't get physical address (%s)\n", 
  435.                 [self name], [self stringFromReturn:irtn]);
  436.             return SR_IOST_MEMF;
  437.         }
  438.         ddm_dma("    mdl[%d] = 0x%x\n", page, mdl[page], 3,4,5);
  439.         mdl[page] = physAddr;
  440.         virtAddr += AMD_DMA_PAGE_SIZE;
  441.         #if    DDM_DEBUG
  442.         if(page == 0) {
  443.             ddmPhys = (unsigned char *)(physAddr + offset);
  444.         }
  445.         #endif    DDM_DEBUG
  446.     }
  447.     
  448.     /*
  449.      * Load byte count and address of MDL into DMA engine, and go.
  450.      */
  451.     ddm_dma("    dmaStartCount = 0x%x\n", byteCount, 2,3,4,5);
  452.     WRITE_REGL(dmaStartCount, byteCount);
  453.     WRITE_REGL(dmaStartMdlAddrs, mdlPhys);
  454.     if(activeCmd->scsiReq->read) {
  455.         cmd = DC_CMD_START | DC_MDL | DC_DIR_READ;
  456.     }
  457.     else {
  458.         cmd = DC_CMD_START | DC_MDL | DC_DIR_WRITE;
  459.     }
  460.     WRITE_REGL(dmaCommand, cmd);
  461.     #if    WRITE_DMA_COMMAND_TWICE
  462.     WRITE_REGL(dmaCommand, cmd);
  463.     #endif    WRITE_DMA_COMMAND_TWICE
  464.     WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO | SCMD_ENABLEDMA);
  465.     scState = SCS_DMAING;
  466.     return SR_IOST_GOOD;
  467. }
  468.  
  469. /*
  470.  * Terminate a DMA, including FIFO flush if necessary. Returns number of 
  471.  * bytes transferred.
  472.  */
  473. - (unsigned)dmaTerminate
  474. {
  475.     unsigned char     fifoDepth = 0;
  476.     unsigned     cmd;
  477.     int         tries;
  478.     unsigned    status;
  479.     unsigned    bytesXfrd;
  480.     unsigned    scsiXfrCnt;
  481.     unsigned    value;
  482.     
  483.     ASSERT(activeCmd != NULL);
  484.     
  485.     /*
  486.      * Get resid count from SCSI block.
  487.      */
  488.     scsiXfrCnt = READ_REG(currXfrCntLow);
  489.     value = READ_REG(currXfrCntMid);
  490.     scsiXfrCnt += (value << 8);
  491.     value = READ_REG(currXfrCntHi);
  492.     scsiXfrCnt += (value << 16);
  493.     
  494.     fifoDepth = READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK;
  495.     if((activeCmd->scsiReq->read) && (scsiXfrCnt != 0)) {
  496.         /*
  497.          * Make sure SCSI fifo is empty. The manual says we 
  498.          * might have to wait a while.
  499.          */
  500.         if(fifoDepth) {
  501.             IODelay(1000);
  502.             fifoDepth = READ_REG(currFifoState) & 
  503.                 FS_FIFO_LEVEL_MASK;
  504.             switch(fifoDepth) {
  505.                 case 0:
  506.                     ddm_dma("dmaTerminate: fifo cleared\n",
  507.                     1,2,3,4,5);
  508.                     break;        // normal, OK
  509.                 case 1:
  510.                     IOLog("%s: Odd Byte Disconnect on target %d\n",
  511.                     [self name], 
  512.                     activeCmd->scsiReq->target);
  513.                 break;
  514.                 default:
  515.                     IOLog("%s: SCSI FIFO hung\n", [self name]);
  516.                 break;
  517.             
  518.                    /*
  519.                  * I'm not sure what to do about these
  520.                  * errors...
  521.                  */
  522.             }
  523.         }
  524.         if(activeCmd->scsiReq->read) {
  525.             cmd = DC_CMD_BLAST | DC_MDL | DC_DIR_READ;
  526.         }
  527.         else {
  528.             cmd = DC_CMD_BLAST | DC_MDL | DC_DIR_WRITE;
  529.         }
  530.         ddm_dma("   ...sending DMA blast\n", 1,2,3,4,5);
  531.         WRITE_REGL(dmaCommand, cmd);
  532.         #if    WRITE_DMA_COMMAND_TWICE
  533.         WRITE_REGL(dmaCommand, cmd);
  534.         #endif    WRITE_DMA_COMMAND_TWICE
  535.         
  536.         /*
  537.          * Unfortunately, we have to poll for this one. No interrupt.
  538.          * FIXME - documentation is unclear on this. 6.7.6, the 
  539.          * description of dmaStatus, says DS_BLAST_COMPLETE is only 
  540.          * complete for "SCSI Disconnect and Reselect Operation".
  541.          * That doesn't make a whole lot of sense to me...
  542.          */
  543.         for(tries=0; tries<500; tries++) {
  544.             status = READ_REGL(dmaStatus);
  545.             if(status & DS_BLAST_COMPLETE) {
  546.                 break;
  547.             }
  548.             IODelay(100);
  549.         }
  550.         
  551.         ddm_dma("DMA blast : tries = %d fifoDepth = %d\n", 
  552.             tries, fifoDepth, 3,4,5);
  553.     }
  554.     
  555.     /*
  556.      * Obtain number of bytes transferred. 
  557.      */
  558.     bytesXfrd = activeCmd->currentByteCount - 
  559.         (scsiXfrCnt + fifoDepth);
  560.     ddm_chip("dmaTerminate: currentByteCount 0x%x, bytesXfrd 0x%x\n",
  561.         activeCmd->currentByteCount, bytesXfrd, 3,4,5);
  562. #if    0
  563.     {
  564.     unsigned char *vp = activeCmd->buffer;
  565.     
  566.     ddm_init("ddmPhys = %02x %02x %02x %02x %02x\n",
  567.         ddmPhys[0], ddmPhys[1], ddmPhys[2], ddmPhys[3], ddmPhys[4]);
  568.     ddm_init("          %02x %02x %02x %02x %02x\n",
  569.             ddmPhys[5], ddmPhys[6], ddmPhys[7], ddmPhys[8], ddmPhys[9]);
  570.     ddm_init("virt    = %02x %02x %02x %02x %02x\n",
  571.         vp[0], vp[1], vp[2], vp[3], vp[4]);
  572.     ddm_init("          %02x %02x %02x %02x %02x\n",
  573.             vp[5], vp[6], vp[7], vp[8], vp[9]);
  574.     }
  575. #endif    0
  576.     [self dmaIdle];
  577.     return bytesXfrd;
  578. }
  579.  
  580. @end
  581.  
  582. #if    TEST_DEBUG
  583.  
  584. /*
  585.  * Do some simple I/O before IODisk starts probing us.
  586.  */
  587. int    loopTest = 0;
  588. int    target = 0;
  589.  
  590. #define DO_INIT_SLEEP    0
  591. #define DO_TUR        1
  592. #define DO_READ        1
  593. #define TEST_READ_SIZE    1    // in sectors
  594. #define DO_TEST_ALIGN    0
  595. #define TEST_DISCONNECT    1
  596.  
  597. static void testDebug(id driver)
  598. {
  599.     IOSCSIRequest    scsiReq;
  600.     sc_status_t    srtn;
  601.     unsigned char    *rbuf;
  602.     int        block = 100000;
  603.     
  604.     ddm_init("testDebug\n", 1,2,3,4,5);
  605.     if(DO_INIT_SLEEP) {
  606.         IOLog("Sleeping for 10 seconds for DDM view\n");
  607.         IOSleep(10000);
  608.     }
  609.     if(DO_READ) {
  610.         if(DO_TEST_ALIGN) {
  611.             rbuf = IOMallocLow(TEST_READ_SIZE * 512);
  612.             if(rbuf == NULL) {
  613.                 IOLog("IOMallocLow returned NULL!\n");
  614.                 rbuf = IOMalloc(TEST_READ_SIZE * 512);
  615.             }
  616.         }
  617.         else {
  618.             rbuf = IOMalloc(TEST_READ_SIZE * 512);
  619.         }
  620.     }
  621.     do {
  622.         if(DO_TUR) {
  623.             bzero(&scsiReq, sizeof(IOSCSIRequest));
  624.             scsiReq.target = target;
  625.             scsiReq.cmdQueueDisable = 1;
  626.         
  627.             /* 
  628.              * cdb = all zeroes = test unit ready 
  629.              */
  630.             scsiReq.timeoutLength = 4;
  631.             srtn = [driver executeRequest:&scsiReq
  632.                 buffer:NULL
  633.                 client:(vm_task_t)0];
  634.             IOLog("testDebug: TUR result = %s\n",
  635.                 IOFindNameForValue(scsiReq.driverStatus, 
  636.                     IOScStatusStrings));
  637.         }
  638.         
  639.         if(DO_READ) {
  640.             cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
  641.             unsigned i;
  642.  
  643.             bzero(&scsiReq, sizeof(IOSCSIRequest));
  644.             scsiReq.target = target;
  645.             scsiReq.cmdQueueDisable = 1;
  646.             scsiReq.disconnect = TEST_DISCONNECT;
  647.             for(i=0; i<(TEST_READ_SIZE * 512); i++) {
  648.                 rbuf[i] = i;
  649.             }
  650.             cdbp->c6_opcode = 8;
  651.             cdbp->c6_len = TEST_READ_SIZE;
  652.             cdbp->c6_lba0 = block;
  653.             /*
  654.              * Force a disconnect eventually 
  655.              */
  656.             if(block == 0) {
  657.                 block = 100000;    
  658.             }
  659.             else {
  660.                 block = 0;
  661.             }
  662.             scsiReq.maxTransfer = TEST_READ_SIZE * 512;
  663.             scsiReq.read = YES;
  664.             scsiReq.timeoutLength = 10;
  665.             srtn = [driver executeRequest:&scsiReq
  666.                 buffer:rbuf
  667.                 client:IOVmTaskSelf()];
  668.             if(scsiReq.driverStatus == 0) {
  669.                 ddm_init("rbuf = %02x %02x %02x %02x %02x\n",
  670.                    rbuf[0],rbuf[1],rbuf[2],rbuf[3],rbuf[4]);
  671.                 ddm_init("       %02x %02x %02x %02x %02x\n",
  672.                    rbuf[5],rbuf[6],rbuf[7],rbuf[8],rbuf[9]);
  673.             }
  674.             IOLog("testDebug: Read result = %s\n",
  675.                 IOFindNameForValue(scsiReq.driverStatus, 
  676.                     IOScStatusStrings));
  677.         }
  678.         IOSleep(5000);
  679.     } while(loopTest);
  680.     
  681. }
  682.  
  683. #endif    TEST_DEBUG
  684.  
  685. #if    TEST_IPL_BUG
  686.  
  687. #define IPL_TEST_LOOPS    1000000        // # of loops
  688. #define IPL_TEST_TIME    0        // us delay per loop
  689.  
  690. static void testIplBug() {
  691.     int loopNum;
  692.     ns_time_t curTime, lastTime;
  693.     unsigned usTime;
  694.     
  695.     IOGetTimestamp(&lastTime);
  696.     for(loopNum=0; loopNum<IPL_TEST_LOOPS; loopNum++) {
  697.         if(IPL_TEST_TIME) {
  698.             IODelay(IPL_TEST_TIME);
  699.         }
  700.         IOGetTimestamp(&curTime);
  701.         usTime = (unsigned)((curTime - lastTime) / 1000ULL);
  702.         if(usTime > 1000) {
  703.             ddm_intr("usTime %d loopNum %d curTime 0x%x lastTime "
  704.                 "0x%x\n",
  705.                 usTime, loopNum,
  706.                 (unsigned)(curTime & 0xffffffffULL),
  707.                 (unsigned)(lastTime & 0xffffffffULL), 5);
  708.         }
  709.         lastTime = curTime;
  710.         
  711.     }
  712.     ddm_intr("testIplBug complete; IPL_TEST_TIME %d\n", IPL_TEST_TIME,
  713.         2,3,4,5);
  714.         
  715.     /*
  716.      * Calibrate the IODelay call...
  717.      *
  718.     for(loopNum=0; loopNum<500; loopNum++) {
  719.         IODelay(IPL_TEST_TIME);
  720.         ddm_intr("IODelay(%d) calibration\n", IPL_TEST_TIME, 2,3,4,5);
  721.     }
  722.     */
  723. }
  724.  
  725. #endif    TEST_IPL_BUG
  726.