Annotation of Examples/DriverKit/AMDPCSCSIDriver/AMDPCSCSIDriver_reloc.tproj/AMD_ChipPrivate.m, revision 1.1

1.1     ! root        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) */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.