|
|
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: /** ! 26: * Copyright (c) 1994-1996 NeXT Software, Inc. All rights reserved. ! 27: * Copyright 1997 Apple Computer Inc. All Rights Reserved. ! 28: * @author Martin Minow mailto:[email protected] ! 29: * @revision 1997.02.13 Initial conversion from AMDPCSCSIDriver sources. ! 30: * ! 31: * Set tabs every 4 characters. ! 32: * ! 33: * AppleMeshHardware.m - Architecture-specific methods for Apple96 SCSI driver. ! 34: * ! 35: * Edit History ! 36: * 1997.02.13 MM Initial conversion from AMDPCSCSIDriver sources. ! 37: */ ! 38: #import "Apple96SCSI.h" ! 39: #import "Apple96SCSIPrivate.h" ! 40: #import "Apple96Hardware.h" ! 41: #import "Apple96HWPrivate.h" ! 42: #import "Apple96ConfigKeys.h" ! 43: #import "Apple96Curio.h" ! 44: #import "Apple96CurioPublic.h" ! 45: #import "MacSCSICommand.h" ! 46: #import "bringup.h" ! 47: #import <driverkit/generalFuncs.h> ! 48: #import <driverkit/kernelDriver.h> ! 49: #import <driverkit/align.h> ! 50: #import <bsd/dev/scsireg.h> ! 51: // #import <mach/mach.h> ! 52: // #import <mach/mach_error.h> ! 53: #import <mach/kern_return.h> ! 54: #import <kernserv/prototypes.h> ! 55: ! 56: static int getConfigParam( ! 57: id configTable, ! 58: const char *paramName ! 59: ); ! 60: static unsigned int GetSCSICommandLength( ! 61: const cdb_t *cdbPtr, ! 62: unsigned int defaultLength ! 63: ); ! 64: ! 65: ! 66: /** ! 67: * These are the hardware-specific methods that are not explicitly ! 68: * tied to Mesh and DBDMA. ! 69: */ ! 70: ! 71: @implementation Apple96_SCSI(Hardware) ! 72: ! 73: /** ! 74: * Perform architecture-specific initialization: fetch the device's ! 75: * bus address and interrupt port number. Also, allocate one page ! 76: * of memory for the channel command. (Strictly speaking, we don't ! 77: * need an entire page, but we can use the rest of the page for ! 78: * a permanent status log). ! 79: * ! 80: * @param deviceDescription Specify the device to initialize. ! 81: * @return self [self free] if failure. ! 82: */ ! 83: - hardwareInitialization ! 84: : deviceDescription ! 85: { ! 86: IOReturn ioReturn = IO_R_SUCCESS; ! 87: id result = self; ! 88: kern_return_t kernelReturn; ! 89: UInt8 lun; ! 90: id configTable; ! 91: const char *configValue; ! 92: UInt8 deviceNumber; ! 93: UInt8 functionNumber; ! 94: UInt8 busNumber; ! 95: ! 96: ENTRY("Hhi hardwareInitialization"); ! 97: ddmInit("%s: hardwareInitialization\n", ! 98: "Apple96SCSI", ! 99: 2,3,4,5 ! 100: ); ! 101: configTable = [deviceDescription configTable]; ! 102: ASSERT(configTable != NULL); ! 103: configValue = [configTable valueForStringKey: "Bus Type"]; ! 104: if (configValue == NULL) { ! 105: IOLog("%s: No bus type in configuration table\n", ! 106: "Apple96SCSI" ! 107: ); ! 108: ioReturn = IO_R_NO_DEVICE; ! 109: } ! 110: ddmInit("Bus type: \"%s\"\n", configValue, 2, 3, 4, 5); ! 111: if (configValue == NULL || strcmp(configValue, "PPC") != 0) { ! 112: IOLog("%s: Unsupported bus type \"%s\" in configuration table\n", ! 113: "Apple96SCSI", ! 114: configValue ? configValue :"null" ! 115: ); ! 116: ioReturn = IO_R_NO_DEVICE; ! 117: } ! 118: if (ioReturn == IO_R_SUCCESS) { ! 119: #if 0 // ** ** ** Need correct definition ** ** ** ! 120: ioReturn = [deviceDescription getPCIDevice ! 121: : &deviceNumber ! 122: function : &functionNumber ! 123: bus : &busNumber]; ! 124: #else ! 125: deviceNumber = 00; ! 126: functionNumber = 00; ! 127: busNumber = 00; ! 128: kernelReturn = 0; ! 129: #endif ! 130: if (ioReturn != IO_R_SUCCESS) { ! 131: IOLog("%s: Can't get PCI device information: %s\n", ! 132: "Apple96SCSI", ! 133: [self stringFromReturn : ioReturn] ! 134: ); ! 135: } ! 136: } ! 137: if (ioReturn == IO_R_SUCCESS) { ! 138: #if 0 ! 139: IOLog("%s: Hardware device found at" ! 140: " bus %u, device %u, function %u, interrupt %u\n", ! 141: "Apple96SCSI", ! 142: busNumber, ! 143: deviceNumber, ! 144: functionNumber, ! 145: 0 ! 146: // [deviceDescription interrupt] ! 147: ); ! 148: #endif ! 149: } ! 150: if (configValue != NULL) { ! 151: [configTable freeString : configValue]; ! 152: configValue = NULL; ! 153: } ! 154: if (ioReturn == IO_R_SUCCESS) { ! 155: ioReturn = [self hardwareAllocateHardwareAndChannelMemory : deviceDescription]; ! 156: } ! 157: if (ioReturn == IO_R_SUCCESS) { ! 158: /* ! 159: * Initialize gPerTargetData[] and the dbdma channel area. ! 160: */ ! 161: [self initializePerTargetData]; ! 162: /* ! 163: * All of the addresses are established. Check that the hardware ! 164: * is present and working. ! 165: */ ! 166: ioReturn = [self hardwareChipSelfTest]; ! 167: } ! 168: if (ioReturn == IO_R_SUCCESS) { ! 169: /* ! 170: * Tell the superclass to initialize our I/O thread. After this, ! 171: * we should be able to execute SCSI requests. ! 172: */ ! 173: if ([super initFromDeviceDescription:deviceDescription] == NULL) { ! 174: IOLog("%s: Host Adaptor was not initialized. Fatal\n", ! 175: "Apple96SCSI" ! 176: ); ! 177: ioReturn = IO_R_NO_DEVICE; ! 178: } ! 179: } ! 180: if (ioReturn == IO_R_SUCCESS) { ! 181: ddmInit("Init: I/O thread running\n", 1, 2, 3, 4, 5); ! 182: gFlagIOThreadRunning = 1; ! 183: /* ! 184: * Initialize local variables. Note that activeArray and ! 185: * perTarget arrays are zeroed by objc runtime. ! 186: */ ! 187: queue_init(&gDisconnectedCommandQueue); ! 188: queue_init(&gIncomingCommandQueue); ! 189: queue_init(&gPendingCommandQueue); ! 190: gIncomingCommandLock = [[NXLock alloc] init]; ! 191: gActiveCommand = NULL; ! 192: [self resetStats]; ! 193: gOptionDisconnectEnable = ENABLE_DISCONNECT; ! 194: gOptionCmdQueueEnable = ENABLE_TAGGED_QUEUEING; ! 195: gNextQueueTag = QUEUE_TAG_NONTAGGED + 1; ! 196: gInitiatorID = kInitiatorIDDefault; ! 197: /* ! 198: * Initiator bus ID as a bitmask for selection. ! 199: */ ! 200: gInitiatorIDMask = (1 << gInitiatorID); ! 201: /* ! 202: * Reserve the initiator ID for all LUNs. ! 203: */ ! 204: for (lun = 0; lun < SCSI_NLUNS; lun++) { ! 205: [self reserveTarget ! 206: : gInitiatorID ! 207: lun : lun ! 208: forOwner : self ! 209: ]; ! 210: } ! 211: /* ! 212: * get tagged command queueing, sync mode, fast mode enables from ! 213: * configTable. ! 214: */ ! 215: #ifdef CRAP /* this requires "inspector" support: */ ! 216: gOptionCmdQueueEnable = getConfigParam(configTable, CMD_QUEUE_ENABLE); ! 217: #endif /* CRAP */ ! 218: /* ! 219: * Note: the external bus on PCI Mac's do not support synchronous ! 220: * and/or fast modes. This code should be modified to read the ! 221: * chip version id and configure sync/fast accordingly. ! 222: */ ! 223: #if 0 /* Enable for 8100 internal bus */ ! 224: gOptionSyncModeEnable = getConfigParam(configTable, SYNC_ENABLE); ! 225: gOptionFastModeEnable = getConfigParam(configTable, FAST_ENABLE); ! 226: #else ! 227: gOptionSyncModeEnable = 0; ! 228: gOptionFastModeEnable = 0; ! 229: #endif ! 230: gOptionExtendTiming = getConfigParam(configTable, EXTENDED_TIMING); ! 231: gOptionAutoSenseEnable = AUTO_SENSE_ENABLE; // from bringup.h ! 232: /* ! 233: * Get internal version of interruptPort; set the port queue ! 234: * length to the maximum size. It is not clear if we want ! 235: * to do this. ! 236: */ ! 237: gKernelInterruptPort = IOConvertPort( ! 238: [self interruptPort], ! 239: IO_KernelIOTask, ! 240: IO_Kernel ! 241: ); ! 242: #if 0 // ** ** ** Need correct header file ** ** ** ! 243: kernelReturn = port_set_backlog( ! 244: task_self(), ! 245: [self interruptPort], ! 246: PORT_BACKLOG_MAX ! 247: ); ! 248: if (kernelReturn != KERN_SUCCESS) { ! 249: IOLog("%s: warning, port_set_backlog error %d (%s)\n", ! 250: [self name], ! 251: kernelReturn, ! 252: mach_error_string(kernelReturn) ! 253: ); ! 254: } ! 255: #endif ! 256: /* ! 257: * Initialize the chip and reset the bus. ! 258: */ ! 259: ioReturn = [self hardwareReset : TRUE reason : NULL]; ! 260: ! 261: } ! 262: if (ioReturn == IO_R_SUCCESS) { ! 263: /* ! 264: * OK, we're ready to roll. ! 265: */ ! 266: [self enableInterrupt:0]; ! 267: // [self enableAllInterrupts ]; ! 268: [self registerDevice]; ! 269: } ! 270: else { ! 271: /* ! 272: * Do we need to free the locks and similar? ! 273: */ ! 274: [self free]; ! 275: result = NULL; ! 276: } ! 277: RESULT(result); ! 278: return (result); ! 279: } ! 280: ! 281: /** ! 282: * Initialize sync mode to async for all targets at start and ! 283: * after bus reset. ! 284: */ ! 285: - (void) initializePerTargetData ! 286: { ! 287: UInt8 target; ! 288: ! 289: ENTRY("His initializeTargetSyncMode"); ! 290: for (target = 0; target < SCSI_NTARGETS; target++) { ! 291: [self renegotiateSyncMode : target]; ! 292: gPerTargetData[ target ].inquiry_7 = 0; ! 293: } ! 294: EXIT(); ! 295: } ! 296: ! 297: /** ! 298: * Initialize the synchronous data transfer state for a target. ! 299: */ ! 300: - (void) renegotiateSyncMode ! 301: : (UInt8) target ! 302: { ! 303: ENTRY("Hrs renegotiateSyncMode"); ! 304: EXIT(); ! 305: } ! 306: ! 307: /** ! 308: * Reusable CURIO init function. This includes a SCSI reset. ! 309: * Handling of ioComplete of active and disconnected commands must be done ! 310: * elsewhere. Returns IO_R_SUCCESS if successful. This is called ! 311: * from a Task thread. It will disable and re-enable interrupts. ! 312: * Reason is for error logging. ! 313: */ ! 314: - (IOReturn) hardwareReset ! 315: : (Boolean) resetSCSIBus ! 316: reason : (const char *) reason ! 317: { ! 318: ENTRY("HHr hardwareReset"); ! 319: if (reason != NULL) { ! 320: IOLog("%s: Bus Reset (%s)\n", ! 321: [self name], ! 322: reason ! 323: ); ! 324: } ! 325: /* ! 326: * First of all, reset the hardware. ! 327: */ ! 328: [self curioHardwareReset : resetSCSIBus reason : reason]; ! 329: /* ! 330: * Kill all disconnected, pending, and incoming I/O requests. ! 331: */ ! 332: [self abortAllCommands : SR_IOST_RESET]; ! 333: RESULT(IO_R_SUCCESS); ! 334: return (IO_R_SUCCESS); ! 335: } ! 336: ! 337: ! 338: /* ! 339: * Start a SCSI transaction for the specified command. ActiveCmd must be ! 340: * NULL. A return of kHardwareStartRejected indicates that caller may try ! 341: * again with another command; kHardwareStartBusy indicates a condition ! 342: * other than (activeCmd != NULL) which prevents the processing of the command. ! 343: */ ! 344: - (HardwareStartResult) hardwareStart ! 345: : (CommandBuffer *) cmdBuf ! 346: { ! 347: IOSCSIRequest *scsiReq; ! 348: HardwareStartResult result = kHardwareStartOK; ! 349: cdb_t *cdbp; ! 350: Boolean okToDisconnect = gOptionDisconnectEnable; ! 351: // Boolean okToDisconnect = TRUE; ! 352: Boolean okToQueue = gOptionCmdQueueEnable; ! 353: UInt8 msgByte; ! 354: ! 355: ENTRY("Hst hardwareStart"); ! 356: /* ! 357: * We do not have a current command here. ! 358: */ ! 359: ASSERT(cmdBuf != NULL && cmdBuf->scsiReq != NULL); ! 360: scsiReq = cmdBuf->scsiReq; ! 361: cdbp = &scsiReq->cdb; ! 362: ddmChip("hardwareStart[%d.%d] cmdBuf = 0x%x opcode %s\n", ! 363: scsiReq->target, ! 364: scsiReq->lun, ! 365: cmdBuf, ! 366: IOFindNameForValue(cdbp->cdb_opcode, IOSCSIOpcodeStrings), ! 367: 5); ! 368: cmdBuf->cdbLength = GetSCSICommandLength(cdbp, scsiReq->cdbLength); ! 369: if (cmdBuf->cdbLength == 0) { ! 370: /* ! 371: * Failure: we can't determine the length of this command. ! 372: */ ! 373: [self ioComplete ! 374: : cmdBuf ! 375: finalStatus : SR_IOST_CMDREJ ! 376: ]; ! 377: ddmChip("hardwareStart rejected: invalid cdb length\n", 1, 2, 3, 4, 5); ! 378: result = kHardwareStartRejected; ! 379: } ! 380: if (result == kHardwareStartOK) { ! 381: /* ! 382: * Peek at the control byte (the last byte in the command). ! 383: */ ! 384: msgByte = ((UInt8 *) cdbp)[cmdBuf->cdbLength - 1]; ! 385: if ((msgByte & CTRL_LINKFLAG) != CTRL_NOLINK) { ! 386: /* ! 387: * Failure: we don't support linked commands. ! 388: */ ! 389: [self ioComplete ! 390: : cmdBuf ! 391: finalStatus : SR_IOST_CMDREJ ! 392: ]; ! 393: ddmChip("hardwareStart rejected: linked command\n", 1, 2, 3, 4, 5); ! 394: result = kHardwareStartRejected; ! 395: } ! 396: } ! 397: if (result == kHardwareStartOK) { ! 398: /* ! 399: * Autosense always renegotiates synchronous transfer mode. ! 400: * This is necessary as the target might have been reset ! 401: * or hit with a power-cycle. ! 402: */ ! 403: if (cmdBuf->flagIsAutosense) { ! 404: [self renegotiateSyncMode : gCurrentTarget]; ! 405: okToDisconnect = FALSE; ! 406: } ! 407: else { ! 408: /* ! 409: * This is a real command. Setup the user data ! 410: * pointers and counters and build a SCSI request ! 411: * channel command list. ! 412: * ! 413: * First, peek at the command for some special cases. ! 414: */ ! 415: cmdBuf->queueTag = QUEUE_TAG_NONTAGGED; /* No tag just yet */ ! 416: switch (cdbp->cdb_opcode) { ! 417: case kScsiCmdInquiry: ! 418: /* ! 419: * The first command SCSIDisk sends us is an Inquiry ! 420: * command. This never gets retried, so avoid a possible ! 421: * reject of a command queue tag. Avoid this hack if ! 422: * there are any other commands outstanding for this ! 423: * target/lun. ! 424: */ ! 425: if (gActiveArray[scsiReq->target][scsiReq->lun] == 0) { ! 426: scsiReq->cmdQueueDisable = TRUE; ! 427: } ! 428: okToDisconnect = FALSE; ! 429: break; ! 430: case kScsiCmdRequestSense: ! 431: /* ! 432: * Always force sync renegotiation on any Request Sense to ! 433: * catch independent target power cycles. ! 434: * (Synch renegotiation needed should be set after all ! 435: * target-detected errors -- fix needed in MessageIn). ! 436: * Sense is always issued with disconnect disabled to ! 437: * maintain T/L/Q nexus. ! 438: * ! 439: * Watch it: request sense from a client is incompatible ! 440: * with tagged queuing. ! 441: */ ! 442: [self renegotiateSyncMode : gCurrentTarget]; ! 443: okToDisconnect = FALSE; ! 444: break; ! 445: ! 446: case kScsiCmdTestUnitReady: ! 447: case kScsiCmdReadCapacity: ! 448: okToDisconnect = FALSE; ! 449: break; ! 450: } ! 451: } ! 452: ! 453: if ( scsiReq->disconnect == FALSE ) /* If this req doesn't want */ ! 454: okToDisconnect = FALSE; /* it, clear disconnect. */ ! 455: ! 456: okToQueue &= okToDisconnect ! 457: && (scsiReq->cmdQueueDisable == FALSE) ! 458: && (gPerTargetData[ scsiReq->target ].inquiry_7 & 0x02); ! 459: ! 460: cmdBuf->flagActive = 0; /* Init flags for this command */ ! 461: /* ! 462: * Make sure that the chip is stable before we try to start ! 463: * a request. ! 464: */ ! 465: /* ! 466: * Currently, the only expected reason we return kHardwareStartBusy ! 467: * is if we have a reselect pending. ! 468: * ** ** ** I don't think this can happen ** ** ** ! 469: */ ! 470: if (gFlagBusBusy) { ! 471: queue_enter(&gPendingCommandQueue, cmdBuf, CommandBuffer *, link); ! 472: ddmChip("hardwareStart deferred: bus busy\n", 1, 2, 3, 4, 5); ! 473: result = kHardwareStartBusy; ! 474: } ! 475: } ! 476: if (result == kHardwareStartOK) { ! 477: if (gActiveCommand != NULL) { ! 478: /* ! 479: * This should never happen. It ensures that there are ! 480: * no race conditions that reselect us between the time ! 481: * threadExecuteRequest looked at gActiveCommand and the ! 482: * time we disabled interrupts. ! 483: */ ! 484: queue_enter(&gPendingCommandQueue, cmdBuf, CommandBuffer *, link); ! 485: ddmChip("hardwareStart deferred: there is an active command\n", 1, 2, 3, 4, 5); ! 486: result = kHardwareStartBusy; ! 487: } ! 488: } ! 489: if (result == kHardwareStartOK) { ! 490: /* ! 491: * Activate this command - if we fail later, we'll de-activate it. ! 492: */ ! 493: #if SERIOUS_DEBUGGING ! 494: /* ! 495: * If we're reading, preset the buffer to a known data. ! 496: */ ! 497: if (cmdBuf->scsiReq != NULL ! 498: && cmdBuf->scsiReq->read ! 499: && cmdBuf->buffer != NULL ! 500: && (((UInt32) cmdBuf->buffer) & 0x03) == 0) { ! 501: int i; ! 502: UInt32 *ptr = (UInt32 *) cmdBuf->buffer; ! 503: for (i = 0; i < cmdBuf->scsiReq->maxTransfer; i += sizeof (UInt32)) { ! 504: *ptr++ = 0xDEADBEEF; ! 505: } ! 506: } ! 507: #endif /* SERIOUS_DEBUGGING */ ! 508: #if SERIOUS_DEBUGGING || LOG_COMMAND_AND_RESULT ! 509: [self logCommand ! 510: : cmdBuf ! 511: logMemory : FALSE ! 512: reason : "Command at commandStart" ! 513: ]; ! 514: #endif /* SERIOUS_DEBUGGING || LOG_COMMAND_AND_RESULT */ ! 515: ASSERT(gActiveCommand == NULL); ! 516: [self activateCommand : cmdBuf]; ! 517: ASSERT(scsiReq->target == gCurrentTarget && scsiReq->lun == gCurrentLUN); ! 518: /* MESH only: [self clearChannelCommandResults]; */ ! 519: /* ! 520: * Reset the message out buffer pointers. ! 521: */ ! 522: gMsgOutPtr = gMsgOutBuffer; ! 523: gMsgPutPtr = gMsgOutBuffer; ! 524: msgByte = kScsiMsgIdentify | scsiReq->lun; ! 525: if (okToDisconnect) ! 526: msgByte |= kScsiMsgEnableDisconnectMask; ! 527: *gMsgOutPtr++ = msgByte; ! 528: /* ! 529: * According to the SCSI Spec, the tag command immediately ! 530: * follows the selection. ! 531: */ ! 532: /* ! 533: * Note that autosense is issued on the current tag. ! 534: * The command was initialized with QUEUE_TAG_NONTAGGED. ! 535: */ ! 536: /***** Driver Kit supports only simple queue tags. *****/ ! 537: if ( okToQueue ) { ! 538: /* Avoid using tag QUEUE_TAG_NONTAGGED (zero). */ ! 539: cmdBuf->queueTag = gNextQueueTag; ! 540: if (++gNextQueueTag == QUEUE_TAG_NONTAGGED) { ! 541: gNextQueueTag++; ! 542: } ! 543: *gMsgOutPtr++ = kScsiMsgSimpleQueueTag; ! 544: *gMsgOutPtr++ = cmdBuf->queueTag; ! 545: } ! 546: if (cmdBuf->flagIsAutosense == 0) { ! 547: cmdBuf->currentDataIndex = 0; ! 548: cmdBuf->savedDataIndex = 0; ! 549: if (gActiveCommand->mem != NULL) { ! 550: [gActiveCommand->mem setPosition : 0]; /* Needed? */ ! 551: } ! 552: scsiReq->driverStatus = SR_IOST_INVALID; ! 553: scsiReq->totalTime = 0ULL; ! 554: scsiReq->latentTime = 0ULL; ! 555: } ! 556: [self hardwareStartSCSIRequest]; ! 557: IOGetTimestamp(&cmdBuf->startTime); ! 558: } ! 559: RESULT(result); ! 560: return (result); ! 561: } ! 562: ! 563: ! 564: @end /* Apple96_SCSI(Hardware) */ ! 565: ! 566: ! 567: ! 568: /* ! 569: * Obtain a YES/NO type parameter from the config table. ! 570: * @param configTable The table to examine. ! 571: * @param paramName The parameter to look for. ! 572: * @result Zero if missing from the table or the table value is ! 573: * not YES. One if present in the table and the table ! 574: * value is YES. ! 575: */ ! 576: static int getConfigParam( ! 577: id configTable, ! 578: const char *paramName ! 579: ) ! 580: { ! 581: const char *value; ! 582: int result = 0; // default if not present in table ! 583: ! 584: ENTRY("Hgc getConfigParam"); ! 585: value = [configTable valueForStringKey:paramName]; ! 586: if (value != NULL) { ! 587: if (strcmp(value, "YES") == 0) { ! 588: result = 1; ! 589: } ! 590: [configTable freeString:value]; ! 591: } ! 592: RESULT(result); ! 593: return (result); ! 594: } ! 595: ! 596: static unsigned int ! 597: GetSCSICommandLength( ! 598: const cdb_t *cdbPtr, ! 599: unsigned int defaultLength ! 600: ) ! 601: { ! 602: unsigned int result; ! 603: ! 604: /* ! 605: * Warning: don't use sizeof here - the compiler rounds the ! 606: * value up to the next word boundary. ! 607: */ ! 608: switch (((UInt8 *) cdbPtr)[0] & 0xE0) { ! 609: case (0 << 5): ! 610: result = 6; ! 611: break; ! 612: case (1 << 5): ! 613: case (2 << 5): ! 614: result = 10; ! 615: break; ! 616: case (5 << 5): ! 617: result = 12; ! 618: break; ! 619: case (6 << 5): ! 620: result = (defaultLength != 0) ? defaultLength : 6; ! 621: break; ! 622: case (7 << 5): ! 623: result = (defaultLength != 0) ? defaultLength : 10; ! 624: break; ! 625: default: ! 626: result = 0; ! 627: break; ! 628: } ! 629: return (result); ! 630: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.