Annotation of kernel/bsd/dev/ppc/drvSymbios8xx/Sym8xxClient.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* Sym8xxClient.m created by russb2 on Sat 30-May-1998 */
        !            26: 
        !            27: #import "Sym8xxController.h"
        !            28: 
        !            29: static u_int8_t                xferMsgSync[]   = {0x01, 0x03, 0x01, 0x0c, 0x10};
        !            30: static u_int8_t                xferMsgAsync[]  = {0x01, 0x03, 0x01, 0x00, 0x00};
        !            31: static u_int8_t                xferMsgWide16[] = {0x01, 0x02, 0x03, 0x01};
        !            32: static u_int8_t        cdbLength[8]    = { 6, 10, 10, 0, 0, 12, 0, 0 };
        !            33: 
        !            34: @implementation Sym8xxController(Client)
        !            35: 
        !            36: /*-----------------------------------------------------------------------------*
        !            37:  *  Client thread routines.
        !            38:  *
        !            39:  *  This module processes I/O requests from driverKit. It does most of the resource 
        !            40:  *  allocation and command preparation. Once a command is prepared it is queued
        !            41:  *  to the driver's I/O Thread for execution.
        !            42:  *
        !            43:  *-----------------------------------------------------------------------------*/
        !            44: - (sc_status_t) executeRequest:(IOSCSIRequest *)scsiReq  buffer:(void *)buffer  client:(vm_task_t)client
        !            45: {
        !            46:     SRB                        *srb;
        !            47:     Nexus              *nexus, *nexusPhys;
        !            48:     u_int32_t          len;
        !            49:     ns_time_t          startTime, endTime;
        !            50: 
        !            51:     IOGetTimestamp( &startTime );
        !            52: 
        !            53:     /*
        !            54:      * If a SCSI Bus reset is detected, we hold-off command processing until the targets have
        !            55:      * had a chance to recover.
        !            56:      */
        !            57:     while ( resetQuiesceTimer )
        !            58:     {
        !            59:         [resetQuiesceSem lock];
        !            60:     }
        !            61:     [resetQuiesceSem unlock];    
        !            62: 
        !            63:     /*
        !            64:      * Allocate and initialize a SRB structure.
        !            65:      * Note: This routine clears the SRB and initializes srb->srbPhys
        !            66:      *       which contains the physical address of the srb. 
        !            67:      */
        !            68:     srb = [self Sym8xxAllocSRB];
        !            69:     if ( srb == NULL )
        !            70:     {
        !            71:         return -1;
        !            72:     }
        !            73: 
        !            74:     nexus            = &srb->nexus;
        !            75:     nexusPhys        = &srb->srbPhys->nexus;
        !            76: 
        !            77:     /*
        !            78:      * Set client data buffer pointers in the SRB
        !            79:      */
        !            80:     srb->xferClient = client;
        !            81:     srb->xferBuffer = (vm_offset_t) buffer;
        !            82:     srb->xferCount  = scsiReq->maxTransfer;
        !            83: 
        !            84:     /*
        !            85:      * Set request sense buffer pointers in the SRB
        !            86:      */
        !            87:     if ( !scsiReq->ignoreChkcond )
        !            88:     {
        !            89:         srb->senseData       = (vm_offset_t) &scsiReq->senseData;
        !            90:         srb->senseDataLength = sizeof(esense_reply_t);
        !            91:     }
        !            92: 
        !            93:     srb->srbCmd   = ksrbCmdExecuteReq;
        !            94:     srb->srbState = ksrbStateCDBDone;
        !            95: 
        !            96:     srb->target = scsiReq->target;
        !            97:     srb->lun    = scsiReq->lun;
        !            98: 
        !            99:     /*
        !           100:      * Setup timeout. (250ms ticks)
        !           101:      */
        !           102:     if ( scsiReq->timeoutLength )
        !           103:     {
        !           104:         srb->srbTimeout  = (scsiReq->timeoutLength * 1000) / kSCSITimerIntervalMS + 1;
        !           105:     }
        !           106: 
        !           107:     srb->directionMask = (scsiReq->read) ? 0x01000000 : 0x00000000;
        !           108: 
        !           109:     /*
        !           110:      * Setup the Nexus struct. This part of the SRB is read/written both by the
        !           111:      * script and the driver.
        !           112:      */
        !           113:     nexus->targetParms.target    = srb->target;
        !           114: 
        !           115:     nexus->cdb.ppData = EndianSwap32((u_int32_t)&nexusPhys->cdbData);
        !           116: 
        !           117:     len = cdbLength[scsiReq->cdb.cdb_opcode >> 5];
        !           118:     if ( len == 0 ) len = scsiReq->cdbLength;
        !           119: 
        !           120:     nexus->cdb.length = EndianSwap32( len );
        !           121:     nexus->cdbData    = scsiReq->cdb;
        !           122: 
        !           123:     /*
        !           124:      * Setup SCSI Messages to send on inital selection of the target.
        !           125:      * Note: A SCSI tag for command-queuing requests is allocated 
        !           126:      *       when messages are generated.
        !           127:      */
        !           128:     srb->srbRequestFlags |= (scsiReq->disconnect)       ? ksrbRFDisconnectAllowed : 0;
        !           129:     srb->srbRequestFlags |= (!scsiReq->syncDisable)     ? ksrbRFXferSyncAllowed   : 0;
        !           130:     srb->srbRequestFlags |= (!scsiReq->cmdQueueDisable) ? ksrbRFCmdQueueAllowed   : 0;
        !           131: 
        !           132:     [self Sym8xxCalcMsgs:srb];
        !           133: 
        !           134:     /*
        !           135:      * Setup initial data transfer list (SGList) 
        !           136:      */
        !           137:     nexus->ppSGList   = (SGEntry *)EndianSwap32((u_int32_t)&nexusPhys->sgListData[2]);
        !           138:     [self Sym8xxUpdateSGList: srb ];
        !           139: 
        !           140:     /*
        !           141:      * Queue command to I/O Thread and wait for completion.
        !           142:      */
        !           143:     [self Sym8xxSendCommand: srb];
        !           144: 
        !           145:     /*
        !           146:      * If the command timed-out then issue a Maibox abort to clear
        !           147:      * the request from the target.
        !           148:      * 
        !           149:      * Note: We lock the abortBdrSem to insure there is only one abort
        !           150:      *       active at a time.
        !           151:      */
        !           152:     if ( srb->srbCmd == ksrbCmdProcessTimeout )
        !           153:     {
        !           154:         [abortBdrSem lock];
        !           155:         srb->srbCmd = ksrbCmdAbortReq;
        !           156:         [self Sym8xxSendCommand: srb];
        !           157:         [abortBdrSem unlock];
        !           158:     }
        !           159:     
        !           160:     /* 
        !           161:      * Release the tag for the request.
        !           162:      */
        !           163:     [self Sym8xxFreeTag: srb];
        !           164: 
        !           165:     /* 
        !           166:      * Transfer final request status from the SRB to the original request
        !           167:      */
        !           168:     IOGetTimestamp( &endTime );
        !           169:     scsiReq->totalTime        = endTime - startTime;
        !           170:     scsiReq->driverStatus     = srb->srbSCSIResult;
        !           171:     scsiReq->scsiStatus       = srb->srbSCSIStatus;
        !           172:     scsiReq->bytesTransferred = srb->xferDone;
        !           173: 
        !           174:     [self Sym8xxFreeSRB: srb];
        !           175: 
        !           176:     return scsiReq->driverStatus;
        !           177: }
        !           178: 
        !           179: /*-----------------------------------------------------------------------------*
        !           180:  * Requests from Blue Box.
        !           181:  *
        !           182:  * Note: Hopefully this kludge of having multiple variants of executeRequest
        !           183:  *       will go away soon!
        !           184:  *-----------------------------------------------------------------------------*/
        !           185: - (sc_status_t) executeRequest : (IOSCSIRequest *) scsiReq
        !           186:        ioMemoryDescriptor      : (IOMemoryDescriptor *) ioMemoryDescriptor
        !           187: {
        !           188:     return [self executeRequest:scsiReq buffer:(void *)ioMemoryDescriptor client:(vm_task_t) -1];
        !           189: }
        !           190: 
        !           191: 
        !           192: /*-----------------------------------------------------------------------------*
        !           193:  * This routine queues an SRB to reset the SCSI Bus
        !           194:  *
        !           195:  *-----------------------------------------------------------------------------*/
        !           196: - (sc_status_t) resetSCSIBus
        !           197: {
        !           198:     SRB                        *srb;
        !           199:     sc_status_t                scsiResult;
        !           200: 
        !           201:     srb = [self Sym8xxAllocSRB];
        !           202:     if ( srb == NULL )
        !           203:     {
        !           204:         return -1;
        !           205:     }
        !           206: 
        !           207:     srb->srbCmd = ksrbCmdResetSCSIBus;
        !           208:     [self Sym8xxSendCommand: srb];
        !           209: 
        !           210:     scsiResult = srb->srbSCSIResult;
        !           211:     [self Sym8xxFreeSRB: srb];
        !           212: 
        !           213:     return scsiResult;
        !           214: }
        !           215: 
        !           216: 
        !           217: /*-----------------------------------------------------------------------------*
        !           218:  * This routine queues a command on the driver's I/O Thread, wakes up
        !           219:  * the I/O Thread and then waits for the command to complete. 
        !           220:  *
        !           221:  *-----------------------------------------------------------------------------*/
        !           222: - (void) Sym8xxSendCommand: (SRB *) srb
        !           223: {
        !           224:     kern_return_t      kr;
        !           225: 
        !           226:     msg_header_t       msg = 
        !           227:     {
        !           228:         0,                             // msg_unused
        !           229:         1,                             // msg_simple
        !           230:         sizeof(msg_header_t),          // msg_size
        !           231:         MSG_TYPE_NORMAL,               // msg_type
        !           232:         PORT_NULL,                     // msg_local_port
        !           233:         PORT_NULL,                     // msg_remote_port - TO BE FILLED IN
        !           234:         IO_COMMAND_MSG                 // msg_id
        !           235:     };
        !           236: 
        !           237:     srb->srbCmdLock = [[NXConditionLock alloc] initWith: ksrbCmdPending];
        !           238: 
        !           239:     [srbPendingQLock lock];
        !           240:     queue_enter( &srbPendingQ, srb, SRB *, srbQ );
        !           241:     [srbPendingQLock unlock];
        !           242: 
        !           243:     msg.msg_remote_port = interruptPortKern;
        !           244:     kr = msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
        !           245:     if( kr != KERN_SUCCESS )
        !           246:     {
        !           247:         goto executeCmd_error;
        !           248:     }
        !           249: 
        !           250:     [srb->srbCmdLock lockWhen: ksrbCmdComplete];
        !           251:     [srb->srbCmdLock free];
        !           252:  
        !           253: executeCmd_error:
        !           254:     ;
        !           255:     return;
        !           256: }
        !           257:       
        !           258:          
        !           259: /*-----------------------------------------------------------------------------*
        !           260:  * This routine provides our data alignment/length restrictions to the
        !           261:  * super class. 
        !           262:  *
        !           263:  *-----------------------------------------------------------------------------*/
        !           264: - (void)getDMAAlignment:(IODMAAlignment *)alignment
        !           265: {
        !           266:     alignment->readStart   = 1;
        !           267:     alignment->writeStart  = 1;
        !           268:     alignment->readLength  = 1;
        !           269:     alignment->writeLength = 2;
        !           270: }
        !           271: 
        !           272: /*-----------------------------------------------------------------------------*
        !           273:  * This routine returns the number of targets we support.
        !           274:  *
        !           275:  *-----------------------------------------------------------------------------*/
        !           276: - (int) numberOfTargets                
        !           277: {
        !           278:     return MAX_SCSI_TARGETS;
        !           279: }
        !           280: 
        !           281: /*-----------------------------------------------------------------------------*
        !           282:  * This routine creates SCSI messages to send during the initial connection
        !           283:  * to the target. It is called during client request processing and also by
        !           284:  * the I/O thread when a request sense operation is required.
        !           285:  *
        !           286:  * Outbound messages are setup in the MsgOut buffer in the Nexus structure of
        !           287:  * the SRB.
        !           288:  *
        !           289:  *-----------------------------------------------------------------------------*/
        !           290: - (void) Sym8xxCalcMsgs: (SRB *)srb 
        !           291: {
        !           292:     Nexus              *nexus;
        !           293:     Nexus              *nexusPhys;
        !           294:     u_int32_t          msgIndex;
        !           295:     BOOL               fCmdQueue;
        !           296:     BOOL               fNegotiateSync;
        !           297:     BOOL               fNegotiateWide;
        !           298:     u_int32_t          targetFlags;
        !           299:     u_int32_t          reqFlags;
        !           300:     u_int8_t           *xferMsg = NULL;
        !           301: 
        !           302:     nexus     = &srb->nexus;
        !           303:     nexusPhys = &srb->srbPhys->nexus;
        !           304: 
        !           305:     reqFlags  = srb->srbRequestFlags;
        !           306: 
        !           307:     /*
        !           308:      * Setup Identify message 
        !           309:      */
        !           310:     msgIndex = 0;
        !           311:     nexus->msg.ppData = EndianSwap32((u_int32_t)&nexusPhys->msgData);
        !           312:     nexus->msgData[msgIndex++] = srb->lun | (( reqFlags & ksrbRFDisconnectAllowed ) ? 0xC0 : 0x80);
        !           313: 
        !           314:     targetFlags = targets[srb->target].flags;
        !           315: 
        !           316:     /* 
        !           317:      * Setup Tag message if cmdQueueing is supported.
        !           318:      *
        !           319:      * Note: On target flags:
        !           320:      *             kTFxxxxSupported - Inquiry data indicates the function is supported.
        !           321:      *             kTFxxxxAllowed   - The function is not explicity disabled for this target.
        !           322:      *             kRFxxxxAllowed   - The function is not explicitly disabled by the command
        !           323:      */
        !           324:     fCmdQueue = ( (targetFlags & kTFCmdQueueSupported) 
        !           325:                       && (targetFlags & kTFCmdQueueAllowed) 
        !           326:                             && (reqFlags & ksrbRFCmdQueueAllowed) );
        !           327: 
        !           328:     /*
        !           329:      * Allocate tag for request.
        !           330:      *
        !           331:      * For non-tagged requests a pseudo-tag is created consisting of target*16+lun. For tagged
        !           332:      * requests a tag in the range 128-255 is allocated.
        !           333:      *
        !           334:      * If a pseudo-tag is inuse for a non-tagged command or there are no tags available for
        !           335:      * a tagged request, then the command is blocked until a tag becomes available.
        !           336:      *
        !           337:      * Note: If we are being called during request sense processing (srbState != ksrbStateCDBDone)
        !           338:      *       then a tag has already been allocated to the request.
        !           339:      */
        !           340:     if ( srb->srbState == ksrbStateCDBDone )
        !           341:     {
        !           342:         srb->tag = srb->nexus.tag = [self Sym8xxAllocTag:(SRB *)srb CmdQueue:(BOOL)fCmdQueue];
        !           343:     }
        !           344: 
        !           345:     if ( fCmdQueue )
        !           346:     {
        !           347:         nexus->msgData[msgIndex++] = 0x20;
        !           348:         nexus->msgData[msgIndex++] = srb->nexus.tag;
        !           349:     }
        !           350: 
        !           351:     /*
        !           352:      * Setup to negotiate for Wide (16-bit) data transfers
        !           353:      *
        !           354:      * Note: There is no provision to negotiate back to narrow transfers although
        !           355:      *       SCSI does support this.
        !           356:      */
        !           357:     fNegotiateWide = (targetFlags & kTFXferWide16Supported) 
        !           358:                           && (targetFlags & kTFXferWide16Allowed) 
        !           359:                                 && !(targetFlags & kTFXferWide16);
        !           360:     
        !           361:     if ( fNegotiateWide )
        !           362:     {
        !           363:         srb->srbRequestFlags |= ksrbRFNegotiateWide;
        !           364:         bcopy( xferMsgWide16, &nexus->msgData[msgIndex], sizeof(xferMsgWide16) );
        !           365:         msgIndex += sizeof(xferMsgWide16);
        !           366:     }
        !           367: 
        !           368:     /*
        !           369:      * Setup to negotiate for Synchronous data transfers.
        !           370:      *
        !           371:      * Note: We can negotiate back to async based on the flags in the command. 
        !           372:      */
        !           373: 
        !           374:     fNegotiateSync = (targetFlags & kTFXferSyncSupported) 
        !           375:                         && (targetFlags & kTFXferSyncAllowed)
        !           376:                                && ( ((reqFlags & ksrbRFXferSyncAllowed) != 0) ^ ((targetFlags & kTFXferSync) != 0) ) ;
        !           377: 
        !           378:     if ( fNegotiateSync )
        !           379:     {
        !           380:         srb->srbRequestFlags |= ksrbRFNegotiateSync;
        !           381:         xferMsg = (reqFlags & ksrbRFXferSyncAllowed) ? xferMsgSync : xferMsgAsync;
        !           382:         bcopy( xferMsg, &nexus->msgData[msgIndex], sizeof(xferMsgSync) );
        !           383:         msgIndex      += sizeof(xferMsgSync);
        !           384:     }
        !           385: 
        !           386:     /*
        !           387:      * If we are negotiating for both Sync and Wide data transfers, we setup both messages
        !           388:      * in the Nexus msgOut buffer. However, after each message the script needs to wait for
        !           389:      * a reply message from the target. In this case, we set the msgOut length to include
        !           390:      * bytes upto the end of the Wide message. When we get the reply from the target, the
        !           391:      * routine handling the WDTR will setup the Nexus pointers/counts to send the remaining
        !           392:      * message bytes. See Sym8xxExecute.m(Sym8xxNegotiateWDTR).
        !           393:      */
        !           394:     srb->srbMsgLength = msgIndex;
        !           395: 
        !           396:     if ( fNegotiateSync && fNegotiateWide ) msgIndex -= sizeof(xferMsgSync);
        !           397: 
        !           398:     nexus->msg.length = EndianSwap32( msgIndex );
        !           399: }
        !           400: 
        !           401: /*-----------------------------------------------------------------------------*
        !           402:  * This routine sets up the data transfer SG list for the client's buffer in the
        !           403:  * Nexus structure.
        !           404:  *
        !           405:  * The SGList actually consists of script instructions. The script will branch
        !           406:  * to the SGList when the target enters data transfer phase. When the SGList completes
        !           407:  * it will either execute a script INT instruction if there are more segments of the
        !           408:  * user buffer that need to be transferred or will execute a script RETURN instruction
        !           409:  * to return to the script.
        !           410:  *
        !           411:  * The first two slots in the SGList are reserved for partial data transfers. See
        !           412:  * Sym8xxExecute.m(Sym8xxAdjustDataPtrs).
        !           413:  * 
        !           414:  *-----------------------------------------------------------------------------*/
        !           415: - (BOOL) Sym8xxUpdateSGList: (SRB *) srb
        !           416: {
        !           417:     BOOL               rc;
        !           418: 
        !           419:     if ( srb->xferClient != (vm_task_t)-1 )
        !           420:     {
        !           421:         rc = [self Sym8xxUpdateSGListVirt: srb];
        !           422:     }
        !           423:     else
        !           424:     {
        !           425:         rc = [self Sym8xxUpdateSGListDesc: srb];
        !           426:     }
        !           427:     return rc;
        !           428: }
        !           429: 
        !           430: /*-----------------------------------------------------------------------------*
        !           431:  * Build SG list based on a single virtual address range/length
        !           432:  *
        !           433:  *-----------------------------------------------------------------------------*/
        !           434: - (BOOL) Sym8xxUpdateSGListVirt: (SRB *) srb
        !           435: {
        !           436:     u_int32_t                  offset;
        !           437:     u_int32_t                  physAddr;
        !           438:     u_int32_t                  bytesLeft;
        !           439:     u_int32_t                  bytesOnPage;
        !           440:     u_int32_t                  i;
        !           441:     u_int32_t                  len = 0;
        !           442:     IOReturn                   rc = IO_R_SUCCESS;
        !           443: 
        !           444:     offset    = srb->xferOffset;
        !           445:     bytesLeft = srb->xferCount - srb->xferOffset;
        !           446:     i         = 2;
        !           447: 
        !           448:     while ( (bytesLeft > 0) && (i < MAX_SGLIST_ENTRIES-1))
        !           449:     {
        !           450: 
        !           451:         rc = IOPhysicalFromVirtual(    (vm_task_t)     srb->xferClient,        
        !           452:                                        (vm_address_t)  (srb->xferBuffer+offset), 
        !           453:                                        (u_int32_t *)   &physAddr );
        !           454: 
        !           455:         if ( rc != IO_R_SUCCESS )
        !           456:         {
        !           457:             break;
        !           458:         }
        !           459: 
        !           460:         /*
        !           461:          * Note: The script instruction(s) to transfer data to/from the scsi bus
        !           462:          *       have the same format as a typical SGList with the transfer length 
        !           463:          *       as the first word and the physical transfer address as the second. 
        !           464:          *       The data transfer direction is specified by a bit or'd into the
        !           465:          *       high byte of the SG entry's length field.
        !           466:          */
        !           467:         srb->nexus.sgListData[i].physAddr = EndianSwap32( physAddr );
        !           468: 
        !           469:         bytesOnPage = page_size - ((srb->xferBuffer + offset) & (page_size - 1));
        !           470:         len = ( bytesLeft < bytesOnPage ) ? bytesLeft : bytesOnPage;
        !           471: 
        !           472:         srb->nexus.sgListData[i].length = EndianSwap32( len | srb->directionMask );
        !           473: 
        !           474:         bytesLeft -= len;
        !           475:         offset    += len;
        !           476:         i++;
        !           477:     }
        !           478: 
        !           479:     if ( !bytesLeft )
        !           480:     {
        !           481:         srb->nexus.sgListData[i].length   = EndianSwap32( 0x90080000 );
        !           482:         srb->nexus.sgListData[i].physAddr = EndianSwap32( 0x00000000 );
        !           483:     }
        !           484:     else
        !           485:     {
        !           486:         srb->nexus.sgListData[i].length   = EndianSwap32( 0x98080000 );
        !           487:         srb->nexus.sgListData[i].physAddr = EndianSwap32( A_sglist_complete );
        !           488:     }
        !           489: 
        !           490:     srb->xferOffsetPrev = srb->xferOffset;
        !           491:     srb->xferOffset     = offset;
        !           492: 
        !           493:     return ((rc != IO_R_SUCCESS) ? NO : YES) ;
        !           494: }
        !           495: 
        !           496: /*-----------------------------------------------------------------------------*
        !           497:  * Build SG list based on an IOMemoryDescriptor object.
        !           498:  *
        !           499:  *-----------------------------------------------------------------------------*/
        !           500: - (BOOL) Sym8xxUpdateSGListDesc: (SRB *) srb
        !           501: {
        !           502: 
        !           503:     PhysicalRange              range;
        !           504:     u_int32_t                  actRanges;
        !           505:     u_int32_t                  offset;
        !           506:     u_int32_t                  bytesLeft;
        !           507:     u_int32_t                  i;
        !           508:     IOReturn                   rc = YES;
        !           509: 
        !           510:     offset    = srb->xferOffset;
        !           511:     bytesLeft = srb->xferCount - srb->xferOffset;
        !           512:     i         = 2;
        !           513: 
        !           514:     [(id)srb->xferBuffer setPosition: offset];
        !           515: 
        !           516:     while ( (bytesLeft > 0) && (i < MAX_SGLIST_ENTRIES-1))
        !           517:     {
        !           518:         [(id)srb->xferBuffer getPhysicalRanges: 1
        !           519:                              maxByteCount:      0x00FFFFFF
        !           520:                             newPosition:       &offset
        !           521:                             actualRanges:      &actRanges
        !           522:                             physicalRanges:    &range];
        !           523: 
        !           524:         if ( actRanges != 1 )
        !           525:         {
        !           526:             rc = NO;
        !           527:             break;
        !           528:         }
        !           529: 
        !           530:         /*
        !           531:          * Note: The script instruction(s) to transfer data to/from the scsi bus
        !           532:          *       have the same format as a typical SGList with the transfer length 
        !           533:          *       as the first word and the physical transfer address as the second. 
        !           534:          *       The data transfer direction is specified by a bit or'd into the
        !           535:          *       high byte of the SG entry's length field.
        !           536:          */
        !           537:         srb->nexus.sgListData[i].physAddr = EndianSwap32( (u_int32_t)range.address );
        !           538:         srb->nexus.sgListData[i].length   = EndianSwap32( range.length | srb->directionMask );
        !           539: 
        !           540:         bytesLeft -= range.length;
        !           541:         i++;
        !           542:     }
        !           543: 
        !           544:     if ( !bytesLeft )
        !           545:     {
        !           546:         srb->nexus.sgListData[i].length   = EndianSwap32( 0x90080000 );
        !           547:         srb->nexus.sgListData[i].physAddr = EndianSwap32( 0x00000000 );
        !           548:     }
        !           549:     else
        !           550:     {
        !           551:         srb->nexus.sgListData[i].length   = EndianSwap32( 0x98080000 );
        !           552:         srb->nexus.sgListData[i].physAddr = EndianSwap32( A_sglist_complete );
        !           553:     }
        !           554: 
        !           555:     srb->xferOffsetPrev = srb->xferOffset;
        !           556:     srb->xferOffset     = offset;
        !           557: 
        !           558:     return rc;
        !           559: }
        !           560: 
        !           561: 
        !           562: /*-----------------------------------------------------------------------------*
        !           563:  * This routine allocates a SCSI Tag value for a request. For non-tagged requests
        !           564:  * a pseudo-tag is generated with the value target*16+lun.
        !           565:  *
        !           566:  * If all tags are in-use or a pseudo tag is in-use, the request is blocked until
        !           567:  * the tag becomes available.
        !           568:  *
        !           569:  *-----------------------------------------------------------------------------*/
        !           570: - (u_int32_t) Sym8xxAllocTag:(SRB *) srb CmdQueue:(BOOL)fCmdQueue
        !           571: {
        !           572:     u_int32_t          i;
        !           573:     u_int32_t          tagIndex;
        !           574:     u_int32_t          tagMask;
        !           575: 
        !           576:     while ( 1 )
        !           577:     {
        !           578:         if ( fCmdQueue )
        !           579:         {
        !           580:             for ( i = MIN_SCSI_TAG; i < MAX_SCSI_TAG; i ++ )
        !           581:             {
        !           582:                 tagIndex = i / 32; 
        !           583:                 tagMask  = 1 << (i % 32);
        !           584:                 if ( !(tags[tagIndex] & tagMask) )
        !           585:                 {
        !           586:                     tags[tagIndex] |= tagMask;
        !           587:                     return i;
        !           588:                 }
        !           589:             }
        !           590:             /*
        !           591:              * This semaphore gets unlocked whenever a tag gets returned to the pool. Any
        !           592:              * requests waiting for a tag will wake-up and try to allocate a tag. If they
        !           593:              * fail they will return here and will be put back to sleep.
        !           594:              */
        !           595:             [cmdQTagSem lock];
        !           596:         }
        !           597:         else
        !           598:         {
        !           599:             i = ((u_int32_t)srb->target << 3) | srb->lun;
        !           600:             tagIndex = i / 32;
        !           601:             tagMask  = 1 << (i % 32); 
        !           602:             if ( !(tags[tagIndex] & tagMask) )
        !           603:             {
        !           604:                 tags[tagIndex] |= tagMask;
        !           605:                 return i;
        !           606:             }
        !           607:             /*
        !           608:              * This per-target semaphore gets unlocked whenever a request completes on a target. Any
        !           609:              * requests pending for this target will wake-up and try to allocate this pseudo-tag. If they
        !           610:              * fail they will return here and will be put back to sleep.
        !           611:              */
        !           612:             [targets[srb->target].targetTagSem lock];    
        !           613:         }
        !           614:     }
        !           615:     return -1;
        !           616: }
        !           617: 
        !           618: /*-----------------------------------------------------------------------------*
        !           619:  * This routine frees a previously allocates SCSI tag. It unlocks the appropriate
        !           620:  * semaphore based on the type of tag returned.
        !           621:  *
        !           622:  *-----------------------------------------------------------------------------*/
        !           623: - (void) Sym8xxFreeTag:(SRB *) srb
        !           624: {
        !           625:     u_int32_t          i;
        !           626: 
        !           627:     i = srb->tag;
        !           628:     tags[i/32] &= ~(1 << (i % 32));
        !           629: 
        !           630:     if ( i < MIN_SCSI_TAG )
        !           631:     {
        !           632:         [targets[srb->target].targetTagSem unlock];
        !           633:     }
        !           634:     else
        !           635:     {
        !           636:         [cmdQTagSem unlock];
        !           637:     }
        !           638: }  
        !           639: 
        !           640: 
        !           641: /*-----------------------------------------------------------------------------*
        !           642:  * This routine maintains a list of pages which are divided up into SRB sized
        !           643:  * allocations. The list of pages is grown or shrunk as needed.
        !           644:  * 
        !           645:  * The reason we dont use the driverKit IOMalloc function is that it does not
        !           646:  * guarantee that allocations will not cross page boundaries. The driver does 
        !           647:  * require this since the script accesses memory based on physical rather than
        !           648:  * virtual addresses. 
        !           649:  *
        !           650:  *-----------------------------------------------------------------------------*/
        !           651: - (SRB *) Sym8xxAllocSRB
        !           652: {
        !           653:     SRBPool            *pSRBPool;
        !           654:     SRB                        *pSRB = NULL;
        !           655: 
        !           656:     do
        !           657:     {
        !           658:         /* 
        !           659:          * We hold the srbPoolLock when we are searching or changing the SRB pool 
        !           660:          * data structures
        !           661:          */
        !           662:         [srbPoolLock lock];
        !           663: 
        !           664:         /*
        !           665:          * Search the list of pages currently in the SRB pool until we find a page
        !           666:          * with at least one free SRB to allocate.
        !           667:          */
        !           668:         pSRBPool = (SRBPool *) queue_first( &srbPool );
        !           669:         while (!queue_end( &srbPool, &pSRBPool->nextPage ) )
        !           670:         {
        !           671:             if ( !queue_empty( &pSRBPool->freeSRBList ) )
        !           672:             {
        !           673:                 pSRBPool->srbInUseCount++;
        !           674:                 queue_remove_first( &pSRBPool->freeSRBList, pSRB, SRB *, srbQ );
        !           675:                 break;
        !           676:             }
        !           677:             pSRBPool = (SRBPool *)queue_next( &pSRBPool->nextPage );
        !           678:         }
        !           679:     
        !           680:         [srbPoolLock unlock];
        !           681: 
        !           682:         if ( pSRB )
        !           683:         {
        !           684:             bzero( pSRB, sizeof(SRB) );
        !           685:             pSRB->srbPhys = (SRB *)(pSRBPool->pagePhysAddr + (uint)pSRB - (uint)pSRBPool);
        !           686:             pSRB->srbSeqNum = ++srbSeqNum;            
        !           687:             break;
        !           688:         }
        !           689: 
        !           690:         /*
        !           691:          * If we can find no available SRBs, we unlock a thread to grow the SRB pool and
        !           692:          * block this request until the pool grow operation completes. When our thread runs
        !           693:          * again it will retry the SRB allocation.
        !           694:          */
        !           695:         if ( srbPoolGrow == NO )
        !           696:         {
        !           697:             srbPoolGrow = YES;
        !           698:             [srbPoolGrowLock unlockWith: kSRBGrowPoolRunning];
        !           699:         }
        !           700: 
        !           701:         [srbPoolGrowLock lockWhen:   kSRBGrowPoolIdle];
        !           702:         [srbPoolGrowLock unlockWith: kSRBGrowPoolIdle];        
        !           703:     }
        !           704:     while ( 1 );
        !           705:     
        !           706:     return pSRB;
        !           707: }         
        !           708: 
        !           709: /*-----------------------------------------------------------------------------*
        !           710:  * This routine returns SRBs to the SRB pool.
        !           711:  *
        !           712:  * The page in the pool containing the SRB is located and the
        !           713:  * SRB is added to that page's SRB free list.
        !           714:  *
        !           715:  * The pool is then scanned for pages with no SRBs allocated.
        !           716:  * If more than two pages are found with zero SRBs allocate, the 
        !           717:  * additional idle pages are returned to the kernel.
        !           718:  *
        !           719:  *-----------------------------------------------------------------------------*/
        !           720: - (void) Sym8xxFreeSRB: (SRB *) pSRB
        !           721: {
        !           722:     SRB                                *srbMin, *srbMax;
        !           723:     SRBPool                    *pSRBPool, *pSRBPoolNext;
        !           724:     u_int32_t                  numSRBs;
        !           725:     kern_return_t              kr;
        !           726:     u_int32_t                  idlePageCount = 0;
        !           727: 
        !           728:     [srbPoolLock lock];
        !           729: 
        !           730:     numSRBs = (page_size - sizeof(SRBPool)) / sizeof(SRB);
        !           731: 
        !           732:     /* 
        !           733:      * Scan the pool for a page containing the returned SRB
        !           734:      */
        !           735:     pSRBPool = (SRBPool *) queue_first( &srbPool );
        !           736:     while (!queue_end( &srbPool, &pSRBPool->nextPage ) )
        !           737:     {
        !           738:         srbMin = (SRB *) (pSRBPool+1);
        !           739:         srbMax = &srbMin[numSRBs-1];
        !           740: 
        !           741:         if ( pSRB >= srbMin && pSRB <= srbMax )
        !           742:         {
        !           743:             pSRBPool->srbInUseCount--;
        !           744:             queue_enter( &pSRBPool->freeSRBList, pSRB, SRB *, srbQ );
        !           745:             break;
        !           746:         }    
        !           747:         pSRBPool = (SRBPool *)queue_next( &pSRBPool->nextPage );
        !           748:     }
        !           749: 
        !           750:     /*
        !           751:      * If we fell off the end of the SRB Pool page list without finding
        !           752:      * the owning page, we have a bug.
        !           753:      */
        !           754:     if ( queue_end( &srbPool, &pSRBPool->nextPage ) )
        !           755:     {
        !           756:         kprintf("Sym8xxFreeSRB: Bad SRB returned = %08x\n\r", (u_int32_t)pSRB );
        !           757:     }
        !           758: 
        !           759:     /*
        !           760:      * We scan the SRBPool page list again looking for pages with no SRBs inuse.
        !           761:      * If more than idle pool pages are found, we release the remaining pages to
        !           762:      * the kernel.
        !           763:      */
        !           764:     pSRBPool = (SRBPool *) queue_first( &srbPool );
        !           765:     while (!queue_end( &srbPool, &pSRBPool->nextPage ) )
        !           766:     {
        !           767:         pSRBPoolNext = (SRBPool *)queue_next( &pSRBPool->nextPage );
        !           768: 
        !           769:         if ( !pSRBPool->srbInUseCount )
        !           770:         {
        !           771:             if ( ++idlePageCount > kSRBPoolMaxFreePages )
        !           772:             {
        !           773:                 queue_remove( &srbPool, pSRBPool, SRBPool *, nextPage );
        !           774: 
        !           775: //              kprintf("SCSI(Symbios8xx): Sym8xxShrinkSRBPool\n\r");
        !           776: 
        !           777:                 kr = kmem_free(IOVmTaskSelf(), (vm_offset_t) pSRBPool, page_size );
        !           778:                 if ( kr != KERN_SUCCESS )
        !           779:                 {
        !           780:                     IOPanic("SCSI(Symbios8xx): kmem_free failed - Help me\n\r");
        !           781:                 }
        !           782:             }    
        !           783:         }           
        !           784:         pSRBPool = pSRBPoolNext;
        !           785:     }
        !           786: 
        !           787:     [srbPoolLock unlock];
        !           788: 
        !           789: }
        !           790: 
        !           791: /*-----------------------------------------------------------------------------*
        !           792:  * This routines grows the SRBPool. It runs on its own thread to avoid pager deadlocks.
        !           793:  * 
        !           794:  * We need this entry thunk since the thread creation routines dont support objC 
        !           795:  * interfaces directly.
        !           796:  *
        !           797:  *-----------------------------------------------------------------------------*/
        !           798: IOThreadFunc Sym8xxGrowSRBPool( Sym8xxController *controller )
        !           799: {
        !           800:     [controller Sym8xxGrowSRBPool];
        !           801:     return NULL;
        !           802: }
        !           803: 
        !           804: - (void) Sym8xxGrowSRBPool
        !           805: {
        !           806:     SRBPool                    *pSRBPool;
        !           807:     SRB                                *pSRB;
        !           808:     kern_return_t              kr;
        !           809:     u_int32_t                  numSRBs;
        !           810:     u_int32_t                  i;
        !           811: 
        !           812:     while ( 1 )
        !           813:     {
        !           814:         [srbPoolGrowLock lockWhen: kSRBGrowPoolRunning];
        !           815:  
        !           816: //      kprintf("SCSI(Symbios8xx): Sym8xxGrowSRBPool\n\r");
        !           817: 
        !           818:         kr = kmem_alloc_wired(IOVmTaskSelf(), (vm_offset_t *) &pSRBPool, page_size );
        !           819:         if ( kr != KERN_SUCCESS )
        !           820:         {
        !           821:             IOPanic("kmem_alloc_wired failed - Help me\n\r");
        !           822:         }
        !           823: 
        !           824:         IOPhysicalFromVirtual((vm_task_t)IOVmTaskSelf(), (vm_offset_t)pSRBPool, (vm_offset_t *)&pSRBPool->pagePhysAddr );
        !           825:     
        !           826:         pSRBPool->srbInUseCount = 0;
        !           827: 
        !           828:         numSRBs = (page_size - sizeof(SRBPool)) / sizeof(SRB);
        !           829:         pSRB    = (SRB *) (pSRBPool+1);
        !           830:         
        !           831:         queue_init( &pSRBPool->freeSRBList );
        !           832:         for ( i=0; i < numSRBs; i++ )
        !           833:         {
        !           834:             queue_enter( &pSRBPool->freeSRBList, (pSRB+i), SRB *, srbQ );
        !           835:         }
        !           836: 
        !           837:         [srbPoolLock lock];
        !           838:         queue_enter( &srbPool, pSRBPool, SRBPool *, nextPage );
        !           839:         [srbPoolLock unlock];
        !           840: 
        !           841:         srbPoolGrow = NO;
        !           842:         [srbPoolGrowLock unlockWith: kSRBGrowPoolIdle];
        !           843:     }
        !           844: }
        !           845: 
        !           846: 
        !           847: /*-----------------------------------------------------------------------------*
        !           848:  * This routine interfaces between the system timer and our I/O Thread. It
        !           849:  * sends a message to the IOThread to run the -timeoutOccurred routine which
        !           850:  * does various timing functions for the driver. See Sym8xxExecuteRequest(timeoutOccurred).
        !           851:  *
        !           852:  *-----------------------------------------------------------------------------*/
        !           853: IOThreadFunc Sym8xxTimerReq( Sym8xxController *device )
        !           854: {
        !           855:     msg_header_t       msg = { 0 };
        !           856: 
        !           857:     msg.msg_size = sizeof (msg);
        !           858:     msg.msg_remote_port = device->interruptPortKern;
        !           859:     msg.msg_id =  IO_TIMEOUT_MSG;
        !           860:        
        !           861:     msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
        !           862: 
        !           863:     return NULL;
        !           864: }
        !           865: 
        !           866: @end

unix.superglobalmegacorp.com

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