Annotation of kernel/bsd/dev/ppc/drvSymbios8xx/Sym8xxClient.m, revision 1.1.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.