|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * IOSCSIParallelDevice.cpp ! 24: * ! 25: */ ! 26: ! 27: #include <IOKit/IOSyncer.h> ! 28: #include <IOKit/scsi/IOSCSIParallelInterface.h> ! 29: ! 30: #undef super ! 31: #define super IOSCSIDevice ! 32: ! 33: #ifndef MIN ! 34: #define MIN(a,b) ((a <= b) ? a : b) ! 35: #endif ! 36: ! 37: OSDefineMetaClassAndAbstractStructors( IOCDBDevice, IOService ) ! 38: OSDefineMetaClassAndAbstractStructors( IOSCSIDevice, IOCDBDevice ) ! 39: OSDefineMetaClassAndStructors( IOSCSIParallelDevice, IOSCSIDevice ) ! 40: ! 41: /* ! 42: * ! 43: * ! 44: * ! 45: */ ! 46: bool IOSCSIParallelDevice::init( IOSCSIParallelController *forController, SCSITargetLun forTargetLun ) ! 47: { ! 48: SCSICDBInfo scsiCDB; ! 49: ! 50: controller = forController; ! 51: targetLun = forTargetLun; ! 52: ! 53: target = &controller->targets[targetLun.target]; ! 54: ! 55: queue_init( &deviceList ); ! 56: queue_init( &bypassList ); ! 57: queue_init( &activeList ); ! 58: queue_init( &abortList ); ! 59: queue_init( &cancelList ); ! 60: ! 61: clientSem = IORWLockAlloc(); ! 62: if ( clientSem == 0 ) ! 63: { ! 64: return false; ! 65: } ! 66: ! 67: if ( super::init() == false ) ! 68: { ! 69: return false; ! 70: } ! 71: ! 72: if ( controller->controllerInfo.lunPrivateDataSize != 0 ) ! 73: { ! 74: devicePrivateData = IOMallocContiguous( controller->controllerInfo.lunPrivateDataSize, 16, 0 ); ! 75: if ( devicePrivateData == 0 ) ! 76: { ! 77: return false; ! 78: } ! 79: } ! 80: ! 81: bzero( &scsiCDB, sizeof(scsiCDB) ); ! 82: ! 83: abortCmd = allocCommand(kIOSCSIParallelDevice, 0); ! 84: if ( abortCmd == 0 ) ! 85: { ! 86: return false; ! 87: } ! 88: abortCmd->setTimeout( kSCSIAbortTimeoutmS ); ! 89: ! 90: cancelCmd = allocCommand(kIOSCSIParallelDevice, 0); ! 91: if ( cancelCmd == 0 ) ! 92: { ! 93: return false; ! 94: } ! 95: cancelCmd->setTimeout( 0 ); ! 96: cancelCmd->cmdType = kSCSICommandCancel; ! 97: ! 98: reqSenseCmd = allocCommand(kIOSCSIParallelDevice, 0); ! 99: if ( reqSenseCmd == 0 ) ! 100: { ! 101: return false; ! 102: } ! 103: scsiCDB.cdbLength = 6; ! 104: scsiCDB.cdb[0] = kSCSICmdRequestSense; ! 105: scsiCDB.cdb[1] = targetLun.lun << 4; ! 106: scsiCDB.cdbTag = (UInt32) -1; ! 107: ! 108: reqSenseCmd->setTimeout( kSCSIReqSenseTimeoutmS ); ! 109: reqSenseCmd->cmdType = kSCSICommandReqSense; ! 110: reqSenseCmd->setCDB( &scsiCDB ); ! 111: ! 112: if ( controller->controllerInfo.tagAllocationMethod == kTagAllocationPerLun ) ! 113: { ! 114: tagArray = (UInt32 *)IOMalloc( controller->tagArraySize ); ! 115: bzero( tagArray, controller->tagArraySize ); ! 116: } ! 117: ! 118: deviceGate = IOCommandGate::commandGate( this, (IOCommandGate::Action) &IOSCSIParallelDevice::receiveCommand ); ! 119: if ( deviceGate == 0 ) ! 120: { ! 121: return false; ! 122: } ! 123: ! 124: if ( controller->workLoop->addEventSource( deviceGate ) != kIOReturnSuccess ) ! 125: { ! 126: return false; ! 127: } ! 128: ! 129: commandLimitSave = commandLimit = controller->controllerInfo.maxCommandsPerLun; ! 130: ! 131: idleNotifyActive = false; ! 132: ! 133: normalQHeld = false; ! 134: bypassQHeld = false; ! 135: ! 136: return true; ! 137: } ! 138: ! 139: /* ! 140: * ! 141: * ! 142: * ! 143: */ ! 144: IOReturn IOSCSIParallelDevice::probeTargetLun() ! 145: { ! 146: SCSICDBInfo cdb; ! 147: SCSIResults result; ! 148: IOReturn rc; ! 149: IOMemoryDescriptor *desc = 0; ! 150: SCSIInquiry *inqData = 0; ! 151: UInt32 size = 0; ! 152: OSDictionary *propTable; ! 153: ! 154: probeCmd = allocCommand(kIOSCSIParallelDevice, 0); ! 155: ! 156: if ( probeCmd == 0 ) ! 157: { ! 158: rc = kIOReturnNoMemory; ! 159: goto probeError; ! 160: } ! 161: ! 162: size = kDefaultInquirySize; ! 163: ! 164: if ( !(inqData = (SCSIInquiry *)IOMalloc(size)) ) ! 165: { ! 166: rc = kIOReturnNoMemory; ! 167: goto probeError; ! 168: } ! 169: ! 170: desc = IOMemoryDescriptor::withAddress( (void *)inqData, size, kIODirectionIn ); ! 171: if ( desc == 0 ) ! 172: { ! 173: rc = kIOReturnNoMemory; ! 174: goto probeError; ! 175: } ! 176: ! 177: if ( open( this ) == false ) ! 178: { ! 179: rc = kIOReturnError; ! 180: goto probeError; ! 181: } ! 182: ! 183: bzero( (void *)&cdb, sizeof(cdb) ); ! 184: ! 185: cdb.cdbLength = 6; ! 186: cdb.cdb[0] = kSCSICmdInquiry; ! 187: cdb.cdb[4] = size; ! 188: probeCmd->setCDB( &cdb ); ! 189: ! 190: probeCmd->setPointers( desc, size, false ); ! 191: ! 192: probeCmd->setTimeout( kSCSIProbeTimeoutmS ); ! 193: probeCmd->setCallback(); ! 194: ! 195: probeCmd->execute(); ! 196: ! 197: rc = probeCmd->getResults( &result ); ! 198: ! 199: switch ( rc ) ! 200: { ! 201: case kIOReturnSuccess: ! 202: break; ! 203: ! 204: case kIOReturnUnderrun: ! 205: rc = kIOReturnSuccess; ! 206: break; ! 207: ! 208: default: ! 209: goto probeError; ! 210: } ! 211: ! 212: if ( result.bytesTransferred <= (UInt32)(&inqData->flags - &inqData->devType) ) ! 213: { ! 214: rc = kIOReturnDeviceError; ! 215: goto probeError; ! 216: } ! 217: ! 218: switch ( inqData->devType & kSCSIDevTypeQualifierMask ) ! 219: { ! 220: case kSCSIDevTypeQualifierConnected: ! 221: case kSCSIDevTypeQualifierNotConnected: ! 222: break; ! 223: case kSCSIDevTypeQualifierReserved: ! 224: case kSCSIDevTypeQualifierMissing: ! 225: rc = kIOReturnNotAttached; ! 226: break; ! 227: default: ! 228: break; ! 229: } ! 230: ! 231: if ( rc != kIOReturnSuccess ) ! 232: { ! 233: goto probeError; ! 234: } ! 235: ! 236: inquiryData = inqData; ! 237: inquiryDataSize = result.bytesTransferred; ! 238: ! 239: propTable = createProperties(); ! 240: if ( !propTable ) goto probeError; ! 241: ! 242: setPropertyTable( propTable ); ! 243: ! 244: propTable->release(); ! 245: ! 246: probeError: ; ! 247: ! 248: if ( desc ) ! 249: { ! 250: desc->release(); ! 251: } ! 252: ! 253: if ( inqData ) ! 254: { ! 255: if ( rc != kIOReturnSuccess ) ! 256: { ! 257: IOFree( inqData, size ); ! 258: } ! 259: } ! 260: ! 261: return rc; ! 262: } ! 263: ! 264: /* ! 265: * ! 266: * ! 267: * ! 268: */ ! 269: void IOSCSIParallelDevice::setupTarget() ! 270: { ! 271: SCSITargetParms targetParms; ! 272: UInt32 transferWidth; ! 273: ! 274: if ( targetLun.lun != 0 ) ! 275: { ! 276: close( this ); ! 277: return; ! 278: } ! 279: ! 280: bzero( &targetParms, sizeof(SCSITargetParms) ); ! 281: ! 282: if ( inquiryData->flags & kSCSIDevCapSync ) ! 283: { ! 284: targetParms.transferPeriodpS = controller->controllerInfo.minTransferPeriodpS; ! 285: targetParms.transferOffset = controller->controllerInfo.maxTransferOffset; ! 286: } ! 287: ! 288: if ( inquiryData->flags & kSCSIDevCapWBus32 ) ! 289: { ! 290: transferWidth = 4; ! 291: } ! 292: else if ( inquiryData->flags & kSCSIDevCapWBus16 ) ! 293: { ! 294: transferWidth = 2; ! 295: } ! 296: else ! 297: { ! 298: transferWidth = 1; ! 299: } ! 300: ! 301: targetParms.transferWidth = MIN( transferWidth, controller->controllerInfo.maxTransferWidth ); ! 302: ! 303: if ( inquiryData->flags & kSCSIDevCapCmdQue ) ! 304: { ! 305: targetParms.enableTagQueuing = true; ! 306: } ! 307: ! 308: setTargetParms( &targetParms ); ! 309: ! 310: close( this ); ! 311: } ! 312: ! 313: /* ! 314: * ! 315: * ! 316: * ! 317: */ ! 318: void IOSCSIParallelDevice::getInquiryData( void *clientBuf, UInt32 clientBufSize, UInt32 *clientDataSize ) ! 319: { ! 320: UInt32 len; ! 321: ! 322: bzero( clientBuf, clientBufSize ); ! 323: ! 324: len = MIN( clientBufSize, inquiryDataSize ); ! 325: ! 326: bcopy( inquiryData, clientBuf, len ); ! 327: ! 328: *clientDataSize = len; ! 329: } ! 330: ! 331: /* ! 332: * ! 333: * ! 334: * ! 335: */ ! 336: void IOSCSIParallelDevice::abort() ! 337: { ! 338: submitCommand( kSCSICommandAbortAll, 0 ); ! 339: } ! 340: ! 341: /* ! 342: * ! 343: * ! 344: * ! 345: */ ! 346: void IOSCSIParallelDevice::reset() ! 347: { ! 348: submitCommand( kSCSICommandDeviceReset, 0 ); ! 349: } ! 350: ! 351: /* ! 352: * ! 353: * ! 354: * ! 355: */ ! 356: void IOSCSIParallelDevice::holdQueue( UInt32 queueType ) ! 357: { ! 358: if ( getWorkLoop()->inGate() == false ) ! 359: { ! 360: IOPanic( "IOSCSIParallelDevice::holdQueue() - must be called from workloop!!\n\r"); ! 361: } ! 362: ! 363: if ( queueType == kQTypeBypassQ ) ! 364: { ! 365: bypassQHeld = true; ! 366: } ! 367: else if ( queueType == kQTypeNormalQ ) ! 368: { ! 369: normalQHeld = true; ! 370: } ! 371: } ! 372: ! 373: /* ! 374: * ! 375: * ! 376: * ! 377: */ ! 378: void IOSCSIParallelDevice::releaseQueue( UInt32 queueType ) ! 379: { ! 380: if ( getWorkLoop()->inGate() == false ) ! 381: { ! 382: IOPanic( "IOSCSIParallelDevice::releaseQueue() - must be called from workloop!!\n\r"); ! 383: } ! 384: ! 385: if ( queueType == kQTypeBypassQ ) ! 386: { ! 387: bypassQHeld = false; ! 388: } ! 389: else if ( queueType == kQTypeNormalQ ) ! 390: { ! 391: normalQHeld = false; ! 392: } ! 393: ! 394: dispatchRequest(); ! 395: } ! 396: ! 397: /* ! 398: * ! 399: * ! 400: * ! 401: */ ! 402: void IOSCSIParallelDevice::notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 ) ! 403: { ! 404: if ( getWorkLoop()->inGate() == false ) ! 405: { ! 406: IOPanic( "IOSCSIParallelDevice:::notifyIdle() - must be called from workloop!!\n\r"); ! 407: } ! 408: ! 409: if ( callback == 0 ) ! 410: { ! 411: idleNotifyActive = false; ! 412: return; ! 413: } ! 414: ! 415: if ( idleNotifyActive == true ) ! 416: { ! 417: IOPanic( "IOSCSIParallelDevice:::notifyIdle() - only one idle notify may be active\n\r"); ! 418: } ! 419: ! 420: idleNotifyActive = true; ! 421: idleNotifyTarget = target; ! 422: idleNotifyCallback = callback; ! 423: idleNotifyRefcon = refcon; ! 424: ! 425: checkIdleNotify(); ! 426: } ! 427: ! 428: ! 429: /* ! 430: * ! 431: * ! 432: * ! 433: */ ! 434: void IOSCSIParallelDevice::submitCommand( UInt32 cmdType, IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber ) ! 435: { ! 436: deviceGate->runCommand( (void *)cmdType, (void *)scsiCmd, (void *) cmdSequenceNumber, (void *) 0 ); ! 437: } ! 438: ! 439: /* ! 440: * ! 441: * ! 442: * ! 443: */ ! 444: void IOSCSIParallelDevice::receiveCommand( UInt32 cmdType, IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber, void *p3 ) ! 445: { ! 446: queue_head_t *queue; ! 447: ! 448: switch ( cmdType ) ! 449: { ! 450: case kSCSICommandExecute: ! 451: scsiCmd->cmdType = (SCSICommandType) cmdType; ! 452: ! 453: scsiCmd->scsiCmd.cdbFlags &= (kCDBFNoDisconnect); ! 454: ! 455: queue = (scsiCmd->queueType == kQTypeBypassQ) ? &bypassList : &deviceList; ! 456: ! 457: if ( scsiCmd->queuePosition == kQPositionHead ) ! 458: { ! 459: stackCommand( queue, scsiCmd ); ! 460: } ! 461: else ! 462: { ! 463: addCommand( queue, scsiCmd ); ! 464: } ! 465: ! 466: dispatchRequest(); ! 467: break; ! 468: ! 469: case kSCSICommandAbortAll: ! 470: abortAllCommands( kSCSICommandAbortAll ); ! 471: break; ! 472: ! 473: case kSCSICommandAbort: ! 474: abortCommand( scsiCmd, cmdSequenceNumber ); ! 475: break; ! 476: ! 477: case kSCSICommandDeviceReset: ! 478: abortAllCommands( kSCSICommandDeviceReset ); ! 479: break; ! 480: ! 481: default: ! 482: /* ??? */ ! 483: break; ! 484: } ! 485: } ! 486: ! 487: /* ! 488: * ! 489: * ! 490: * ! 491: */ ! 492: void IOSCSIParallelDevice::abortCommand( IOSCSIParallelCommand *scsiCmd, UInt32 sequenceNumber ) ! 493: { ! 494: if ( scsiCmd->list == (queue_head_t *)deviceGate ) ! 495: { ! 496: if ( scsiCmd->sequenceNumber != sequenceNumber ) ! 497: { ! 498: return; ! 499: } ! 500: scsiCmd->results.returnCode = kIOReturnAborted; ! 501: } ! 502: else if ( scsiCmd->list == &deviceList ) ! 503: { ! 504: if ( scsiCmd->sequenceNumber != sequenceNumber ) ! 505: { ! 506: return; ! 507: } ! 508: ! 509: deleteCommand( &deviceList, scsiCmd ); ! 510: scsiCmd->results.returnCode = kIOReturnAborted; ! 511: finishCommand( scsiCmd ); ! 512: } ! 513: else if ( scsiCmd->list == &activeList ) ! 514: { ! 515: if ( scsiCmd->sequenceNumber != sequenceNumber ) ! 516: { ! 517: return; ! 518: } ! 519: ! 520: moveCommand( &activeList, &abortList, scsiCmd ); ! 521: ! 522: dispatchRequest(); ! 523: } ! 524: } ! 525: ! 526: ! 527: /* ! 528: * ! 529: * ! 530: * ! 531: */ ! 532: void IOSCSIParallelDevice::abortAllCommands( SCSICommandType cmdType ) ! 533: { ! 534: IOSCSIParallelDevice *abortDev; ! 535: ! 536: abortCmdPending = cmdType; ! 537: ! 538: if ( abortCmdPending == kSCSICommandAbortAll ) ! 539: { ! 540: if ( client != 0 ) ! 541: { ! 542: client->message( kSCSIClientMsgDeviceAbort, this ); ! 543: } ! 544: } ! 545: else if ( abortCmdPending == kSCSICommandDeviceReset ) ! 546: { ! 547: queue_iterate( &target->deviceList, abortDev, IOSCSIParallelDevice *, nextDevice ) ! 548: { ! 549: if ( abortDev->client != 0 ) ! 550: { ! 551: abortDev->client->message( kSCSIClientMsgDeviceReset, abortDev ); ! 552: } ! 553: } ! 554: } ! 555: ! 556: dispatchRequest(); ! 557: } ! 558: ! 559: /* ! 560: * ! 561: * ! 562: * ! 563: */ ! 564: void IOSCSIParallelDevice::resetOccurred( SCSIClientMessage clientMsg ) ! 565: { ! 566: if ( client != 0 && clientMsg != kSCSIClientMsgNone ) ! 567: { ! 568: client->message( clientMsg, this ); ! 569: } ! 570: ! 571: moveAllCommands( &activeList, &cancelList, kIOReturnAborted ); ! 572: moveAllCommands( &abortList, &cancelList, kIOReturnAborted ); ! 573: ! 574: abortState = kStateIdle; ! 575: reqSenseState = kStateIdle; ! 576: commandLimit = commandLimitSave; ! 577: negotiateState = kStateIdle; ! 578: ! 579: dispatchRequest(); ! 580: } ! 581: ! 582: void IOSCSIParallelDevice::resetComplete() ! 583: { ! 584: if ( client != 0 ) ! 585: { ! 586: client->message( kSCSIClientMsgBusReset | kSCSIClientMsgDone, this ); ! 587: } ! 588: } ! 589: ! 590: ! 591: /* ! 592: * ! 593: * ! 594: * ! 595: */ ! 596: bool IOSCSIParallelDevice::checkAbortQueue() ! 597: { ! 598: IOSCSIParallelCommand *origCmd; ! 599: ! 600: if ( abortState == kStateActive ) ! 601: { ! 602: return true; ! 603: } ! 604: ! 605: if ( abortCmdPending != kSCSICommandNone ) ! 606: { ! 607: abortCmd->origCommand = 0; ! 608: ! 609: abortCmd->scsiCmd.cdbTagMsg = 0; ! 610: abortCmd->scsiCmd.cdbTag = (UInt32) -1; ! 611: ! 612: ! 613: abortCmd->cmdType = abortCmdPending; ! 614: abortCmd->scsiCmd.cdbAbortMsg = (abortCmdPending == kSCSICommandAbortAll) ! 615: ? kSCSIMsgAbort : kSCSIMsgBusDeviceReset; ! 616: ! 617: if ( disableDisconnect == true ) ! 618: { ! 619: abortCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect; ! 620: } ! 621: else ! 622: { ! 623: abortCmd->scsiCmd.cdbFlags &= ~kCDBFlagsNoDisconnect; ! 624: } ! 625: ! 626: ! 627: abortCmd->timer = ( abortCmd->timeout != 0 ) ? ! 628: abortCmd->timeout / kSCSITimerIntervalmS + 1 : 0; ! 629: ! 630: bzero( &abortCmd->results, sizeof(SCSIResults) ); ! 631: ! 632: abortCmdPending = kSCSICommandNone; ! 633: abortState = kStateActive; ! 634: ! 635: addCommand( &activeList, abortCmd ); ! 636: controller->executeCommand( abortCmd ); ! 637: } ! 638: else if ( queue_empty( &abortList ) == false ) ! 639: { ! 640: origCmd = (IOSCSIParallelCommand *)queue_first( &abortList ); ! 641: abortCmd->origCommand = origCmd; ! 642: ! 643: abortCmd->cmdType = kSCSICommandAbort; ! 644: abortCmd->scsiCmd.cdbTagMsg = origCmd->scsiCmd.cdbTagMsg; ! 645: abortCmd->scsiCmd.cdbTag = origCmd->scsiCmd.cdbTag; ! 646: abortCmd->scsiCmd.cdbAbortMsg = (abortCmd->scsiCmd.cdbTagMsg != 0) ! 647: ? kSCSIMsgAbortTag : kSCSIMsgAbort; ! 648: ! 649: abortCmd->timer = ( abortCmd->timeout != 0 ) ? ! 650: abortCmd->timeout / kSCSITimerIntervalmS + 1 : 0; ! 651: ! 652: bzero( &abortCmd->results, sizeof(SCSIResults) ); ! 653: ! 654: abortState = kStateActive; ! 655: ! 656: addCommand( &activeList, abortCmd ); ! 657: controller->executeCommand( abortCmd ); ! 658: } ! 659: else ! 660: { ! 661: return false; ! 662: } ! 663: ! 664: return true; ! 665: } ! 666: ! 667: /* ! 668: * ! 669: * ! 670: * ! 671: */ ! 672: void IOSCSIParallelDevice::checkCancelQueue() ! 673: { ! 674: if ( cancelState != kStateIdle ) ! 675: { ! 676: return; ! 677: } ! 678: ! 679: if ( queue_empty( &cancelList ) == true ) ! 680: { ! 681: return; ! 682: } ! 683: ! 684: if ( controller->controllerInfo.disableCancelCommands == true ) ! 685: { ! 686: return; ! 687: } ! 688: ! 689: cancelCmd->origCommand = (IOSCSIParallelCommand *)queue_first( &cancelList ); ! 690: bzero( &cancelCmd->results, sizeof(SCSIResults) ); ! 691: ! 692: cancelState = kStateActive; ! 693: controller->cancelCommand( cancelCmd ); ! 694: } ! 695: ! 696: /* ! 697: * ! 698: * ! 699: * ! 700: */ ! 701: bool IOSCSIParallelDevice::checkReqSense() ! 702: { ! 703: IOMemoryDescriptor *senseData; ! 704: UInt32 senseLength; ! 705: SCSITargetParms *tpCur; ! 706: ! 707: if ( target->reqSenseState == kStateActive ) ! 708: { ! 709: return true; ! 710: } ! 711: ! 712: if ( reqSenseState == kStateIssue ) ! 713: { ! 714: reqSenseCmd->origCommand = reqSenseOrigCmd; ! 715: bzero( &reqSenseCmd->results, sizeof(SCSIResults) ); ! 716: ! 717: reqSenseOrigCmd->getPointers( &senseData, &senseLength, 0, true ); ! 718: reqSenseCmd->setPointers( senseData, senseLength, false ); ! 719: ! 720: reqSenseCmd->scsiCmd.cdbFlags = 0; ! 721: ! 722: if ( disableDisconnect == true ) ! 723: { ! 724: reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect; ! 725: } ! 726: else ! 727: { ! 728: reqSenseCmd->scsiCmd.cdbFlags &= ~kCDBFlagsNoDisconnect; ! 729: } ! 730: ! 731: tpCur = &target->targetParmsCurrent; ! 732: ! 733: if ( tpCur->transferWidth != 1 ) ! 734: { ! 735: reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateWDTR; ! 736: } ! 737: ! 738: if ( tpCur->transferOffset != 0 ) ! 739: { ! 740: reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateSDTR; ! 741: } ! 742: ! 743: reqSenseCmd->timer = ( reqSenseCmd->timeout != 0 ) ? ! 744: reqSenseCmd->timeout / kSCSITimerIntervalmS + 1 : 0; ! 745: ! 746: reqSenseCmd->scsiCmd.cdb[3] = (senseLength >> 8) & 0xff; ! 747: reqSenseCmd->scsiCmd.cdb[4] = senseLength & 0xff; ! 748: ! 749: reqSenseState = kStatePending; ! 750: } ! 751: ! 752: if ( reqSenseState == kStatePending ) ! 753: { ! 754: target->reqSenseState = reqSenseState = kStateActive; ! 755: ! 756: addCommand( &activeList, reqSenseCmd ); ! 757: ! 758: controller->executeCommand( reqSenseCmd ); ! 759: } ! 760: ! 761: return (target->reqSenseCount > 0); ! 762: } ! 763: ! 764: ! 765: /* ! 766: * ! 767: * ! 768: * ! 769: */ ! 770: bool IOSCSIParallelDevice::checkDeviceQueue( UInt32 *dispatchAction ) ! 771: { ! 772: IOSCSIParallelCommand *scsiCmd = 0; ! 773: queue_head_t *queue; ! 774: UInt32 i; ! 775: bool rc = true; ! 776: bool queueHeld; ! 777: ! 778: do ! 779: { ! 780: if ( controller->commandCount >= controller->commandLimit ) ! 781: { ! 782: *dispatchAction = kDispatchStop; ! 783: break; ! 784: } ! 785: ! 786: if ( target->commandCount >= target->commandLimit ) ! 787: { ! 788: *dispatchAction = kDispatchNextTarget; ! 789: break; ! 790: } ! 791: ! 792: *dispatchAction = kDispatchNextLun; ! 793: ! 794: if ( commandCount >= commandLimit ) ! 795: { ! 796: break; ! 797: } ! 798: ! 799: for ( i=0; i < 2; i++ ) ! 800: { ! 801: queueHeld = (i == 0) ? bypassQHeld : normalQHeld; ! 802: queue = (i == 0) ? &bypassList : &deviceList; ! 803: ! 804: if ( queueHeld == true ) ! 805: { ! 806: continue; ! 807: } ! 808: ! 809: scsiCmd = checkCommand( queue ); ! 810: if ( scsiCmd != 0 ) ! 811: { ! 812: *dispatchAction = kDispatchNextCommand; ! 813: break; ! 814: } ! 815: } ! 816: ! 817: if ( i == 2 ) ! 818: { ! 819: rc = false; ! 820: break; ! 821: } ! 822: ! 823: if ( disableDisconnect == true || (scsiCmd->scsiCmd.cdbFlags & kCDBFNoDisconnect) ) ! 824: { ! 825: scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect; ! 826: ! 827: if ( controller->commandCount != 0 ) ! 828: { ! 829: *dispatchAction = kDispatchNextLun; ! 830: break; ! 831: } ! 832: ! 833: controller->noDisconnectCmd = scsiCmd; ! 834: controller->commandLimitSave = controller->commandLimit; ! 835: controller->commandLimit = 1; ! 836: } ! 837: ! 838: else if ( checkTag( scsiCmd ) == false ) ! 839: { ! 840: switch ( controller->controllerInfo.tagAllocationMethod ) ! 841: { ! 842: case kTagAllocationPerTarget: ! 843: *dispatchAction = kDispatchNextTarget; ! 844: break; ! 845: case kTagAllocationPerController: ! 846: *dispatchAction = kDispatchStop; ! 847: break; ! 848: case kTagAllocationPerLun: ! 849: ; ! 850: default: ! 851: *dispatchAction = kDispatchNextLun; ! 852: } ! 853: break; ! 854: } ! 855: ! 856: getCommand( queue ); ! 857: ! 858: checkNegotiate( scsiCmd ); ! 859: ! 860: scsiCmd->timer = ( scsiCmd->timeout != 0 ) ? scsiCmd->timeout / kSCSITimerIntervalmS + 1 : 0; ! 861: ! 862: commandCount++; ! 863: target->commandCount++; ! 864: controller->commandCount++; ! 865: ! 866: addCommand( &activeList, scsiCmd ); ! 867: ! 868: controller->executeCommand( scsiCmd ); ! 869: ! 870: } while ( 0 ); ! 871: ! 872: return rc; ! 873: } ! 874: ! 875: /* ! 876: * ! 877: * ! 878: * ! 879: */ ! 880: void IOSCSIParallelDevice::rescheduleCommand( IOSCSIParallelCommand *scsiCmd ) ! 881: { ! 882: if ( scsiCmd->list != &activeList ) ! 883: { ! 884: IOLog( "IOSCSIParallelController::rescheduleCommand() - Command not active. Cmd = %08x\n\r", (int)scsiCmd ); ! 885: return; ! 886: } ! 887: ! 888: deleteCommand( &activeList, scsiCmd ); ! 889: ! 890: switch ( scsiCmd->cmdType ) ! 891: { ! 892: case kSCSICommandExecute: ! 893: if ( scsiCmd->scsiCmd.cdbTagMsg != 0 ) ! 894: { ! 895: freeTag( scsiCmd->scsiCmd.cdbTag ); ! 896: scsiCmd->scsiCmd.cdbTag = (UInt32) -1; ! 897: } ! 898: ! 899: stackCommand( &deviceList, scsiCmd ); ! 900: ! 901: if ( scsiCmd->scsiCmd.cdbFlags & kCDBFlagsNoDisconnect ) ! 902: { ! 903: controller->commandLimit = controller->commandLimitSave; ! 904: controller->noDisconnectCmd = 0; ! 905: } ! 906: ! 907: controller->commandCount--; ! 908: target->commandCount--; ! 909: commandCount--; ! 910: break; ! 911: ! 912: case kSCSICommandReqSense: ! 913: reqSenseState = kStatePending; ! 914: target->reqSenseState = kStateIdle; ! 915: break; ! 916: ! 917: case kSCSICommandAbortAll: ! 918: case kSCSICommandDeviceReset: ! 919: abortCmdPending = scsiCmd->cmdType; ! 920: ! 921: case kSCSICommandAbort: ! 922: abortState = kStateIdle; ! 923: break; ! 924: ! 925: default: ! 926: ; ! 927: } ! 928: ! 929: dispatchRequest(); ! 930: ! 931: } ! 932: ! 933: /* ! 934: * ! 935: * ! 936: * ! 937: */ ! 938: bool IOSCSIParallelDevice::setTargetParms( SCSITargetParms *targetParms ) ! 939: { ! 940: IOSCSIParallelCommand *scsiCmd; ! 941: SCSICDBInfo scsiCDB; ! 942: bool fTagEnable; ! 943: bool rc = true; ! 944: ! 945: IOMemoryDescriptor *senseDesc; ! 946: UInt8 senseBuffer[14]; ! 947: ! 948: ! 949: if ( getWorkLoop()->inGate() == true ) ! 950: { ! 951: IOPanic( "IOSCSIParallelDevice:::setTargetParms() - must not be called from workloop!!\n\r"); ! 952: } ! 953: ! 954: IOWriteLock( target->clientSem ); ! 955: ! 956: target->targetParmsNew = *targetParms; ! 957: ! 958: target->commandLimit = 1; ! 959: ! 960: fTagEnable = (targetParms->enableTagQueuing == true) ! 961: && (controller->controllerInfo.tagAllocationMethod != kTagAllocationNone) ! 962: && (controller->controllerInfo.maxTags != 0); ! 963: ! 964: if ( fTagEnable == true ) ! 965: { ! 966: target->commandLimitSave = controller->controllerInfo.maxCommandsPerTarget; ! 967: } ! 968: else ! 969: { ! 970: target->commandLimitSave = 1; ! 971: target->targetParmsNew.enableTagQueuing = false; ! 972: } ! 973: ! 974: scsiCmd = allocCommand(kIOSCSIParallelDevice, 0); ! 975: ! 976: bzero( &scsiCDB, sizeof( SCSICDBInfo ) ); ! 977: ! 978: scsiCDB.cdbLength = 6; ! 979: scsiCDB.cdb[0] = kSCSICmdTestUnitReady; ! 980: scsiCDB.cdb[1] = targetLun.lun << 4; ! 981: scsiCmd->setCDB( &scsiCDB ); ! 982: ! 983: ! 984: senseDesc = IOMemoryDescriptor::withAddress(senseBuffer, sizeof(senseBuffer), kIODirectionIn); ! 985: if ( senseDesc == 0 ) return false; ! 986: scsiCmd->setPointers( senseDesc, sizeof(senseBuffer), false, true ); ! 987: ! 988: IOWriteLock( target->targetSem ); ! 989: ! 990: target->negotiateState = kStateIssue; ! 991: ! 992: scsiCmd->execute(); ! 993: ! 994: IOWriteLock( target->targetSem ); ! 995: IORWUnlock( target->targetSem ); ! 996: ! 997: scsiCmd->release(); ! 998: senseDesc->release(); ! 999: ! 1000: rc = (target->negotiateResult == kIOReturnSuccess); ! 1001: ! 1002: IORWUnlock( target->clientSem ); ! 1003: ! 1004: return rc; ! 1005: } ! 1006: ! 1007: /* ! 1008: * ! 1009: * ! 1010: * ! 1011: */ ! 1012: void IOSCSIParallelDevice::getTargetParms( SCSITargetParms *targetParms ) ! 1013: { ! 1014: *targetParms = target->targetParmsCurrent; ! 1015: } ! 1016: ! 1017: /* ! 1018: * ! 1019: * ! 1020: * ! 1021: */ ! 1022: bool IOSCSIParallelDevice::setLunParms( SCSILunParms *lunParms ) ! 1023: { ! 1024: IOSCSIParallelCommand *scsiCmd; ! 1025: SCSICDBInfo scsiCDB; ! 1026: ! 1027: IOMemoryDescriptor *senseDesc; ! 1028: UInt8 senseBuffer[14]; ! 1029: ! 1030: if ( getWorkLoop()->inGate() == true ) ! 1031: { ! 1032: IOPanic( "IOSCSIParallelDevice:::setLunParms() - must not be called from workloop!!\n\r"); ! 1033: } ! 1034: ! 1035: IOWriteLock( clientSem ); ! 1036: ! 1037: lunParmsNew = *lunParms; ! 1038: commandLimitSave = commandLimit; ! 1039: commandLimit = 1; ! 1040: ! 1041: scsiCmd = allocCommand(kIOSCSIParallelDevice, 0); ! 1042: ! 1043: bzero( &scsiCDB, sizeof( SCSICDBInfo ) ); ! 1044: ! 1045: scsiCDB.cdbLength = 6; ! 1046: scsiCDB.cdb[0] = kSCSICmdTestUnitReady; ! 1047: scsiCDB.cdb[1] = targetLun.lun << 4; ! 1048: scsiCmd->setCDB( &scsiCDB ); ! 1049: ! 1050: senseDesc = IOMemoryDescriptor::withAddress(senseBuffer, sizeof(senseBuffer), kIODirectionIn); ! 1051: if ( senseDesc == 0 ) return false; ! 1052: scsiCmd->setPointers( senseDesc, sizeof(senseBuffer), false, true ); ! 1053: ! 1054: negotiateState = kStateIssue; ! 1055: ! 1056: scsiCmd->execute(); ! 1057: ! 1058: scsiCmd->release(); ! 1059: senseDesc->release(); ! 1060: ! 1061: while ( negotiateState != kStateIdle ) ! 1062: { ! 1063: IOSleep( 100 ); ! 1064: } ! 1065: ! 1066: IORWUnlock( clientSem ); ! 1067: ! 1068: return true; ! 1069: } ! 1070: ! 1071: /* ! 1072: * ! 1073: * ! 1074: * ! 1075: */ ! 1076: void IOSCSIParallelDevice::getLunParms( SCSILunParms *lunParms ) ! 1077: { ! 1078: lunParms->disableDisconnect = disableDisconnect; ! 1079: } ! 1080: ! 1081: /* ! 1082: * ! 1083: * ! 1084: * ! 1085: */ ! 1086: void IOSCSIParallelDevice::checkNegotiate( IOSCSIParallelCommand *scsiCmd ) ! 1087: { ! 1088: SCSITargetParms *tpCur, *tpNew; ! 1089: ! 1090: if ( target->negotiateState == kStateIssue ) ! 1091: { ! 1092: if ( target->commandCount == 0 ) ! 1093: { ! 1094: tpNew = &target->targetParmsNew; ! 1095: tpCur = &target->targetParmsCurrent; ! 1096: ! 1097: target->negotiateResult = kIOReturnSuccess; ! 1098: ! 1099: if ( tpCur->transferPeriodpS != tpNew->transferPeriodpS || tpCur->transferOffset != tpNew->transferOffset ) ! 1100: { ! 1101: scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateSDTR; ! 1102: target->negotiateState = kStateActive; ! 1103: } ! 1104: ! 1105: if ( tpCur->transferWidth != tpNew->transferWidth ) ! 1106: { ! 1107: scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateWDTR; ! 1108: target->negotiateState = kStateActive; ! 1109: } ! 1110: ! 1111: if ( tpCur->enableTagQueuing != tpNew->enableTagQueuing ) ! 1112: { ! 1113: scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsEnableTagQueuing; ! 1114: target->negotiateState = kStateActive; ! 1115: } ! 1116: ! 1117: if ( target->negotiateState != kStateActive ) ! 1118: { ! 1119: IORWUnlock( target->targetSem ); ! 1120: target->negotiateState = kStateIdle; ! 1121: target->commandLimit = target->commandLimitSave; ! 1122: } ! 1123: ! 1124: *tpCur = *tpNew; ! 1125: } ! 1126: } ! 1127: ! 1128: if ( negotiateState == kStateIssue ) ! 1129: { ! 1130: if ( commandCount == 0 ) ! 1131: { ! 1132: disableDisconnect = lunParmsNew.disableDisconnect; ! 1133: negotiateState = kStateIdle; ! 1134: } ! 1135: } ! 1136: } ! 1137: ! 1138: /* ! 1139: * ! 1140: * ! 1141: * ! 1142: */ ! 1143: bool IOSCSIParallelDevice::checkTag( IOSCSIParallelCommand *scsiCmd ) ! 1144: { ! 1145: SCSICDBInfo scsiCDB; ! 1146: bool rc = true; ! 1147: ! 1148: scsiCmd->getCDB( &scsiCDB ); ! 1149: ! 1150: scsiCDB.cdbTagMsg = 0; ! 1151: scsiCDB.cdbTag = (UInt32)-1; ! 1152: ! 1153: do ! 1154: { ! 1155: if ( scsiCmd->device->target->targetParmsCurrent.enableTagQueuing == false ) ! 1156: { ! 1157: break; ! 1158: } ! 1159: ! 1160: if ( allocTag( &scsiCDB.cdbTag ) == false ) ! 1161: { ! 1162: rc = false; ! 1163: break; ! 1164: } ! 1165: ! 1166: if ( scsiCDB.cdbTagMsg == 0 ) ! 1167: { ! 1168: scsiCDB.cdbTagMsg = kSCSIMsgSimpleQueueTag; ! 1169: } ! 1170: } ! 1171: while ( 0 ); ! 1172: ! 1173: scsiCmd->setCDB( &scsiCDB ); ! 1174: ! 1175: return rc; ! 1176: } ! 1177: ! 1178: /* ! 1179: * ! 1180: * ! 1181: * ! 1182: */ ! 1183: bool IOSCSIParallelDevice::allocTag( UInt32 *tagId ) ! 1184: { ! 1185: UInt32 i; ! 1186: UInt32 tagIndex; ! 1187: UInt32 tagMask; ! 1188: UInt32 *tags = 0; ! 1189: ! 1190: switch ( controller->controllerInfo.tagAllocationMethod ) ! 1191: { ! 1192: case kTagAllocationPerLun: ! 1193: tags = tagArray; ! 1194: break; ! 1195: case kTagAllocationPerTarget: ! 1196: tags = target->tagArray; ! 1197: break; ! 1198: case kTagAllocationPerController: ! 1199: tags = controller->tagArray; ! 1200: break; ! 1201: default: ! 1202: ; ! 1203: } ! 1204: ! 1205: if ( tags == 0 ) return false; ! 1206: ! 1207: for ( i = 0; i < controller->controllerInfo.maxTags; i++ ) ! 1208: { ! 1209: tagIndex = i / 32; ! 1210: tagMask = 1 << (i % 32); ! 1211: if ( !(tags[tagIndex] & tagMask) ) ! 1212: { ! 1213: tags[tagIndex] |= tagMask; ! 1214: *tagId = i; ! 1215: return true; ! 1216: } ! 1217: } ! 1218: return false; ! 1219: } ! 1220: ! 1221: /* ! 1222: * ! 1223: * ! 1224: * ! 1225: */ ! 1226: void IOSCSIParallelDevice::freeTag( UInt32 tagId ) ! 1227: { ! 1228: UInt32 *tags = 0; ! 1229: ! 1230: switch ( controller->controllerInfo.tagAllocationMethod ) ! 1231: { ! 1232: case kTagAllocationPerLun: ! 1233: tags = tagArray; ! 1234: break; ! 1235: case kTagAllocationPerTarget: ! 1236: tags = target->tagArray; ! 1237: break; ! 1238: case kTagAllocationPerController: ! 1239: tags = controller->tagArray; ! 1240: break; ! 1241: default: ! 1242: ; ! 1243: } ! 1244: ! 1245: if ( tags == 0 ) return; ! 1246: ! 1247: tags[tagId/32] &= ~(1 << (tagId % 32)); ! 1248: } ! 1249: ! 1250: /* ! 1251: * ! 1252: * ! 1253: * ! 1254: */ ! 1255: IOSCSIParallelCommand *IOSCSIParallelDevice::findCommandWithNexus( UInt32 tagValue ) ! 1256: { ! 1257: IOSCSIParallelCommand *scsiCmd; ! 1258: ! 1259: queue_iterate( &activeList, scsiCmd, IOSCSIParallelCommand *, nextCommand ) ! 1260: { ! 1261: switch ( scsiCmd->cmdType ) ! 1262: { ! 1263: case kSCSICommandExecute: ! 1264: case kSCSICommandReqSense: ! 1265: if ( scsiCmd->scsiCmd.cdbTag == tagValue ) ! 1266: { ! 1267: return scsiCmd; ! 1268: } ! 1269: break; ! 1270: default: ! 1271: ; ! 1272: } ! 1273: } ! 1274: ! 1275: queue_iterate( &abortList, scsiCmd, IOSCSIParallelCommand *, nextCommand ) ! 1276: { ! 1277: switch ( scsiCmd->cmdType ) ! 1278: { ! 1279: case kSCSICommandExecute: ! 1280: case kSCSICommandReqSense: ! 1281: if ( scsiCmd->scsiCmd.cdbTag == tagValue ) ! 1282: { ! 1283: return scsiCmd; ! 1284: } ! 1285: break; ! 1286: default: ! 1287: ; ! 1288: } ! 1289: } ! 1290: ! 1291: return 0; ! 1292: } ! 1293: ! 1294: /* ! 1295: * ! 1296: * ! 1297: * ! 1298: */ ! 1299: void IOSCSIParallelDevice::timer() ! 1300: { ! 1301: IOSCSIParallelCommand *scsiCmd, *tmp = 0; ! 1302: SCSITargetLun scsiTargetLun; ! 1303: ! 1304: queue_iterate( &activeList, scsiCmd, IOSCSIParallelCommand *, nextCommand ) ! 1305: { ! 1306: tmp = (IOSCSIParallelCommand *)queue_prev( &scsiCmd->nextCommand ); ! 1307: ! 1308: if ( scsiCmd->timer ) ! 1309: { ! 1310: if ( !--scsiCmd->timer ) ! 1311: { ! 1312: scsiCmd->getTargetLun( &scsiTargetLun ); ! 1313: IOLog("Timeout: T/L = %d:%d Cmd = %08x Cmd Type = %d\n\r", ! 1314: scsiTargetLun.target, scsiTargetLun.lun, (int)scsiCmd, scsiCmd->cmdType ); ! 1315: ! 1316: switch ( scsiCmd->cmdType ) ! 1317: { ! 1318: case kSCSICommandExecute: ! 1319: moveCommand( &activeList, &abortList, scsiCmd, kIOReturnTimeout ); ! 1320: scsiCmd = tmp; ! 1321: break; ! 1322: ! 1323: case kSCSICommandReqSense: ! 1324: reqSenseState = kStateIdle; ! 1325: moveCommand( &activeList, &abortList, scsiCmd, kIOReturnTimeout ); ! 1326: scsiCmd = tmp; ! 1327: break; ! 1328: ! 1329: case kSCSICommandAbort: ! 1330: case kSCSICommandAbortAll: ! 1331: case kSCSICommandDeviceReset: ! 1332: controller->busResetState = kStateIssue; ! 1333: break; ! 1334: ! 1335: default: ! 1336: ; ! 1337: } ! 1338: ! 1339: dispatchRequest(); ! 1340: } ! 1341: } ! 1342: ! 1343: if ( queue_end( &activeList, (queue_head_t *)scsiCmd ) == true ) ! 1344: { ! 1345: break; ! 1346: } ! 1347: } ! 1348: } ! 1349: ! 1350: /* ! 1351: * ! 1352: * ! 1353: * ! 1354: */ ! 1355: void IOSCSIParallelDevice::dispatchRequest() ! 1356: { ! 1357: target->state = kStateActive; ! 1358: controller->dispatchRequest(); ! 1359: } ! 1360: ! 1361: /* ! 1362: * ! 1363: * ! 1364: * ! 1365: */ ! 1366: bool IOSCSIParallelDevice::dispatch( UInt32 *dispatchAction ) ! 1367: { ! 1368: bool rc; ! 1369: ! 1370: checkCancelQueue(); ! 1371: ! 1372: if ( controller->checkBusReset() == true ) ! 1373: { ! 1374: *dispatchAction = kDispatchStop; ! 1375: return true; ! 1376: } ! 1377: ! 1378: if ( (rc = controller->commandDisable) == true ) ! 1379: { ! 1380: *dispatchAction = kDispatchNextTarget; ! 1381: return true; ! 1382: } ! 1383: ! 1384: if ( checkAbortQueue() == true ) ! 1385: { ! 1386: *dispatchAction = kDispatchNextTarget; ! 1387: return true; ! 1388: } ! 1389: ! 1390: do ! 1391: { ! 1392: if ( (rc = controller->commandDisable) == true ) ! 1393: { ! 1394: *dispatchAction = kDispatchStop; ! 1395: break; ! 1396: } ! 1397: ! 1398: if ( (rc = checkReqSense()) == true ) ! 1399: { ! 1400: *dispatchAction = kDispatchNextTarget; ! 1401: break; ! 1402: } ! 1403: ! 1404: rc = checkDeviceQueue( dispatchAction ); ! 1405: ! 1406: } while ( *dispatchAction == kDispatchNextCommand ); ! 1407: ! 1408: return rc; ! 1409: } ! 1410: ! 1411: ! 1412: /* ! 1413: * ! 1414: * ! 1415: * ! 1416: */ ! 1417: void IOSCSIParallelDevice::completeCommand( IOSCSIParallelCommand *scsiCmd ) ! 1418: { ! 1419: SCSICommandType cmdType; ! 1420: ! 1421: cmdType = scsiCmd->cmdType; ! 1422: switch ( cmdType ) ! 1423: { ! 1424: case kSCSICommandExecute: ! 1425: executeCommandDone( scsiCmd ); ! 1426: break; ! 1427: ! 1428: case kSCSICommandReqSense: ! 1429: executeReqSenseDone( scsiCmd ); ! 1430: break; ! 1431: ! 1432: case kSCSICommandAbort: ! 1433: case kSCSICommandAbortAll: ! 1434: case kSCSICommandDeviceReset: ! 1435: abortCommandDone( scsiCmd ); ! 1436: break; ! 1437: ! 1438: case kSCSICommandCancel: ! 1439: cancelCommandDone( scsiCmd ); ! 1440: break; ! 1441: ! 1442: default: ! 1443: ; ! 1444: } ! 1445: ! 1446: checkIdleNotify(); ! 1447: ! 1448: dispatchRequest(); ! 1449: } ! 1450: ! 1451: /* ! 1452: * ! 1453: * ! 1454: * ! 1455: */ ! 1456: void IOSCSIParallelDevice::checkIdleNotify() ! 1457: { ! 1458: if ( idleNotifyActive == false ) ! 1459: { ! 1460: return; ! 1461: } ! 1462: ! 1463: if ( (queue_empty( &activeList ) == true) ! 1464: && (queue_empty( &abortList ) == true) ! 1465: && (queue_empty( &cancelList ) == true) ! 1466: && (target->reqSenseCount == 0) ) ! 1467: { ! 1468: idleNotifyActive = false; ! 1469: (idleNotifyCallback)( idleNotifyTarget, idleNotifyRefcon ); ! 1470: } ! 1471: } ! 1472: ! 1473: /* ! 1474: * ! 1475: * ! 1476: * ! 1477: */ ! 1478: void IOSCSIParallelDevice::flushQueue( UInt32 queueType, IOReturn rc ) ! 1479: { ! 1480: queue_head_t *queue; ! 1481: ! 1482: queue = (queueType == kQTypeBypassQ) ? &bypassList : &deviceList; ! 1483: purgeAllCommands( queue, rc ); ! 1484: } ! 1485: ! 1486: /* ! 1487: * ! 1488: * ! 1489: * ! 1490: */ ! 1491: void IOSCSIParallelDevice::executeCommandDone( IOSCSIParallelCommand *scsiCmd ) ! 1492: { ! 1493: deleteCommand( scsiCmd->list, scsiCmd ); ! 1494: ! 1495: commandCount--; ! 1496: controller->commandCount--; ! 1497: target->commandCount--; ! 1498: ! 1499: if ( scsiCmd->scsiCmd.cdbTagMsg != 0 ) ! 1500: { ! 1501: freeTag( scsiCmd->scsiCmd.cdbTag ); ! 1502: scsiCmd->scsiCmd.cdbTag = (UInt32) -1; ! 1503: } ! 1504: ! 1505: if ( scsiCmd->scsiCmd.cdbFlags & (kCDBFlagsNegotiateSDTR | kCDBFlagsNegotiateWDTR | kCDBFlagsEnableTagQueuing) ) ! 1506: { ! 1507: target->negotiateState = kStateIdle; ! 1508: target->commandLimit = target->commandLimitSave; ! 1509: ! 1510: if ( scsiCmd->results.adapterStatus != kSCSIAdapterStatusSuccess ) ! 1511: { ! 1512: target->negotiateResult = kIOReturnIOError; ! 1513: ! 1514: target->targetParmsNew.transferWidth = 1; ! 1515: target->targetParmsNew.transferOffset = 0; ! 1516: target->targetParmsNew.transferPeriodpS = 0; ! 1517: target->targetParmsNew.enableTagQueuing = false; ! 1518: ! 1519: target->commandLimitSave = target->commandLimit = 1; ! 1520: ! 1521: target->negotiateState = kStateIssue; ! 1522: } ! 1523: ! 1524: IORWUnlock( target->targetSem ); ! 1525: } ! 1526: ! 1527: if ( scsiCmd->scsiCmd.cdbFlags & kCDBFlagsNoDisconnect ) ! 1528: { ! 1529: controller->commandLimit = controller->commandLimitSave; ! 1530: controller->noDisconnectCmd = 0; ! 1531: } ! 1532: ! 1533: if ( scsiCmd->results.scsiStatus == kSCSIStatusCheckCondition ! 1534: && scsiCmd->results.requestSenseDone == false ! 1535: && scsiCmd->senseData != 0 ) ! 1536: { ! 1537: reqSenseOrigCmd = scsiCmd; ! 1538: reqSenseState = kStateIssue; ! 1539: target->reqSenseCount++; ! 1540: return; ! 1541: } ! 1542: ! 1543: if ( scsiCmd->results.scsiStatus == kSCSIStatusQueueFull ) ! 1544: { ! 1545: if ( commandCount > 4 ) ! 1546: { ! 1547: // IOLog( "IOSCSI: Q-full - commandCount = %d commandLimit = %d\n\r", commandCount, commandLimit ); ! 1548: commandLimit = commandCount; ! 1549: } ! 1550: ! 1551: stackCommand( &deviceList, scsiCmd ); ! 1552: return; ! 1553: } ! 1554: ! 1555: finishCommand( scsiCmd ); ! 1556: } ! 1557: ! 1558: /* ! 1559: * ! 1560: * ! 1561: * ! 1562: */ ! 1563: void IOSCSIParallelDevice::executeReqSenseDone( IOSCSIParallelCommand *scsiCmd ) ! 1564: { ! 1565: IOSCSIParallelCommand *origCommand; ! 1566: ! 1567: deleteCommand( scsiCmd->list, scsiCmd ); ! 1568: ! 1569: target->reqSenseState = reqSenseState = kStateIdle; ! 1570: target->reqSenseCount--; ! 1571: ! 1572: reqSenseOrigCmd = 0; ! 1573: ! 1574: origCommand = scsiCmd->origCommand; ! 1575: ! 1576: if ( (scsiCmd->results.returnCode == kIOReturnSuccess) || (scsiCmd->results.returnCode == kIOReturnUnderrun) ) ! 1577: { ! 1578: origCommand->results.requestSenseDone = true; ! 1579: origCommand->results.requestSenseLength = scsiCmd->results.bytesTransferred; ! 1580: } ! 1581: else ! 1582: { ! 1583: origCommand->results.requestSenseDone = false; ! 1584: origCommand->results.requestSenseLength = 0; ! 1585: } ! 1586: ! 1587: finishCommand( scsiCmd->origCommand ); ! 1588: } ! 1589: ! 1590: /* ! 1591: * ! 1592: * ! 1593: * ! 1594: */ ! 1595: void IOSCSIParallelDevice::abortCommandDone( IOSCSIParallelCommand *scsiCmd ) ! 1596: { ! 1597: IOSCSIParallelCommand *origSCSICmd; ! 1598: IOSCSIParallelDevice *abortDev; ! 1599: ! 1600: deleteCommand( scsiCmd->list, scsiCmd ); ! 1601: ! 1602: if ( scsiCmd->cmdType == kSCSICommandAbortAll ) ! 1603: { ! 1604: if ( client != 0 ) ! 1605: { ! 1606: client->message( kSCSIClientMsgDeviceAbort | kSCSIClientMsgDone, this ); ! 1607: } ! 1608: } ! 1609: if ( scsiCmd->cmdType == kSCSICommandDeviceReset ) ! 1610: { ! 1611: target->commandLimit = target->commandLimitSave; ! 1612: target->reqSenseCount = 0; ! 1613: target->reqSenseState = kStateIdle; ! 1614: target->negotiateState = kStateIssue; ! 1615: ! 1616: target->targetParmsCurrent.transferPeriodpS = 0; ! 1617: target->targetParmsCurrent.transferOffset = 0; ! 1618: target->targetParmsCurrent.transferWidth = 1; ! 1619: ! 1620: queue_iterate( &target->deviceList, abortDev, IOSCSIParallelDevice *, nextDevice ) ! 1621: { ! 1622: abortDev->resetOccurred( (SCSIClientMessage)(kSCSIClientMsgDeviceReset | kSCSIClientMsgDone) ); ! 1623: } ! 1624: } ! 1625: else if ( scsiCmd->cmdType == kSCSICommandAbort ) ! 1626: { ! 1627: origSCSICmd = scsiCmd->origCommand; ! 1628: ! 1629: if ( findCommand( &abortList, origSCSICmd ) == true ) ! 1630: { ! 1631: moveCommand( &abortList, &cancelList, origSCSICmd, kIOReturnAborted ); ! 1632: } ! 1633: abortState = kStateIdle; ! 1634: } ! 1635: ! 1636: return; ! 1637: } ! 1638: ! 1639: /* ! 1640: * ! 1641: * ! 1642: * ! 1643: */ ! 1644: void IOSCSIParallelDevice::cancelCommandDone( IOSCSIParallelCommand *scsiCmd ) ! 1645: { ! 1646: IOSCSIParallelCommand *origSCSICmd; ! 1647: ! 1648: cancelState = kStateIdle; ! 1649: ! 1650: origSCSICmd = scsiCmd->origCommand; ! 1651: ! 1652: if ( findCommand( &cancelList, origSCSICmd ) == true ) ! 1653: { ! 1654: IOLog( "IOSCSIParallelDevice::cancelCommandDone - Cancelled command not completed - scsiCmd = %08x\n\r", (int)origSCSICmd ); ! 1655: deleteCommand( &cancelList, origSCSICmd ); ! 1656: } ! 1657: } ! 1658: ! 1659: /* ! 1660: * ! 1661: * ! 1662: * ! 1663: */ ! 1664: void IOSCSIParallelDevice::finishCommand( IOSCSIParallelCommand *scsiCmd ) ! 1665: { ! 1666: if ( scsiCmd->completionInfo.async.callback ) ! 1667: { ! 1668: (*scsiCmd->completionInfo.async.callback)( scsiCmd->completionInfo.async.target, ! 1669: scsiCmd->completionInfo.async.refcon ); ! 1670: } ! 1671: else ! 1672: { ! 1673: scsiCmd->completionInfo.sync.lock->signal(); ! 1674: } ! 1675: } ! 1676: ! 1677: ! 1678: /* ! 1679: * ! 1680: * ! 1681: */ ! 1682: OSDictionary *IOSCSIParallelDevice::createProperties() ! 1683: { ! 1684: OSDictionary *propTable = 0; ! 1685: OSObject *regObj; ! 1686: char tmpbuf[81]; ! 1687: char *d; ! 1688: ! 1689: ! 1690: propTable = OSDictionary::withCapacity(kSCSIMaxProperties); ! 1691: if ( propTable == NULL ) ! 1692: { ! 1693: return NULL; ! 1694: } ! 1695: ! 1696: regObj = (OSObject *)OSNumber::withNumber(targetLun.target,32); ! 1697: if ( addToRegistry( propTable, regObj, kSCSIPropertyTarget ) != true ) ! 1698: { ! 1699: goto createprop_error; ! 1700: } ! 1701: ! 1702: regObj = (OSObject *)OSNumber::withNumber(targetLun.target,32); ! 1703: if ( addToRegistry( propTable, regObj, kSCSIPropertyIOUnit ) != true ) ! 1704: { ! 1705: goto createprop_error; ! 1706: } ! 1707: ! 1708: regObj = (OSObject *)OSNumber::withNumber(targetLun.lun,32); ! 1709: if ( addToRegistry( propTable, regObj, kSCSIPropertyLun ) != true ) ! 1710: { ! 1711: goto createprop_error; ! 1712: } ! 1713: ! 1714: d= tmpbuf; ! 1715: ! 1716: stripBlanks( d, (char *)inquiryData->vendorName, sizeof(inquiryData->vendorName) ); ! 1717: regObj = (OSObject *)OSString::withCString( d ); ! 1718: if ( addToRegistry( propTable, regObj, kSCSIPropertyVendorName ) != true ) ! 1719: { ! 1720: goto createprop_error; ! 1721: } ! 1722: ! 1723: stripBlanks( d, (char *)inquiryData->productName, sizeof(inquiryData->productName) ); ! 1724: regObj = (OSObject *)OSString::withCString( d ); ! 1725: if ( addToRegistry( propTable, regObj, kSCSIPropertyProductName ) != true ) ! 1726: { ! 1727: goto createprop_error; ! 1728: } ! 1729: ! 1730: stripBlanks( d, (char *)inquiryData->productRevision, sizeof(inquiryData->productRevision) ); ! 1731: regObj = (OSObject *)OSString::withCString( d ); ! 1732: if ( addToRegistry( propTable, regObj, kSCSIPropertyProductRevision ) != true ) ! 1733: { ! 1734: goto createprop_error; ! 1735: } ! 1736: ! 1737: return propTable; ! 1738: ! 1739: createprop_error: ; ! 1740: propTable->release(); ! 1741: return NULL; ! 1742: } ! 1743: ! 1744: ! 1745: /* ! 1746: * ! 1747: * ! 1748: */ ! 1749: bool IOSCSIParallelDevice::addToRegistry( OSDictionary *propTable, OSObject *regObj, char *key ) ! 1750: { ! 1751: bool rc; ! 1752: ! 1753: if ( regObj == NULL ) ! 1754: { ! 1755: return false; ! 1756: } ! 1757: ! 1758: rc = propTable->setObject( key, regObj ); ! 1759: ! 1760: return rc; ! 1761: } ! 1762: ! 1763: ! 1764: /* ! 1765: * ! 1766: * ! 1767: * ! 1768: */ ! 1769: bool IOSCSIParallelDevice::matchPropertyTable(OSDictionary * table) ! 1770: { ! 1771: bool match; ! 1772: ! 1773: if ( (match = compareProperty(table, kSCSIPropertyIOUnit)) ) ! 1774: match = super::matchPropertyTable(table); ! 1775: ! 1776: return match; ! 1777: } ! 1778: ! 1779: ! 1780: /* ! 1781: * ! 1782: * ! 1783: * ! 1784: */ ! 1785: IOService *IOSCSIParallelDevice::matchLocation(IOService * client) ! 1786: { ! 1787: return this; ! 1788: } ! 1789: ! 1790: ! 1791: /* ! 1792: * ! 1793: * ! 1794: * ! 1795: */ ! 1796: void IOSCSIParallelDevice::stripBlanks( char *d, char *s, UInt32 l ) ! 1797: { ! 1798: char *p, c; ! 1799: ! 1800: for ( p = d, c = *s; l && c ; l--) ! 1801: { ! 1802: c = (*d++ = *s++); ! 1803: if ( c != ' ' ) ! 1804: { ! 1805: p = d; ! 1806: } ! 1807: } ! 1808: *p = 0; ! 1809: } ! 1810: ! 1811: /* ! 1812: * ! 1813: * ! 1814: * ! 1815: */ ! 1816: IOSCSICommand *IOSCSIParallelDevice::allocCommand( IOSCSIDevice *, UInt32 clientDataSize ) ! 1817: { ! 1818: IOSCSIParallelCommand *cmd; ! 1819: ! 1820: if ( (cmd = controller->allocCommand( clientDataSize )) ) ! 1821: { ! 1822: cmd->device = this; ! 1823: } ! 1824: return (IOSCSICommand *)cmd; ! 1825: } ! 1826: ! 1827: IOSCSIParallelCommand *IOSCSIParallelDevice::allocCommand( IOSCSIParallelDevice *, UInt32 clientDataSize ) ! 1828: { ! 1829: return (IOSCSIParallelCommand *) allocCommand( kIOSCSIDevice, clientDataSize ); ! 1830: } ! 1831: ! 1832: IOCDBCommand *IOSCSIParallelDevice::allocCommand( IOCDBDevice *, UInt32 clientDataSize ) ! 1833: { ! 1834: return (IOCDBCommand *) allocCommand( kIOSCSIDevice, clientDataSize ); ! 1835: } ! 1836: ! 1837: ! 1838: /* ! 1839: * ! 1840: * ! 1841: */ ! 1842: IOWorkLoop *IOSCSIParallelDevice::getWorkLoop() const ! 1843: { ! 1844: return controller->workLoop; ! 1845: } ! 1846: ! 1847: ! 1848: /* ! 1849: * ! 1850: * ! 1851: * ! 1852: */ ! 1853: bool IOSCSIParallelDevice::open( IOService *forClient, IOOptionBits options, void *arg ) ! 1854: { ! 1855: if ( client != 0 ) return false; ! 1856: ! 1857: client = forClient; ! 1858: ! 1859: return super::open( forClient, options, arg ); ! 1860: } ! 1861: ! 1862: /* ! 1863: * ! 1864: * ! 1865: * ! 1866: */ ! 1867: void IOSCSIParallelDevice::close( IOService *forClient, IOOptionBits options ) ! 1868: { ! 1869: client = 0; ! 1870: ! 1871: return super::close( forClient, options ); ! 1872: } ! 1873: ! 1874: /* ! 1875: * ! 1876: * ! 1877: * ! 1878: */ ! 1879: IOReturn IOSCSIParallelDevice::message( UInt32 forMsg, IOService *forProvider, void *forArg ) ! 1880: { ! 1881: IOReturn rc = kIOReturnSuccess; ! 1882: SCSIClientMessage clientMsg; ! 1883: ! 1884: clientMsg = (SCSIClientMessage) forMsg; ! 1885: ! 1886: // IOLog( "IOSCSIParallelDevice::message() - clientMsg = %08x\n\r", clientMsg ); ! 1887: ! 1888: switch( clientMsg ) ! 1889: { ! 1890: case kSCSIClientMsgBusReset: ! 1891: holdQueue( kQTypeNormalQ ); ! 1892: break; ! 1893: case kSCSIClientMsgBusReset | kSCSIClientMsgDone: ! 1894: releaseQueue( kQTypeNormalQ ); ! 1895: break; ! 1896: default: ! 1897: rc = super::message( clientMsg, forProvider, forArg ); ! 1898: } ! 1899: ! 1900: return rc; ! 1901: } ! 1902: ! 1903: /* ! 1904: * ! 1905: * ! 1906: * ! 1907: */ ! 1908: void IOSCSIParallelDevice::free() ! 1909: { ! 1910: if ( deviceGate != 0 ) ! 1911: { ! 1912: controller->workLoop->removeEventSource( deviceGate ); ! 1913: deviceGate->release(); ! 1914: } ! 1915: ! 1916: if ( reqSenseCmd != 0 ) reqSenseCmd->release(); ! 1917: if ( abortCmd != 0 ) abortCmd->release(); ! 1918: if ( cancelCmd != 0 ) cancelCmd->release(); ! 1919: if ( probeCmd != 0 ) probeCmd->release(); ! 1920: ! 1921: if ( tagArray != 0 ) IOFree( tagArray, controller->tagArraySize ); ! 1922: if ( inquiryData != 0 ) IOFree( inquiryData, inquiryDataSize ); ! 1923: if ( devicePrivateData != 0 ) IOFreeContiguous( devicePrivateData, controller->controllerInfo.lunPrivateDataSize ); ! 1924: if ( clientSem != 0 ) IORWLockFree( clientSem ); ! 1925: ! 1926: super::free(); ! 1927: } ! 1928: ! 1929:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.