home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer) / NeXT_Developer-3.3.iso / NextDeveloper / Examples / DriverKit / AMDPCSCSIDriver / AMDPCSCSIDriver_reloc.tproj / AMD_ChipPrivate.m < prev    next >
Encoding:
Text File  |  1995-02-10  |  32.0 KB  |  1,274 lines

  1. /*     Copyright (c) 1994 NeXT Computer, Inc.  All rights reserved. 
  2.  *
  3.  * AMD_ChipPrivate.m - methods used only by AMD_Chip module.
  4.  *
  5.  * HISTORY
  6.  * 2 Nov 94    Doug Mitchell at NeXT
  7.  *      Created. 
  8.  */
  9.  
  10. #import "AMD_Chip.h"
  11. #import "AMD_ChipPrivate.h"
  12. #import "AMD_Private.h"
  13. #import "AMD_x86.h"
  14. #import "AMD_Regs.h"
  15. #import "AMD_Types.h"
  16. #import "AMD_ddm.h"
  17. #import "bringup.h"
  18. #import <driverkit/generalFuncs.h>
  19. #import <kernserv/prototypes.h>
  20.  
  21.  
  22. @implementation AMD_SCSI(ChipPrivate)
  23.  
  24. /*
  25.  * Determine if SCSI interrupt is pending.
  26.  */
  27. - (sintPending_t)scsiInterruptPending
  28. {
  29.     unsigned char sstat;
  30.     
  31.     sstat = READ_REG(scsiStat);
  32.     if (sstat & SS_INTERRUPT) {
  33.         return SINT_DEVICE;
  34.     }
  35.     else {
  36.         return SINT_NONE;
  37.     }
  38. }
  39.  
  40. /*
  41.  * Methods invoked upon interrupt. One per legal scState. All assume that 
  42.  * status and interrupt status have been captured in saveStatus and 
  43.  * saveIntrStatus.
  44.  */
  45.  
  46. /*
  47.  * Disconnected - only legal event here is reselection.
  48.  */
  49. - (void)fsmDisconnected
  50. {
  51.     ddm_chip("fsmDisconnected\n", 1,2,3,4,5);
  52.     ASSERT(activeCmd == NULL);
  53.     if(saveIntrStatus & IS_RESELECTED) {
  54.         /*
  55.          * We've been reselected. 
  56.          */
  57.                 
  58.         unsigned char    selectByte;
  59.         unsigned     fifoDepth;
  60.         unsigned char    msg;
  61.     
  62.         /* 
  63.          * Make sure there's a selection byte and an 
  64.          * identify message in the fifo.
  65.          */
  66.         fifoDepth = READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK;
  67.         ddm_chip("reselect: fifoDepth %d\n", fifoDepth, 2,3,4,5);
  68.         if(fifoDepth != 2) {
  69.             ddm_err("reselection, fifoDepth %d\n", fifoDepth, 
  70.                 2,3,4,5);
  71.             IOLog("AMD53C974: Bad FIFO count (%d) on Reselect\n",
  72.                 fifoDepth);
  73.             [self hwAbort:SR_IOST_HW 
  74.                 reason:NULL];
  75.             return;
  76.             
  77.         }
  78.         
  79.         /* 
  80.          * make sure target set his bit.
  81.          */
  82.         if ((selectByte = READ_REG(scsiFifo) &~ (1 << hostId)) == 0) {
  83.             ddm_err("fsmDisconnected: reselection failed"
  84.                 " - no target bit\n", 1,2,3,4,5);
  85.             [self hwAbort:SR_IOST_BV 
  86.                 reason:"No target bit on Reselect"];
  87.             return;
  88.         }
  89.         
  90.         /* 
  91.          * figure out target from bit that's on.
  92.          */
  93.         for (reselTarget = 0; 
  94.              (selectByte & 1) == 0; 
  95.              reselTarget++, selectByte>>=1) {
  96.             continue;
  97.         }
  98.         
  99.         /* 
  100.          * first message byte must be identify.
  101.          */
  102.         msg = READ_REG(scsiFifo);
  103.         if (saveStatus & SS_PARITYERROR) {
  104.             ddm_err("fsmDisconnected: reselected parity error\n",
  105.                 1,2,3,4,5);
  106.             [self hwAbort:SR_IOST_PARITY 
  107.                 reason:"Parity error on Reselect"];
  108.             return;
  109.         }
  110.         if ((msg & MSG_IDENTIFYMASK) == 0) {
  111.             ddm_err("fsmDisconnected: reselection failed - "
  112.                 "bad msg byte (0x%x)\n", msg, 2,3,4,5);
  113.             [self hwAbort:SR_IOST_BV 
  114.                 reason:"Bad ID Message on Reselect"];
  115.             return;
  116.         }
  117.         reselLun = msg & MSG_ID_LUNMASK;
  118.         currMsgInCnt = 0;
  119.         
  120.         /*
  121.          * At this point, the chip is waiting for us to validate 
  122.          * the identify message. If cmd queueing is enabled
  123.          * for this target, the target is waiting to send a queue 
  124.          * tag message, so we have to tell the chip to 
  125.          * drop ACK before we proceed with the reselection.
  126.          *
  127.          * In case of sync mode, we need to load target context right
  128.          * now, before dropping ACK, because the target might go
  129.          * straight to a data in or data out as soon as ACK drops.
  130.          */
  131.         [self targetContext:reselTarget];
  132.         scState = SCS_ACCEPTINGMSG;
  133.         reselPending = 1;
  134.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  135.         WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
  136.         ddm_chip("reselPending: target %d lun %d\n",
  137.             reselTarget, reselLun, 3,4,5);
  138.          
  139.     } else if(saveIntrStatus & IS_SCSIRESET) {
  140.         /*
  141.          * TBD - for now ignore, we get one of these by resetting the
  142.          * chip. If an I/O is pending, it'll probably time out.
  143.          * Maybe we want to return SR_IOST_RESET on the pending 
  144.          * command...
  145.          */
  146.         ddm_chip("fsmDisconnected: ignoring reset interrupt\n",
  147.             1,2,3,4,5);
  148.     } else {
  149.         /* 
  150.          * I'm confused.... 
  151.          */
  152.         [self hwAbort:SR_IOST_BV 
  153.             reason:"bad interrupt while disconnected"];
  154.     }
  155. }
  156.  
  157.  
  158. /*
  159.  * One of three things can happen here - the selection could succeed (though
  160.  * with possible imcomplete message out), it could time out, or we can be 
  161.  * reselected.
  162.  */
  163. #define CATCH_SELECT_TO        1
  164.  
  165. - (void)fsmSelecting
  166. {
  167.     unsigned char fifoDepth;
  168.     unsigned char phase;
  169.     IOSCSIRequest *scsiReq = activeCmd->scsiReq;
  170.     
  171.     ddm_chip("fsmSelecting\n", 1,2,3,4,5);
  172.     ASSERT(activeCmd != NULL);
  173.     if (saveIntrStatus & IS_DISCONNECT) {
  174.         /*
  175.          * selection timed-out. Abort this request.
  176.          */
  177.         #if    CATCH_SELECT_TO
  178.         /* DEBUG ONLY */
  179.         if(scsiReq->cdb.cdb_opcode != C6OP_INQUIRY) {
  180.             IOLog("Unexpected Select Timeout\n");
  181.         }
  182.         #endif    CATCH_SELECT_TO
  183.         ddm_chip("***SELECTION TIMEOUT for target %d\n",
  184.             activeCmd->scsiReq->target, 2,3,4,5);
  185.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  186.         scState = SCS_DISCONNECTED;
  187.         scsiReq->driverStatus = SR_IOST_SELTO;
  188.         [self ioComplete:activeCmd];
  189.         activeCmd = NULL;
  190.     }
  191.     else if(saveIntrStatus == (IS_SUCCESSFUL_OP|IS_SERVICE_REQ)) {
  192.  
  193.         ddm_chip("selection seqstep=%d\n", 
  194.             saveSeqStep & INS_STATE_MASK, 2,3,4,5);
  195.         
  196.         switch (saveSeqStep & INS_STATE_MASK) {
  197.             case 0:    
  198.                 /*
  199.              * No message phase. If we really wanted one,
  200.              * this could be significant...
  201.              */
  202.             if(activeCmd->queueTag != QUEUE_TAG_NONTAGGED) {
  203.                 /*
  204.                  * This target can't do command queueing.
  205.                  */
  206.                 [self disableMode:AM_CmdQueue];
  207.             }    
  208.             if(SDTR_State == SNS_HOST_INIT_NEEDED) {
  209.                 /*
  210.                  * We were trying to do an SDTR.
  211.                  */
  212.                 [self disableMode:AM_Sync];
  213.                 SDTR_State = SNS_NONE;
  214.             }
  215.             
  216.             /*
  217.              * OK, let's try to continue following phase
  218.              * changes.
  219.              */
  220.             scState = SCS_INITIATOR;
  221.             break;
  222.             
  223.             case 3:    /* didn't complete cmd phase, parity? */
  224.             case 4:    /* everything worked */
  225.             case 1:    /* everything worked, SCMD_SELECT_ATN_STOP
  226.                      * case */
  227.             
  228.                 /* 
  229.              * We're connected. Start following the target's phase
  230.              * changes.
  231.              *
  232.              * If we're trying to do sync negotiation,
  233.              * this is the place to do it. In that case, we
  234.              * sent a SCMD_SELECT_ATN_STOP command, and
  235.              * ATN is now asserted (and we're hopefully in
  236.              * msg out phase). We want to send 5 bytes. 
  237.              * Drop them into currMsgOut[] and prime the  
  238.              * msgOutState machine.
  239.              */
  240.             if(SDTR_State == SNS_HOST_INIT_NEEDED) {
  241.                 [self createSDTR:currMsgOut inboundMsg:NULL];
  242.                 currMsgOutCnt = MSG_SDTR_LENGTH;
  243.                 msgOutState = MOS_WAITING;
  244.             }
  245.             scState = SCS_INITIATOR;
  246.             break;
  247.             
  248.             case 2:    
  249.             /*
  250.              * Either no command phase, or imcomplete message
  251.              * transfer.
  252.              */
  253.             fifoDepth = READ_REG(currFifoState) & 
  254.                 FS_FIFO_LEVEL_MASK;
  255.             phase = saveStatus & SS_PHASEMASK;
  256.             ddm_chip("INCOMPLETE SELECT; fifoDepth %d phase %s\n",
  257.                 fifoDepth, 
  258.                 IOFindNameForValue(phase, scsiPhaseValues),
  259.                 3,4,5);
  260.             if(activeCmd->queueTag != QUEUE_TAG_NONTAGGED) {
  261.                 /*
  262.                  * This target can't do command queueing.
  263.                  */
  264.                 [self disableMode:AM_CmdQueue];
  265.             }    
  266.             
  267.             /*
  268.              * Spec says ATN is asserted if all message bytes
  269.              * were not sent.
  270.              */
  271.             if(fifoDepth > activeCmd->cdbLength) {
  272.                 WRITE_REG(scsiCmd, SCMD_CLR_ATN);
  273.             }
  274.             
  275.             /*
  276.              * OK, let's try to continue following phase
  277.              * changes.
  278.              */
  279.             scState = SCS_INITIATOR;
  280.             break;
  281.  
  282.             default:
  283.             [self hwAbort:SR_IOST_HW 
  284.                 reason:"Selection sequence Error"];
  285.             break;
  286.         }
  287.     }
  288.     else if(saveIntrStatus & IS_RESELECTED) {
  289.         /*
  290.          * We got reselected while trying to do a selection. 
  291.          * Enqueue this cmdBuf on the HEAD of pendingQ, then deal
  292.          * with the reselect. 
  293.          * Tricky case, we have to "deactivate" this command
  294.          * since this hwStart attempt failed.  
  295.          */
  296.         queue_enter_first(&pendingQ, activeCmd, commandBuf *, link);
  297.         [self deactivateCmd:activeCmd];
  298.         ddm_chip("reselect while trying to select target %d\n",
  299.             activeCmd->scsiReq->target, 2,3,4,5);
  300.         activeCmd = NULL;
  301.         scState = SCS_DISCONNECTED;
  302.         
  303.         /*
  304.          * Go deal with reselect.
  305.          */
  306.         [self fsmDisconnected];
  307.     }
  308.     else {
  309.         ddm_err("fsmSelecting: Bogus select/reselect interrupt\n", 
  310.             1,2,3,4,5);
  311.         [self hwAbort:SR_IOST_HW 
  312.             reason: "Bogus select/reselect interrupt"];
  313.         return;
  314.     }
  315.     return;
  316. }
  317.  
  318. /*
  319.  * This one is illegal.
  320.  */
  321. - (void)fsmInitiator
  322. {
  323.     ddm_chip("fsmInitiator\n", 1,2,3,4,5);
  324.     [self hwAbort:SR_IOST_HW reason:"Interrupt as Initiator"];
  325. }
  326.  
  327. /*
  328.  * We just did a SCMD_INIT_CMD_CMPLT command, hopefully all that's left is
  329.  * to drop ACK. Command Complete message is handled in fscAcceptingMsg.
  330.  */
  331. - (void)fsmCompleting
  332. {        
  333.     ddm_chip("fsmCompleting\n", 1,2,3,4,5);
  334.     ASSERT(activeCmd != NULL);
  335.     if(saveIntrStatus & IS_DISCONNECT) {
  336.         ddm_err("unexpected completing disconnect\n",
  337.             1,2,3,4,5);
  338.         return;
  339.     }
  340.     if(saveIntrStatus & IS_SUCCESSFUL_OP) {
  341.         /*
  342.          * Got both status and msg in fifo; Ack is still true.
  343.          */
  344.         if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 2) {
  345.             /*
  346.              * This is pretty bogus - we expect a status and 
  347.              * msg in the fifo. 
  348.                 */
  349.             [self hwAbort:SR_IOST_HW reason:"InitComplete fifo"
  350.                 " level"];
  351.             return;
  352.         }
  353.         activeCmd->scsiReq->scsiStatus = READ_REG(scsiFifo);
  354.         currMsgInCnt = 1;
  355.         currMsgIn[0] = READ_REG(scsiFifo);
  356.         ddm_chip("fsmCompleting: status 0x%x msg 0x%x\n",
  357.             activeCmd->scsiReq->scsiStatus, 
  358.             currMsgIn[0], 3,4,5);
  359.         if (saveStatus & SS_PARITYERROR) {
  360.             ddm_err("fsmCompleting: parity error on msg in\n",
  361.                 1,2,3,4,5);
  362.             [self hwAbort:SR_IOST_PARITY 
  363.                 reason:"Parity error on message in"];
  364.             return;
  365.         }
  366.         scState = SCS_ACCEPTINGMSG;
  367.         WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
  368.         return;
  369.     } else {
  370.         /*
  371.          * Must have just got a status byte only. This is kind of
  372.          * weird, but let's try to handle it.
  373.          */
  374.         ddm_err("fsmCompleting: status only on complete\n", 
  375.             1,2,3,4,5);
  376.         if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 1) {
  377.             [self hwAbort:SR_IOST_HW 
  378.                 reason:"Bad Fifo level on Cmd Complete"];
  379.             return;
  380.         }
  381.         activeCmd->scsiReq->scsiStatus = READ_REG(scsiFifo);
  382.         if(saveStatus & SS_PARITYERROR) {
  383.             ddm_err("fsmCompleting: parity error on status\n",
  384.                 1,2,3,4,5);
  385.             [self hwAbort:SR_IOST_PARITY 
  386.                 reason:"Parity Error on Cmd Complete"];
  387.             return;
  388.         }
  389.         
  390.         /*
  391.          * Back to watching phase changes. Why the target isn't in 
  392.          * message in we have yet to find out.
  393.          */
  394.         scState = SCS_INITIATOR;
  395.     }
  396. }
  397.  
  398. /*
  399.  * DMA Complete.
  400.  */
  401. - (void)fsmDMAing
  402. {
  403.     u_int bytesMoved;
  404.     
  405.     ddm_chip("fsmDMAing\n", 1,2,3,4,5);
  406.     ASSERT(activeCmd != NULL);
  407.     
  408.     bytesMoved = [self dmaTerminate];
  409.     if(bytesMoved > activeCmd->currentByteCount) {
  410.         ddm_err("fsmDMAing: DMA transfer count exceeeded\n",
  411.             1,2,3,4,5);
  412.         ddm_err("  expected %d, moved %d\n", 
  413.             activeCmd->currentByteCount, bytesMoved, 3,4,5);
  414.         bytesMoved = activeCmd->currentByteCount;
  415.     }
  416.     ((char *)activeCmd->currentPtr) += bytesMoved;
  417.     activeCmd->currentByteCount     -= bytesMoved; 
  418.     if(saveStatus & SS_PARITYERROR) {
  419.         ddm_err("fsmDMAing: SCSI Data Parity Error\n", 1,2,3,4,5);
  420.         [self hwAbort:SR_IOST_PARITY reason:"SCSI Data Parity Error"];
  421.         return;
  422.     }
  423.     /*
  424.      * Back to watching phase changes.
  425.          */
  426.     scState = SCS_INITIATOR;
  427. }
  428.  
  429. /*
  430.  * Just completed the SCMD_TRANSFER_INFO operation for message in. ACK is
  431.  * still true. Stash the current message byte in currMsgIn[] and proceed to
  432.  * fsmAcceptingMsg after a SCMD_MSG_ACCEPTED.
  433.  */
  434. - (void)fsmGettingMsg
  435. {
  436.     BOOL    setAtn = NO;
  437.     
  438.     ASSERT((activeCmd != NULL) || reselPending);
  439.     if(saveIntrStatus & IS_DISCONNECT) {
  440.         ddm_chip("fsmGettingMsg: message In Disconnect\n", 1,2,3,4,5);
  441.         /*
  442.          * This error is handled on return...
  443.          */
  444.         return;
  445.     }
  446.     if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 1) {
  447.         ddm_chip("Message In fifo error\n", 1,2,3,4,5);
  448.         [self hwAbort:SR_IOST_HW reason:"Message In fifo error"];
  449.         return;
  450.     }
  451.  
  452.     currMsgIn[currMsgInCnt++] = READ_REG(scsiFifo);
  453.     if(currMsgInCnt > AMD_MSG_SIZE) {
  454.         [self hwAbort:SR_IOST_BV 
  455.             reason:"Too Many Message bytes received"];
  456.     }
  457.     if(saveStatus & SS_PARITYERROR) {
  458.         ddm_err("fsmGettingMsg: parity error on Message In\n", 
  459.             1,2,3,4,5);
  460.         [self hwAbort:SR_IOST_PARITY 
  461.             reason:"parity error on Message In"];
  462.         return;
  463.     }
  464.     ddm_chip("fsmGettingMsg: currMsgIn[%d] = 0x%x (%s)\n", currMsgInCnt-1,
  465.         currMsgIn[currMsgInCnt-1],
  466.         IOFindNameForValue(currMsgIn[currMsgInCnt-1], 
  467.             scsiMsgValues),    4,5);
  468.             
  469.     /*
  470.      * Handle special cases. 
  471.      */
  472.      
  473.     /*
  474.      * 1. If this is the last byte of an unsolicited sync negotiation, 
  475.      *    we have to assert ATN right now. The message is actually
  476.      *    fully parsed, and a response SDTR message created, in
  477.      *    fsmAcceptingMsg.
  478.      *
  479.      *    This parsing is pretty crude; if we come up with other special 
  480.      *    cases, we might rewrite this or come up with some state variables
  481.      *    to help us.
  482.      */
  483.     if((currMsgInCnt >= MSG_SDTR_LENGTH) && (SDTR_State == SNS_NONE)) {
  484.     
  485.         int start = currMsgInCnt - MSG_SDTR_LENGTH;
  486.         
  487.         if((currMsgIn[start] == MSG_EXTENDED) &&
  488.            (currMsgIn[start+1] == (MSG_SDTR_LENGTH - 2)) &&
  489.            (currMsgIn[start+2] == MSG_SDTR)) {
  490.                ddm_chip("UNSOLICITED SDTR IN; setting ATN\n",
  491.                  1,2,3,4,5);
  492.             WRITE_REG(scsiCmd, SCMD_SET_ATN);
  493.             setAtn = YES;
  494.             SDTR_State = SNS_TARGET_INIT;
  495.         }
  496.     }
  497.  
  498.     /*
  499.      * 2. If this was a message reject, it's possible that an extended
  500.      *    message out was prematurely aborted, with ATN still true.
  501.      *    Clear it so we don't do another (needless) message out.
  502.      *    Avoid this, of course, if we set ATN in this method for 
  503.      *    any reason.
  504.      */
  505.     if((currMsgIn[currMsgInCnt - 1] == MSG_MSGREJECT) && 
  506.        (currMsgOutCnt > 1) &&
  507.        !setAtn) {
  508.         ddm_chip("fsmGettingMsg: Message Reject; clearing ATN\n",
  509.             1,2,3,4,5);
  510.         WRITE_REG(scsiCmd, SCMD_CLR_ATN);
  511.     }
  512.     
  513.     /*
  514.      * No need to clear FIFO; its depth was one on entry, and we read
  515.      * the byte. Note that clearing FIFO after the SCS_ACCEPTINGMSG
  516.      * might disturb possible sync data in transfer.
  517.      */
  518.     WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
  519.     scState = SCS_ACCEPTINGMSG;
  520.  
  521. }
  522.  
  523. /*
  524.  * Just finished a message in; Ack is false. If phase is still
  525.  * message in, we're in the midst of an extended message or additional
  526.  * message bytes on reselect. Otherwise, message in is complete;
  527.  * process currMsgIn[].
  528.  */
  529. - (void)fsmAcceptingMsg
  530. {
  531.     unsigned char     phase = saveStatus & SS_PHASEMASK;
  532.     unsigned     index;
  533.     perTargetData    *perTargetPtr;
  534.     
  535.     ddm_chip("fsmAcceptingMsg: phase %s\n", 
  536.         IOFindNameForValue(phase, scsiPhaseValues), 2,3,4,5);
  537.     if((phase == PHASE_MSGIN) && !(saveIntrStatus & IS_DISCONNECT)) {
  538.     
  539.         /*
  540.          * More message bytes to follow.
  541.          * We have to qualify with !IS_DISCONNECT to cover the 
  542.          * case of some targets (like the Exabyte tape drive)
  543.          * which bogusly keep CD, IO, and MSG asserted after
  544.          * they drop BSY upon command complete.
  545.          */
  546.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  547.         WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
  548.         scState = SCS_GETTINGMSG; 
  549.         return;
  550.     }
  551.     
  552.     /*
  553.      * Message in complete. Handle message(s) in currMsgIn[].
  554.      */
  555.     if(reselPending) {
  556.     
  557.         /*
  558.          * We're expecting either:
  559.          * -- no messages, or 
  560.          * -- queue tag and/or Save Pointers.
  561.          */
  562.         unsigned char tag = QUEUE_TAG_NONTAGGED;
  563.         
  564.         ASSERT(activeCmd == NULL);
  565.         for(index=0; index<currMsgInCnt; index++) {
  566.             switch(currMsgIn[index]) {
  567.             case MSG_RESTOREPTRS:
  568.                 ddm_chip("unnecessary restore pointers\n",
  569.                     1,2,3,4,5);
  570.                 continue;    /* to next message */
  571.                 
  572.             case MSG_SIMPLE_QUEUE_TAG:
  573.                 if(index == (currMsgInCnt-1)) {
  574.                 [self hwAbort: SR_IOST_BV
  575.                     reason:"Queue tag message, no tag"];
  576.                 return;
  577.                 }
  578.                 tag = currMsgIn[++index];
  579.                 break;
  580.                 
  581.             /*
  582.              * handle others here...?
  583.              */
  584.             default:
  585.                 IOLog("AMD53C974: bad msg (0x%x) after identify\n",
  586.                     currMsgIn[index]);
  587.                 [self hwAbort: SR_IOST_BV reason:NULL];
  588.                 return;
  589.             }
  590.         }
  591.             
  592.         if([self reselect:reselTarget 
  593.                     lun:reselLun 
  594.                 queueTag:tag] == YES) {
  595.             /*
  596.              * Found a disconnected commandBuf to reconnect.
  597.              *
  598.              * IDENTIFY msg implies restore ptrs.
  599.              */
  600.             reselPending = 0;
  601.             ASSERT(activeCmd != NULL);
  602.             activeCmd->currentPtr = activeCmd->savedPtr;
  603.             activeCmd->currentByteCount =  
  604.                 activeCmd->savedByteCount;
  605.             scState = SCS_INITIATOR;
  606.             return;
  607.         }
  608.         else {
  609.             IOLog("AMD53C974: Illegal reselect (target %d lun "
  610.                 "%d tag %d)\n", reselTarget, reselLun, tag);
  611.             [self hwAbort: SR_IOST_BV 
  612.                 reason:NULL];
  613.             return;
  614.         }
  615.     }    /* reselect pending */
  616.     
  617.     /*
  618.      * Handle all other messages.
  619.      */
  620.     ASSERT(activeCmd != NULL);
  621.     perTargetPtr = &perTarget[activeCmd->scsiReq->target];
  622.     for(index=0; index<currMsgInCnt; index++) {
  623.         switch(currMsgIn[index]) {
  624.         case MSG_CMDCMPLT:
  625.             /*
  626.              * Bus really should be free; we came here from 
  627.              * fsmCompleting.
  628.              */
  629.             if(!(saveIntrStatus & IS_DISCONNECT)) {
  630.                 ddm_err("fsmAcceptingMsg: Command Complete"
  631.                     " but no Disconnect\n", 1,2,3,4,5);
  632.                 [self hwAbort:SR_IOST_BV 
  633.                     reason:"No Disconnect On Command"
  634.                         " Complete"];
  635.                 return;
  636.             }
  637.             
  638.             /*
  639.              * TA DA!
  640.              */
  641.             scState = SCS_DISCONNECTED;
  642.             activeCmd->scsiReq->driverStatus = SR_IOST_GOOD;
  643.             [self ioComplete:activeCmd];
  644.             activeCmd = NULL;
  645.             return;
  646.         
  647.         case MSG_DISCONNECT:
  648.             /*
  649.              * This could be in fsmGettingMsg, where we could 
  650.              * handle it gracefully by doing a MSGREJ, but this
  651.              * is such a bogus error that we'll just reset the
  652.              * offender.
  653.              */
  654.             if(!activeCmd->discEnable) {
  655.                 ddm_chip("***Illegal Disconnect attempt\n",
  656.                     1,2,3,4,5);
  657.                 IOLog("AMD53C974: Illegal disconnect attempt"
  658.                     " on target %d\n",
  659.                     activeCmd->scsiReq->target);
  660.                 [self hwAbort:SR_IOST_BV
  661.                     reason:NULL];
  662.                 return;
  663.             }
  664.             scState = SCS_DISCONNECTED;
  665.             [self disconnect];
  666.             return;
  667.  
  668.         case MSG_SAVEPTRS:
  669.             activeCmd->savedPtr = activeCmd->currentPtr;
  670.             activeCmd->savedByteCount = 
  671.                 activeCmd->currentByteCount;
  672.             break;
  673.             
  674.         case MSG_RESTOREPTRS:
  675.             activeCmd->currentPtr = activeCmd->savedPtr;
  676.             activeCmd->currentByteCount = 
  677.                 activeCmd->savedByteCount;
  678.             break;
  679.                 
  680.         case MSG_MSGREJECT:
  681.             /*
  682.              * look at last message sent; may have to 
  683.              * disable sync or cmd queue mode for this target.
  684.              * This assumes that we don't send SDTR and queue tag
  685.              * in the same message.
  686.              */
  687.             ddm_chip("fsmAcceptingMsg: MESSAGE REJECT RECEIVED "
  688.                 "from target %d\n", 
  689.                 activeCmd->scsiReq->target, 2,3,4,5);
  690.             if(currMsgOutCnt == 0) {
  691.                 /*
  692.                  * Huh? We haven't sent a message recently...
  693.                  */
  694.                 [self hwAbort:SR_IOST_BV
  695.                     reason:"Unexpected Message Reject"];
  696.                 return;
  697.             }
  698.             switch(currMsgOut[0]) {
  699.             case MSG_SIMPLE_QUEUE_TAG:    
  700.                 [self disableMode:AM_CmdQueue];
  701.                 break;
  702.             case MSG_EXTENDED:
  703.                 /*
  704.                  * Only one we ever send is sync negotiation..
  705.                  */
  706.                 if(currMsgOut[2] == MSG_SDTR) {
  707.                     [self disableMode:AM_Sync];
  708.                 SDTR_State = SNS_NONE;
  709.                 break;
  710.                 }
  711.                 else {
  712.                 [self hwAbort:SR_IOST_INT
  713.                     reason:"Currupted Message Buffer"];
  714.                 return;
  715.                 }
  716.             default:
  717.                 IOLog("AMD53C974: %s Message Rejected\n",
  718.                     IOFindNameForValue(currMsgOut[0], 
  719.                     scsiMsgValues));
  720.                 /* oh well... */
  721.                 break;
  722.             }
  723.             
  724.             /*
  725.              * In any case, we're definitely thru with the 
  726.              * outbound message buffer.
  727.              */
  728.             currMsgOutCnt = 0;
  729.             break;
  730.             
  731.         case MSG_LNKCMDCMPLT:
  732.         case MSG_LNKCMDCMPLTFLAG:
  733.             /*
  734.              * This should never happen, because hwStart trashes
  735.              * commands with the LINK bit on.
  736.              */
  737.             [self hwAbort:SR_IOST_BV reason:"Linked command"];
  738.             return;
  739.             
  740.         case MSG_EXTENDED:
  741.             /*
  742.              * The only valid one is sync negotiation....
  743.              */
  744.             switch(currMsgIn[index+2]) {
  745.             case MSG_SDTR:
  746.                 if(currMsgIn[index+1] != (MSG_SDTR_LENGTH-2)) {
  747.                 [self hwAbort:SR_IOST_BV 
  748.                     reason:"Bad Extended Msg Length"];
  749.                 return;
  750.                 }
  751.                 switch(SDTR_State) {
  752.                     case SNS_HOST_INIT:
  753.                     /* 
  754.                      * Just completed SDTR that we initiated.
  755.                      */
  756.                     if([self parseSDTR:&currMsgIn[index]] 
  757.                             == NO) {
  758.                     [self hwAbort:SR_IOST_HW 
  759.                         reason:"Bad SDTR Parameters"];
  760.                     return;
  761.                     }
  762.                    
  763.                    /*
  764.                     * Successful SDTR. 
  765.                     */
  766.                     ddm_chip("host-init SDTR COMPLETE\n", 
  767.                     1,2,3,4,5);
  768.                     SDTR_State = SNS_NONE;
  769.                     break;
  770.                 
  771.                 case SNS_TARGET_INIT:
  772.                     /*
  773.                      * Target-initiated negotiaited. This
  774.                      * was detected in fsmGettingMsg, where
  775.                      * we set ATN true.
  776.                      * Cons up a response and prime the message 
  777.                      * out state machine to send it.
  778.                      */
  779.                     [self createSDTR : currMsgOut
  780.                         inboundMsg : &currMsgIn[index]];
  781.                     currMsgOutCnt = MSG_SDTR_LENGTH;
  782.                     msgOutState = MOS_WAITING;
  783.                     break;
  784.                    
  785.                 default:
  786.                     IOPanic("AMD53C974: Bad SDTR_State");
  787.                 }
  788.                 
  789.                 /*
  790.                  * Skip over the rest of this message; index
  791.                  * should point to the last byte of this message.
  792.                  */
  793.                 index += (MSG_SDTR_LENGTH - 1);
  794.                 break;
  795.     
  796.             default:
  797.                 IOLog("AMD53C974: Unexpected Extended Message "
  798.                     "(0x%x) Received\n",
  799.                     currMsgIn[index+2]);
  800.                 [self hwAbort:SR_IOST_BV reason:NULL];
  801.                 return;
  802.             }    
  803.             break;
  804.                     
  805.         default:
  806.             /*
  807.              * all others are unacceptable. 
  808.              */
  809.             IOLog("AMD53C974: Illegal message (0x%x)\n", 
  810.                 currMsgIn[index]);
  811.             [self messageOut:MSG_MSGREJECT];
  812.         } 
  813.     } /* for index */
  814.     
  815.     /*
  816.      * Default case for 'break' from above switch - back to following 
  817.      * phase changes.
  818.      */
  819.     scState = SCS_INITIATOR;
  820. }
  821.  
  822. /*
  823.  * Just completed the SCMD_TRANSFER_INFO operation for message out. 
  824.  */
  825. - (void)fsmSendingMsg
  826. {
  827.     ddm_chip("fsmSendingMsg\n", 1,2,3,4,5);
  828.     ASSERT(activeCmd != NULL);
  829.     scState = SCS_INITIATOR;
  830.     if(SDTR_State == SNS_TARGET_INIT) {
  831.         /*
  832.          * If the message we just sent was a SDTR, we've just 
  833.          * completed a target-initiated SDTR sequence. 
  834.          * Note this assumes that an outbound SDTR in this 
  835.          * situation is the only message in currMsgOut[].
  836.          * This will have to change if we send a queue tag and
  837.          * SDTR in the sqame message.
  838.          */
  839.         if((currMsgOutCnt == MSG_SDTR_LENGTH) &&
  840.            (currMsgOut[0] == MSG_EXTENDED) &&
  841.            (currMsgOut[1] == (MSG_SDTR_LENGTH - 2)) &&
  842.            (currMsgOut[2] == MSG_SDTR)) {
  843.             
  844.              ddm_chip("fsmSendingMsg: target-init SDTR complete\n",
  845.                 1,2,3,4,5);
  846.             if([self parseSDTR:currMsgOut] == NO) {
  847.                 /*
  848.                  * Shouldn't fail; we generated this 
  849.                  * message ourself...
  850.                  */
  851.                 IOPanic("AMD53C974: SDTR Problem\n");
  852.             }
  853.             SDTR_State = SNS_NONE;
  854.         }
  855.     }
  856. }
  857.  
  858.  
  859. /*
  860.  * Just completed the SCMD_TRANSFER_INFO operation for command.
  861.  */
  862. - (void)fsmSendingCmd
  863. {
  864.     ddm_chip("fsmSendingCmd\n", 1,2,3,4,5);
  865.     ASSERT(activeCmd != NULL);
  866.     scState = SCS_INITIATOR;
  867. }
  868.  
  869. /*
  870.  * Follow SCSI Phase change. Called while SCS_INITIATOR. 
  871.  */
  872. - (void)fsmPhaseChange
  873. {
  874.     int         phase;
  875.     char         *cp;
  876.     cdb_t         *cdbp;
  877.     int         i;
  878.     sc_status_t     rtn;
  879.     
  880.     ddm_chip("fsmPhaseChange\n", 1,2,3,4,5);
  881.     ASSERT(activeCmd != NULL);
  882.  
  883.     /*
  884.      * Advance msg out state machine -- SCSI spec says if
  885.      * we do a msg out phase and then see another phase
  886.      * we can assume msg was transmitted without error.
  887.      * However, if we're in msg in, we may have a message reject
  888.      * coming in, so we'll keep currMsgOut[] valid in that case.
  889.      *
  890.      * FIXME - one case which this would not cover is the queue tag
  891.      * message saved in currMsgOut[] during selection. We don't 
  892.      * go to MOS_SAWMSGOUT in that case. problem?
  893.      */
  894.     phase = saveStatus & SS_PHASEMASK;
  895.     if ((phase != PHASE_MSGOUT) &&
  896.         (phase != PHASE_MSGIN) &&
  897.         (msgOutState == MOS_SAWMSGOUT)) {
  898.         msgOutState = MOS_NONE;
  899.         currMsgOutCnt = 0;
  900.     }
  901.  
  902.     /*
  903.      * If we just sent a host-initiated SDTR and the target went 
  904.      * to something other than phase in, we assume that the negotiation
  905.      * failed. This is in violation of the spec, but the Sony CDROM 
  906.      * does this.
  907.      */
  908.     if((SDTR_State == SNS_HOST_INIT) && (phase != PHASE_MSGIN)) {
  909.         ddm_chip("IMPLIED SNS_HOST_INIT Reject\n", 1,2,3,4,5);
  910.                [self disableMode:AM_Sync];
  911.         SDTR_State = SNS_NONE;
  912.     }
  913.     
  914.     /* 
  915.      * make sure we start off with a clean slate.
  916.      *
  917.      * NO - this can disturb possible sync data in! We'll need to cover
  918.      * this in individual cases elsewhere...
  919.      */
  920.     /* WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO); */
  921.     ddm_chip("fsmPhaseChange:  phase = %s\n", 
  922.         IOFindNameForValue(phase, scsiPhaseValues), 2,3,4,5);
  923.  
  924.     switch (phase) {
  925.  
  926.         case PHASE_COMMAND:
  927.             /*
  928.          * The normal case here is after a host-initiated SDTR
  929.          * sequence. 
  930.          */
  931.         ddm_chip("fsmPhaseChange: command phase\n", 1,2,3,4,5);
  932.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  933.         cdbp = &activeCmd->scsiReq->cdb;
  934.         cp = (char *)cdbp;
  935.         for(i=0; i<activeCmd->cdbLength; i++) {
  936.             WRITE_REG(scsiFifo, *cp++);
  937.         }
  938.  
  939. #if    0
  940.         /*
  941.          * This causes extra bytes to sit around in the fifo
  942.          * if we go straight to data phase after this, and
  943.          * we can't clear the fifo at that time in case
  944.          * we're in sync data in...
  945.          */
  946.         /*
  947.          * fill fifo to avoid spurious command phase for target
  948.          * chips that try to get max command length
  949.          */
  950.         for (i = 12 - activeCmd->cdbLength; i > 0; i--)
  951.             WRITE_REG(scsiFifo, 0);
  952. #endif    0
  953.         WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
  954.         scState = SCS_SENDINGCMD;
  955.         break;
  956.  
  957.         case PHASE_DATAOUT:    /* To Target from Initiator (write) */
  958.         if(activeCmd->scsiReq->read) {
  959.             [self hwAbort:SR_IOST_BV reason:"bad i/o direction"];
  960.             break;
  961.         }
  962.         if(rtn = [self dmaStart]) {
  963.             [self hwAbort:rtn 
  964.                 reason: IOFindNameForValue(rtn, 
  965.                     IOScStatusStrings)];
  966.             break;
  967.         }
  968.         break;
  969.         
  970.         case PHASE_DATAIN:    /* From Target to Initiator (read) */
  971.         if(!activeCmd->scsiReq->read) {
  972.             [self hwAbort:SR_IOST_BV reason:"bad i/o direction"];
  973.             break;
  974.         }
  975.         if(rtn = [self dmaStart]) {
  976.             [self hwAbort:rtn 
  977.                 reason: IOFindNameForValue(rtn, 
  978.                     IOScStatusStrings)];
  979.             break;
  980.         }
  981.         break;
  982.     
  983.         case PHASE_STATUS:    /* Status from Target to Initiator */
  984.         /*
  985.          * fsmCompleting will collect the STATUS byte
  986.          * (and hopefully a MSG) from the fifo when this
  987.          * completes.
  988.          */
  989.         scState = SCS_COMPLETING;
  990.         currMsgInCnt = 0;
  991.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  992.         WRITE_REG(scsiCmd, SCMD_INIT_CMD_CMPLT);
  993.         break;
  994.         
  995.         case PHASE_MSGIN:    /* Message from Target to Initiator */
  996.         scState = SCS_GETTINGMSG;
  997.         currMsgInCnt = 0;
  998.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  999.         WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
  1000.         break;
  1001.         
  1002.         case PHASE_MSGOUT:    /* Message from Initiator to Target */
  1003.             WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  1004.         if(msgOutState == MOS_WAITING) {
  1005.             int i;
  1006.             
  1007.             ASSERT(currMsgOutCnt != 0);
  1008.             for(i=0; i<currMsgOutCnt; i++) {
  1009.                 ddm_chip("msg out: writing 0x%x\n",
  1010.                     currMsgOut[i], 2,3,4,5);
  1011.                 WRITE_REG(scsiFifo, currMsgOut[i]);
  1012.             }
  1013.             msgOutState = MOS_SAWMSGOUT;
  1014.             if(SDTR_State == SNS_HOST_INIT_NEEDED) {
  1015.                 /*
  1016.                  * sending SDTR message after select.
  1017.                  */
  1018.                 ASSERT(currMsgOut[0] == MSG_EXTENDED);
  1019.                 ASSERT(currMsgOut[2] == MSG_SDTR);
  1020.                 ASSERT(currMsgOutCnt == MSG_SDTR_LENGTH);
  1021.                 ddm_chip("going to SNS_HOST_INIT\n",
  1022.                     1,2,3,4,5);
  1023.                 SDTR_State = SNS_HOST_INIT;
  1024.             }
  1025.         } else {
  1026.             /*
  1027.              * Target went to msg out and we don't have
  1028.              * anything to send!  Just give it a nop.
  1029.              */
  1030.             ddm_chip("msg out: sending MSG_NOP\n", 1,2,3,4,5);
  1031.             WRITE_REG(scsiFifo, MSG_NOP);
  1032.         }
  1033.  
  1034.         scState = SCS_SENDINGMSG;
  1035.         /* 
  1036.          * ATN is automatically cleared when transfer info completes.
  1037.          */
  1038.         WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
  1039.         break;
  1040.         
  1041.         default:
  1042.             [self hwAbort:SR_IOST_HW reason:"Bad SCSI phase"];
  1043.         break;
  1044.     }
  1045. }
  1046.  
  1047. /*
  1048.  * Set up to send single-byte message. 
  1049.  */ 
  1050. - (void) messageOut : (u_char)msg
  1051. {
  1052.     ddm_chip("messageOut (0x%x)\n", msg, 2,3,4,5);
  1053.     currMsgOut[0] = msg;
  1054.     currMsgOutCnt = 1;
  1055.     msgOutState = MOS_WAITING;
  1056.     WRITE_REG(scsiCmd, SCMD_SET_ATN);
  1057. }
  1058.  
  1059.  
  1060. /*
  1061.  * Load syncPeriod, syncOffset for activeCmd per perTarget values.
  1062.  */
  1063. - (void)targetContext : (unsigned) target
  1064. {
  1065.     perTargetData *perTargetPtr;
  1066.     
  1067.     perTargetPtr = &perTarget[target];
  1068.     if(!syncModeEnable || 
  1069.        perTargetPtr->syncDisable ||
  1070.        (perTargetPtr->syncXferOffset == 0)) {
  1071.         /*
  1072.          * Easy case, async.
  1073.          */
  1074.         WRITE_REG(syncOffset, 0);
  1075.         ddm_chip("targetContext(%d): ASYNC\n", target, 2,3,4,5);
  1076.         #ifdef    DEBUG
  1077.         syncOffsetShadow = 0;
  1078.         #endif    DEBUG
  1079.     }
  1080.     else {
  1081.         unsigned char periodReg;
  1082.         unsigned char offsetReg;
  1083.         
  1084.         periodReg = nsPeriodToSyncPeriodReg(
  1085.             perTargetPtr->syncXferPeriod,
  1086.             fastModeEnable, scsiClockRate);
  1087.         WRITE_REG(syncPeriod, periodReg);
  1088.         
  1089.         /*
  1090.          * FIXME - might eventually want to use non-default
  1091.          * values for RAD and RAA...
  1092.          */
  1093.         offsetReg = (perTargetPtr->syncXferOffset |
  1094.             SOR_RAD_DEFAULT | SOR_RAA_DEFAULT);
  1095.         WRITE_REG(syncOffset, offsetReg);
  1096.         ddm_chip("targetContext(%d): period 0x%x offset %d\n",
  1097.             target, periodReg, offsetReg, 4,5);
  1098.         #ifdef    DEBUG
  1099.         syncOffsetShadow = offsetReg;
  1100.         syncPeriodShadow = periodReg;
  1101.         #endif    DEBUG
  1102.     }
  1103. }
  1104.  
  1105. /*
  1106.  * Parse and validate 5-byte SDTR message. If valid, save in perTarget 
  1107.  * and in hardware. Returns YES if valid, else NO.
  1108.  * 
  1109.  * Specified message buffer could be from either currMsgIn[] or 
  1110.  * currMsgOut[].
  1111.  */
  1112. - (BOOL)parseSDTR    : (unsigned char *)sdtrMessage
  1113. {
  1114.     unsigned nsPeriod;
  1115.     unsigned char fastClock;
  1116.     unsigned minPeriod;
  1117.     perTargetData *perTargetPtr;
  1118.     
  1119.     ASSERT(activeCmd != NULL);
  1120.     perTargetPtr = &perTarget[activeCmd->scsiReq->target];
  1121.     
  1122.     if(sdtrMessage[0] != MSG_EXTENDED) {
  1123.         goto Bad;
  1124.     }
  1125.     if(sdtrMessage[1] != (MSG_SDTR_LENGTH - 2)) {
  1126.         goto Bad;
  1127.     }
  1128.     if(sdtrMessage[2] != MSG_SDTR) {
  1129.         goto Bad;
  1130.     }
  1131.     
  1132.     /*
  1133.      * period
  1134.      */
  1135.     nsPeriod = SDTR_TO_NS_PERIOD(sdtrMessage[3]);
  1136.     fastClock = READ_REG(control3) & CR3_FAST_CLOCK;
  1137.     if(fastClock && fastModeEnable) {
  1138.         minPeriod = MIN_PERIOD_FASTCLK_FASTSCSI;
  1139.     }
  1140.     else {
  1141.         minPeriod = MIN_PERIOD_NORM;
  1142.     }
  1143.     if(nsPeriod < minPeriod) {
  1144.         goto Bad;
  1145.     }
  1146.     perTargetPtr->syncXferPeriod = nsPeriod;
  1147.     
  1148.     /*
  1149.      * Offset
  1150.      */
  1151.     if(sdtrMessage[4] > AMD_MAX_SYNC_OFFSET) {
  1152.         goto Bad;
  1153.     }
  1154.     perTargetPtr->syncXferOffset = sdtrMessage[4];
  1155.     
  1156.     /*
  1157.      * Success.
  1158.      */
  1159.     perTargetPtr->syncDisable = 0;
  1160.     perTargetPtr->syncNegotNeeded = 0;
  1161.     [self targetContext:activeCmd->scsiReq->target];
  1162.     
  1163.     ddm_chip("parseSDTR SUCCESS: %02x %02x %02x %02x %02x\n",
  1164.         sdtrMessage[0], sdtrMessage[1], sdtrMessage[2], 
  1165.         sdtrMessage[3], sdtrMessage[4]);
  1166.     ddm_chip("   period %d offset %d\n", perTargetPtr->syncXferPeriod,
  1167.         perTargetPtr->syncXferOffset, 3,4,5);
  1168.     return YES;
  1169.     
  1170. Bad:
  1171.     ddm_chip("parseSDTR FAIL: 02%x %02x %02x %02x %02x\n",
  1172.         sdtrMessage[0], sdtrMessage[1], sdtrMessage[2], 
  1173.         sdtrMessage[3], sdtrMessage[4]);
  1174.     return NO;
  1175. }
  1176.  
  1177. /*
  1178.  * Cons up a SDTR message appropriate for both our hardware and a possible
  1179.  * target-generated SDTR message. If inboundMsg is NULL, we just use
  1180.  * the parameters we want.
  1181.  */
  1182. - (void)createSDTR        : (unsigned char *)outboundMsg    // required
  1183.              inboundMsg : (unsigned char *)inboundMsg
  1184. {
  1185.     unsigned     desiredNsPeriod;
  1186.     unsigned     inboundNsPeriod;
  1187.     unsigned     offset = AMD_MAX_SYNC_OFFSET;
  1188.     unsigned char     fastClock;
  1189.     
  1190.     outboundMsg[0] = MSG_EXTENDED;
  1191.     outboundMsg[1] = MSG_SDTR_LENGTH - 2;
  1192.     outboundMsg[2] = MSG_SDTR;
  1193.     
  1194.     /*
  1195.      * period
  1196.      */
  1197.     fastClock = READ_REG(control3) & CR3_FAST_CLOCK;
  1198.     if(fastClock && fastModeEnable) {
  1199.         desiredNsPeriod = MIN_PERIOD_FASTCLK_FASTSCSI;
  1200.     }
  1201.     else {
  1202.         desiredNsPeriod = MIN_PERIOD_NORM;
  1203.     }
  1204.     if(inboundMsg) {
  1205.         inboundNsPeriod = SDTR_TO_NS_PERIOD(inboundMsg[3]);
  1206.     }
  1207.     else {
  1208.         inboundNsPeriod = desiredNsPeriod;
  1209.     }
  1210.     if(inboundNsPeriod > desiredNsPeriod) {
  1211.         /*
  1212.          * Target is slower than us
  1213.          */
  1214.         desiredNsPeriod = inboundNsPeriod;
  1215.     }
  1216.     outboundMsg[3] = NS_PERIOD_TO_SDTR(desiredNsPeriod);
  1217.     
  1218.     /*
  1219.      * Offset
  1220.      */
  1221.     if(inboundMsg) {
  1222.         offset = inboundMsg[4];
  1223.         if(offset > AMD_MAX_SYNC_OFFSET) {
  1224.             /* 
  1225.              * target's buffer smaller than ours
  1226.              */
  1227.             offset = AMD_MAX_SYNC_OFFSET;
  1228.         }
  1229.     }
  1230.     outboundMsg[4] = offset;
  1231.     
  1232.     ddm_chip("createSDTR: %02x %02x %02x %02x %02x\n",
  1233.         outboundMsg[0], outboundMsg[1], outboundMsg[2], 
  1234.         outboundMsg[3], outboundMsg[4]);
  1235.     ddm_chip("   period %d   offset %d\n", desiredNsPeriod, offset, 3,4,5);
  1236. }
  1237.  
  1238. /*
  1239.  * Disable specified mode for activeCmd's target. If mode is currently 
  1240.  * enabled, we'll log a message to the console.
  1241.  */
  1242. - (void)disableMode : (AMD_Mode)mode
  1243. {
  1244.     int target;
  1245.     perTargetData *perTargetPtr;
  1246.     const char *modeStr = NULL;
  1247.     
  1248.     ASSERT(activeCmd != NULL);
  1249.     target = activeCmd->scsiReq->target;
  1250.     perTargetPtr = &perTarget[target];
  1251.     switch(mode) {
  1252.         case AM_Sync:
  1253.             if(perTargetPtr->syncDisable == 0) {
  1254.             perTargetPtr->syncDisable = 1;
  1255.             modeStr = "Synchronous Transfer Mode";
  1256.         }
  1257.         [self targetContext:activeCmd->scsiReq->target];
  1258.         break;
  1259.         case AM_CmdQueue:
  1260.             if(perTargetPtr->cmdQueueDisable == 0) {
  1261.             perTargetPtr->cmdQueueDisable = 1;
  1262.             modeStr = "Command Queueing";
  1263.         }
  1264.         break;
  1265.     }
  1266.     ddm_chip("DISABLING %s for target %d\n", modeStr, target, 3,4,5);
  1267.     if(modeStr) {
  1268.         IOLog("AMD53C974: DISABLING %s for target %d\n", 
  1269.             modeStr, target);
  1270.     }
  1271. }
  1272.  
  1273. @end    /* AMD_SCSI(ChipPrivate) */
  1274.