|
|
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.18 Initial conversion from AMDPCSCSIDriver sources. ! 30: * ! 31: * Apple96SCSI.h - "Main" public methods for the 53C96 PCI SCSI interface. ! 32: * Apple96SCSI is closely based on Doug Mitchell's AMD 53C974/79C974 driver. ! 33: * ! 34: * Hmm, these methods are probably common to all SCSI implementations. ! 35: * ! 36: * Edit History ! 37: * 1998.07.29 MM Disable logRegisters on command timeout. ! 38: * 1997.02.13 MM Initial conversion from AMDPCSCSIDriver sources. ! 39: * 1997.11.12 MM Added support for scatter-gather lists. ! 40: */ ! 41: #import "Apple96SCSI.h" ! 42: #import "Apple96SCSIPrivate.h" ! 43: #import "Apple96CurioPrivate.h" ! 44: #import "Apple96CurioPublic.h" ! 45: #import "Apple96CurioDBDMA.h" ! 46: #import "Apple96Hardware.h" ! 47: #import "Apple96HWPrivate.h" ! 48: #import "Apple96ISR.h" ! 49: #import "bringup.h" ! 50: #import <mach/message.h> ! 51: #import <driverkit/generalFuncs.h> ! 52: #import <driverkit/interruptMsg.h> ! 53: #import <driverkit/align.h> ! 54: #import <driverkit/kernelDriver.h> ! 55: #import <kernserv/prototypes.h> ! 56: #import <driverkit/IOSimpleMemoryDescriptor.h> ! 57: /* string.h defines bzero */ ! 58: #import <string.h> ! 59: ! 60: ! 61: @implementation Apple96_SCSI ! 62: ! 63: /* ! 64: * Create and initialize one instance of Apple96_SCSI. The work is done by ! 65: * architecture- and chip-specific modules. ! 66: */ ! 67: + (Boolean) probe : deviceDescription ! 68: { ! 69: Apple96_SCSI *inst = [self alloc]; ! 70: Boolean result; ! 71: ! 72: ENTRY("Spr probe"); ! 73: MakeTimestampRecord(512); /* TBS: contitionally compile */ ! 74: /* ! 75: * Perform device-specific initialization -- free the instance ! 76: * on failure. ! 77: */ ! 78: if ([inst hardwareInitialization : deviceDescription] == nil) { ! 79: result = NO; ! 80: } ! 81: else { ! 82: result = YES; ! 83: } ! 84: RESULT(result); ! 85: return (result); ! 86: } ! 87: ! 88: - free ! 89: { ! 90: CommandBuffer cmdBuf; ! 91: ! 92: ENTRY("Sfr free"); ! 93: /* ! 94: * First kill the I/O thread if running. ! 95: */ ! 96: if (gFlagIOThreadRunning) { ! 97: cmdBuf.op = kCommandAbortRequest; ! 98: cmdBuf.scsiReq = NULL; ! 99: [self executeCmdBuf:&cmdBuf]; ! 100: } ! 101: if (gIncomingCommandLock != NULL) { ! 102: [gIncomingCommandLock free]; ! 103: } ! 104: [self dbdmaTerminate]; /* Free up DBDMA memory */ ! 105: EXIT(); ! 106: return [super free]; ! 107: } ! 108: ! 109: ! 110: /* ! 111: * Return required DMA alignment for current architecture. ! 112: */ ! 113: - (void)getDMAAlignment : (IODMAAlignment *)alignment; ! 114: { ! 115: alignment->readStart = DBDMA_ReadStartAlignment; ! 116: alignment->writeStart = DBDMA_WriteStartAlignment; ! 117: alignment->readLength = DBDMA_ReadLengthAlignment; ! 118: alignment->writeLength = DBDMA_WriteLengthAlignment; ! 119: } ! 120: ! 121: /* ! 122: * Statistics support. ! 123: */ ! 124: - (unsigned int) numQueueSamples ! 125: { ! 126: return (gTotalCommands); ! 127: } ! 128: ! 129: ! 130: - (unsigned int) sumQueueLengths ! 131: { ! 132: return (gQueueLenTotal); ! 133: } ! 134: ! 135: ! 136: - (unsigned int) maxQueueLength ! 137: { ! 138: return (gMaxQueueLen); ! 139: } ! 140: ! 141: ! 142: - (void)resetStats ! 143: { ! 144: gTotalCommands = 0; ! 145: gQueueLenTotal = 0; ! 146: gMaxQueueLen = 0; ! 147: } ! 148: ! 149: /** ! 150: * Do a SCSI command, as specified by an IOSCSIRequest. All the ! 151: * work is done by the I/O thread. ! 152: * @param scsiReq The request to execute ! 153: * @param buffer The data buffer to transfer to/from, if any ! 154: * @param client The data buffer owner task (for VM munging) ! 155: * ! 156: * This method is called from IOSCSIDevice ! 157: */ ! 158: - (sc_status_t) executeRequest ! 159: : (IOSCSIRequest *) scsiReq ! 160: buffer : (void *) buffer ! 161: client : (vm_task_t) client ! 162: { ! 163: IOMemoryDescriptor *mem = NULL; ! 164: sc_status_t scsiStatus = SR_IOST_GOOD; /* Fool compiler */ ! 165: ! 166: ENTRY("Ser executeRequest"); ! 167: /* ! 168: * Create a simple I/O memory descriptor for this client, ! 169: * then toss it to the common method. ! 170: */ ! 171: if (buffer != NULL) { ! 172: mem = [[IOSimpleMemoryDescriptor alloc] ! 173: initWithAddress : (void *) buffer ! 174: length : scsiReq->maxTransfer ! 175: ]; ! 176: [mem setClient : client]; ! 177: } ! 178: scsiStatus = [self executeRequest ! 179: : scsiReq ! 180: ioMemoryDescriptor : mem ! 181: ]; ! 182: if (mem != NULL) { ! 183: [mem release]; ! 184: } ! 185: RESULT(scsiReq->bytesTransferred); ! 186: return (scsiStatus); ! 187: } ! 188: ! 189: /* ! 190: * Execute a SCSI request using an IOMemoryDescriptor. This allows callers to ! 191: * provide (kernel-resident) logical scatter-gather lists. For compatibility ! 192: * with existing implementations, the low-level SCSI device driver must first ! 193: * ensure that executeRequest:ioMemoryDescriptor is supported by executing: ! 194: * [controller respondsToSelector : executeRequest:ioMemoryDescriptor] ! 195: */ ! 196: - (sc_status_t) executeRequest ! 197: : (IOSCSIRequest *) scsiReq ! 198: ioMemoryDescriptor : (IOMemoryDescriptor *) ioMemoryDescriptor ! 199: { ! 200: CommandBuffer commandBuffer; ! 201: ! 202: ENTRY("Sem executeRequest (IOMemoryDescriptor)"); ! 203: TAG("Ser", scsiReq->maxTransfer); ! 204: ddmExported("executeRequest: cmdBuf 0x%x maxTransfer 0x%x\n", ! 205: &commandBuffer, ! 206: scsiReq->maxTransfer, ! 207: 3,4,5 ! 208: ); ! 209: if (ioMemoryDescriptor != NULL) { ! 210: [ioMemoryDescriptor setMaxSegmentCount : kMaxDMATransfer]; ! 211: [ioMemoryDescriptor state : &commandBuffer.savedDataState]; ! 212: } ! 213: bzero(&commandBuffer, sizeof(CommandBuffer)); ! 214: commandBuffer.op = kCommandExecute; ! 215: commandBuffer.scsiReq = scsiReq; ! 216: commandBuffer.mem = ioMemoryDescriptor; ! 217: scsiReq->driverStatus = SR_IOST_INVALID; /* "In progress" */ ! 218: [self executeCmdBuf : &commandBuffer]; ! 219: ddmExported("executeRequest: cmdBuf 0x%x complete; driverStatus %s\n", ! 220: &commandBuffer, ! 221: IOFindNameForValue(scsiReq->driverStatus, IOScStatusStrings), ! 222: 3,4,5 ! 223: ); ! 224: RESULT(commandBuffer.scsiReq->bytesTransferred); ! 225: #if TIMESTAMP_AT_IOCOMPLETE ! 226: [self logTimestamp : "I/O complete"]; /* After RETURN macro */ ! 227: #endif ! 228: return (commandBuffer.scsiReq->driverStatus); ! 229: } ! 230: ! 231: /** ! 232: * Reset the SCSI bus. All the work is done by the I/O thread. ! 233: */ ! 234: - (sc_status_t) resetSCSIBus ! 235: { ! 236: CommandBuffer commandBuffer; ! 237: ! 238: ENTRY("Sre resetSCSIBus"); ! 239: ddmExported("resetSCSIBus: cmdBuf 0x%x\n", ! 240: &commandBuffer, ! 241: 2, 3,4,5 ! 242: ); ! 243: ! 244: commandBuffer.op = kCommandResetBus; ! 245: commandBuffer.scsiReq = NULL; ! 246: ! 247: [self executeCmdBuf:&commandBuffer]; ! 248: ddmExported("resetSCSIBus: cmdBuf 0x%x DONE\n", ! 249: &commandBuffer, ! 250: 2, 3,4,5 ! 251: ); ! 252: RESULT(SR_IOST_GOOD); ! 253: return (SR_IOST_GOOD); /* can not fail */ ! 254: } ! 255: ! 256: /* ! 257: * The following 6 methods are all called from the I/O thread in IODirectDevice. ! 258: */ ! 259: ! 260: /* ! 261: * Called from the I/O thread when it receives an interrupt message. ! 262: * Currently all work is done by chip-specific module; maybe we should ! 263: * put this method there.... ! 264: */ ! 265: - (void) interruptOccurred ! 266: { ! 267: ENTRY("Sin interruptOccurred"); ! 268: /* ! 269: * Note: the following compiles because ENTRY ends with "do {" ! 270: */ ! 271: #if DDM_DEBUG ! 272: { ! 273: /* ! 274: * calculate interrupt service time if enabled. ! 275: */ ! 276: ns_time_t startTime; ! 277: unsigned elapsedNSec = 0; ! 278: ! 279: if (IODDMMasks[APPLE96_DDM_INDEX] & DDM_INTR) { ! 280: IOGetTimestamp(&startTime); ! 281: } ! 282: ddmInterrupt("interruptOccurred: TOP\n", 1,2,3,4,5); ! 283: #endif DDM_DEBUG ! 284: [self hardwareInterrupt]; ! 285: #if DDM_DEBUG ! 286: if (IODDMMasks[APPLE96_DDM_INDEX] & DDM_INTR) { ! 287: ns_time_t endTime; ! 288: ! 289: IOGetTimestamp(&endTime); ! 290: elapsedNSec = (unsigned) (endTime - startTime); ! 291: } ! 292: ddmInterrupt("interruptOccurred: DONE; elapsed time %d.%03d us\n", ! 293: elapsedNSec / 1000U, ! 294: elapsedNSec - ((elapsedNSec / 1000U) * 1000U), ! 295: 3,4,5 ! 296: ); ! 297: } ! 298: #endif DDM_DEBUG ! 299: // [self enableInterrupt:0]; ! 300: // [self enableAllInterrupts ]; ! 301: EXIT(); ! 302: } ! 303: ! 304: /* ! 305: * These three should not occur; they are here as error traps. All three are ! 306: * called out from the I/O thread upon receipt of messages which it should ! 307: * not be seeing. ! 308: */ ! 309: - (void)interruptOccurredAt:(int)localNum ! 310: { ! 311: IOLog("%s: interruptOccurredAt:%d\n", [self name], localNum); ! 312: } ! 313: ! 314: - (void)otherOccurred:(int)id ! 315: { ! 316: IOLog("%s: otherOccurred:%d\n", [self name], id); ! 317: } ! 318: ! 319: - (void)receiveMsg ! 320: { ! 321: IOLog("%s: receiveMsg\n", [self name]); ! 322: ! 323: /* ! 324: * We have to let IODirectDevice take care of this (i.e., dequeue the ! 325: * bogus message). ! 326: */ ! 327: [super receiveMsg]; ! 328: } ! 329: ! 330: /* ! 331: * Used in -timeoutOccurred to determine if specified cmdBuf has timed out. ! 332: * Returns YES if timeout, else NO. ! 333: */ ! 334: static inline Boolean ! 335: isCmdTimedOut( ! 336: CommandBuffer *cmdBuf, ! 337: ns_time_t now ! 338: ) ! 339: { ! 340: IOSCSIRequest *scsiReq; ! 341: ns_time_t expire; ! 342: Boolean result; ! 343: ! 344: ENTRY("Sit isCmdTimedOut"); ! 345: scsiReq = cmdBuf->scsiReq; ! 346: expire = cmdBuf->startTime + ! 347: (1000000000ULL * (unsigned long long) scsiReq->timeoutLength); ! 348: result = (now > expire); ! 349: #if 0 ! 350: if (result) { ! 351: IOLog("%s: command timeout, target %d exceeded %d\n" ! 352: "drvApple96SCSI", /* Can't use [self name] here */ ! 353: (int) scsiReq->target, ! 354: (int) scsiReq->timeoutLength ! 355: ); ! 356: } ! 357: #endif ! 358: RESULT(result); ! 359: return (result); ! 360: } ! 361: ! 362: /* ! 363: * Called from the I/O thread when it receives a timeout ! 364: * message. We send these messages ourself from serviceTimeoutInterrupt(). ! 365: */ ! 366: - (void) timeoutOccurred ! 367: { ! 368: ns_time_t now; ! 369: Boolean cmdTimedOut = NO; ! 370: CommandBuffer *cmdBuf = gActiveCommand; ! 371: CommandBuffer *nextCmdBuf; ! 372: ! 373: ENTRY("Sto timeoutOccurred"); ! 374: ddmThread("timeoutOccurred: TOP\n", 1,2,3,4,5); ! 375: IOGetTimestamp(&now); ! 376: #if 0 /* Disable. Part of Radar 2261237 */ ! 377: [self logRegisters : TRUE reason : "TimeoutOccurred"]; ! 378: #endif /* Disable. Part of Radar 2261237 */ ! 379: // ** ** ** ! 380: // ** ** ** Umm, is there a race-condition here? Can gActiveCommand be changed ! 381: // ** ** ** out from under us by an interrupt or does the O.S. ensure that ! 382: // ** ** ** these methods are single-threaded? Also, note that the bus ! 383: // ** ** ** is likely to be stuck if there is a very slow device ! 384: // ** ** ** such as a Format or Tape Rewind ongoing. This needs to be ! 385: // ** ** ** updated to use the Copland (and/or SCSI Manager 4.3) algorithms. ! 386: // ** ** ** ! 387: /* ! 388: * Scan gActiveCommand and disconnectQ looking for tardy I/Os. ! 389: */ ! 390: if (cmdBuf != NULL) { ! 391: if (isCmdTimedOut(cmdBuf, now)) { ! 392: ddmThread("gActiveCommand TIMEOUT, cmd 0x%x\n", ! 393: cmdBuf, 2,3,4,5); ! 394: gActiveCommand = NULL; ! 395: /* ! 396: * ** ** ** Umm, what about abort commands? ! 397: */ ! 398: ASSERT(cmdBuf->scsiReq != NULL); ! 399: [self ioComplete ! 400: : cmdBuf ! 401: finalStatus : SR_IOST_IOTO ! 402: ]; ! 403: cmdTimedOut = YES; ! 404: } ! 405: } ! 406: /* ! 407: * ** ** ** ! 408: * ** ** ** Umm, disconnected commands should timeout only ! 409: * ** ** ** when the bus is idle. Otherwise, we can timeout ! 410: * ** ** ** a command whose only fault is that other commands ! 411: * ** ** ** saturated the bus. ! 412: */ ! 413: cmdBuf = (CommandBuffer *) queue_first(&gDisconnectedCommandQueue); ! 414: while (queue_end(&gDisconnectedCommandQueue, (queue_entry_t) cmdBuf) == 0) { ! 415: if (isCmdTimedOut(cmdBuf, now)) { ! 416: ddmThread("disconnected cmd timeout, cmd 0x%x\n", cmdBuf, 2,3,4,5); ! 417: ! 418: /* ! 419: * Remove cmdBuf from disconnectQ and complete it. ! 420: */ ! 421: nextCmdBuf = (CommandBuffer *) queue_next(&cmdBuf->link); ! 422: queue_remove(&gDisconnectedCommandQueue, cmdBuf, CommandBuffer *, link); ! 423: ASSERT(cmdBuf->scsiReq != NULL); ! 424: [self ioComplete ! 425: : cmdBuf ! 426: finalStatus : SR_IOST_IOTO ! 427: ]; ! 428: cmdBuf = nextCmdBuf; ! 429: cmdTimedOut = YES; ! 430: } ! 431: else { ! 432: cmdBuf = (CommandBuffer *) queue_next(&cmdBuf->link); ! 433: } ! 434: } ! 435: /* ! 436: * ** ** ** ! 437: * ** ** ** This is a really big hammer -- and will cause problems ! 438: * ** ** ** with tape drives. It may also cause data loss. ! 439: * ** ** ** ! 440: * Reset bus. This also completes all I/Os in disconnectQ with ! 441: * status CS_Reset. ! 442: */ ! 443: if (cmdTimedOut) { ! 444: [self logRegisters : TRUE reason : "Command timeout"]; ! 445: [self threadResetBus:NULL]; ! 446: } ! 447: ddmThread("timeoutOccurred: DONE\n", 1,2,3,4,5); ! 448: EXIT(); ! 449: } ! 450: ! 451: /* ! 452: * Process all commands in gIncomingCommandQueue. At most one of these will become ! 453: * gActiveCommand. The remainder of kCommandExecute commands go to gPendingCommandQueue. Other ! 454: * types of commands (such as bus reset) are executed immediately. ! 455: * ! 456: * This method is called from IODirectDevice. ! 457: * ** ** ** ! 458: * ** ** ** Note that we don't have a concept of frozen queue. ! 459: * ** ** ** ! 460: */ ! 461: - (void) commandRequestOccurred ! 462: { ! 463: CommandBuffer *cmdBuf; ! 464: CommandBuffer *pendCmd; ! 465: ! 466: ENTRY("Sco commandRequestOccurred"); ! 467: ddmThread("commandRequestOccurred: top\n", 1,2,3,4,5); ! 468: [gIncomingCommandLock lock]; ! 469: while (queue_empty(&gIncomingCommandQueue) == FALSE) { ! 470: cmdBuf = (CommandBuffer *) queue_first(&gIncomingCommandQueue); ! 471: queue_remove(&gIncomingCommandQueue, cmdBuf, CommandBuffer *, link); ! 472: [gIncomingCommandLock unlock]; ! 473: switch (cmdBuf->op) { ! 474: case kCommandResetBus: ! 475: /* ! 476: * Note all active and disconnected commands will ! 477: * be terminted. ! 478: */ ! 479: [self threadResetBus : "Reset Command Received"]; ! 480: [self ioComplete ! 481: : cmdBuf ! 482: finalStatus : SR_IOST_RESET ! 483: ]; ! 484: break; ! 485: case kCommandAbortRequest: ! 486: /* ! 487: * 1. Abort all active, pending, and disconnected ! 488: * commands. ! 489: * 2. Notify caller of completion. ! 490: * 3. Self-terminate. ! 491: */ ! 492: [self abortAllCommands : SR_IOST_INT]; ! 493: pendCmd = (CommandBuffer *) queue_first(&gPendingCommandQueue); ! 494: while (queue_end(&gPendingCommandQueue, (queue_entry_t) pendCmd) == FALSE) { ! 495: [self ioComplete ! 496: : pendCmd ! 497: finalStatus : SR_IOST_INT ! 498: ]; ! 499: pendCmd = (CommandBuffer *) queue_next(&pendCmd->link); ! 500: } ! 501: [cmdBuf->cmdLock lock]; ! 502: [cmdBuf->cmdLock unlockWith:CMD_COMPLETE]; ! 503: ddmEntry("-Method: commandRequestOccurred", 1, 2, 3, 4, 5); ! 504: IOExitThread(); ! 505: /* not reached */ ! 506: case kCommandExecute: ! 507: [self threadExecuteRequest:cmdBuf]; ! 508: break; ! 509: ! 510: } ! 511: [gIncomingCommandLock lock]; ! 512: } ! 513: [gIncomingCommandLock unlock]; ! 514: ddmThread("commandRequestOccurred: DONE\n", 1,2,3,4,5); ! 515: EXIT(); ! 516: } ! 517: ! 518: ! 519: /* ! 520: * Power management methods. All we care about is power off, when we must ! 521: * reset the SCSI bus due to the Compaq BIOS's lack of a SCSI reset, which ! 522: * causes a hang if we have set up targets for sync data transfer mode. ! 523: */ ! 524: - (IOReturn) getPowerState : (PMPowerState *) state_p ! 525: { ! 526: ddmExported("getPowerState called\n", 1,2,3,4,5); ! 527: return IO_R_UNSUPPORTED; ! 528: } ! 529: ! 530: - (IOReturn) setPowerState : (PMPowerState) state ! 531: { ! 532: #ifdef DEBUG ! 533: IOLog("%s: received setPowerState: with %x\n", [self name], ! 534: (unsigned)state); ! 535: #endif DEBUG ! 536: if (state == PM_OFF) { ! 537: // [self scsiReset]; ! 538: // ** ** ** TBS: [self powerDown]; ! 539: return IO_R_SUCCESS; ! 540: } ! 541: return IO_R_UNSUPPORTED; ! 542: } ! 543: ! 544: - (IOReturn) getPowerManagement : (PMPowerManagementState *) state_p ! 545: { ! 546: ddmExported("getPowerManagement called\n", 1,2,3,4,5); ! 547: return IO_R_UNSUPPORTED; ! 548: } ! 549: ! 550: - (IOReturn) setPowerManagement : (PMPowerManagementState) state ! 551: { ! 552: ddmExported("setPowerManagement called\n", 1,2,3,4,5); ! 553: return IO_R_UNSUPPORTED; ! 554: } ! 555: ! 556: #if APPLE96_ENABLE_GET_SET ! 557: ! 558: /** ! 559: * Called by clients (and user-interaction) to configure the device. ! 560: */ ! 561: - (IOReturn) setIntValues ! 562: : (unsigned *) parameterArray ! 563: forParameter : (IOParameterName) parameterName ! 564: count : (unsigned int) count ! 565: { ! 566: IOReturn ioReturn = IO_R_INVALID_ARG; ! 567: ! 568: /* Radar 1670762 ENTRY("Ssi setIntValues"); */ ! 569: ddmExported("setIntValues %s, count %u\n", ! 570: parameterName, ! 571: count, ! 572: 3, 4, 5 ! 573: ); ! 574: if (strcmp(parameterName, APPLE96_AUTOSENSE) == 0) { ! 575: if (count == 1) { ! 576: gOptionAutoSenseEnable = (parameterArray[0] ? 1 : 0); ! 577: IOLog("%s: autoSense %s\n", [self name], ! 578: (gOptionAutoSenseEnable ? "Enabled" : "Disabled")); ! 579: ioReturn = IO_R_SUCCESS; ! 580: } ! 581: } ! 582: else if (strcmp(parameterName, APPLE96_ENABLE_DISCONNECT) == 0) { /* Radar 2005639 */ ! 583: if (count == 1) { ! 584: gOptionDisconnectEnable = (parameterArray[0] ? 1 : 0); ! 585: IOLog("%s: disconnect %s\n", [self name], ! 586: (gOptionDisconnectEnable ? "Enabled" : "Disabled")); ! 587: ioReturn = IO_R_SUCCESS; ! 588: } ! 589: } ! 590: else if (strcmp(parameterName, APPLE96_CMD_QUEUE) == 0) { ! 591: if (count == 1) { ! 592: gOptionCmdQueueEnable = (parameterArray[0] ? 1 : 0); ! 593: IOLog("%s: cmdQueue %s\n", [self name], ! 594: (gOptionCmdQueueEnable ? "Enabled" : "Disabled")); ! 595: ioReturn = IO_R_SUCCESS; ! 596: } ! 597: } ! 598: else if (strcmp(parameterName, APPLE96_SYNC) == 0) { ! 599: if (count == 1) { ! 600: gOptionSyncModeEnable = (parameterArray[0] ? 1 : 0); ! 601: IOLog("%s: syncMode %s\n", [self name], ! 602: (gOptionSyncModeEnable ? "Enabled" : "Disabled")); ! 603: ioReturn = IO_R_SUCCESS; ! 604: } ! 605: } ! 606: else if (strcmp(parameterName, APPLE96_FAST_SCSI) == 0) { ! 607: if (count == 1) { ! 608: gOptionFastModeEnable = (parameterArray[0] ? 1 : 0); ! 609: IOLog("%s: fastMode %s\n", [self name], ! 610: (gOptionFastModeEnable ? "Enabled" : "Disabled")); ! 611: ioReturn = IO_R_SUCCESS; ! 612: } ! 613: } ! 614: else if (strcmp(parameterName, APPLE96_RESET_TARGETS) == 0) { ! 615: if (count == 0) { ! 616: int target; ! 617: ! 618: /* ! 619: * Re-enable sync and command queueing. The ! 620: * disable bits persist after a reset. ! 621: */ ! 622: for (target = 0; target < SCSI_NTARGETS; target++) { ! 623: PerTargetData *perTargetPtr; ! 624: ! 625: perTargetPtr = &gPerTargetData[target]; ! 626: perTargetPtr->cmdQueueDisable = FALSE; ! 627: perTargetPtr->selectATNDisable = FALSE; ! 628: perTargetPtr->maxQueue = 0; ! 629: } ! 630: IOLog("%s: Per Target disable flags cleared\n", [self name]); ! 631: ioReturn = IO_R_SUCCESS; ! 632: } ! 633: } ! 634: else if (strcmp(parameterName, APPLE96_RESET_TIMESTAMP) == 0) { ! 635: ResetTimestampIndex(); ! 636: ioReturn = IO_R_SUCCESS; ! 637: } ! 638: else if (strcmp(parameterName, APPLE96_ENABLE_TIMESTAMP) == 0) { ! 639: EnableTimestamp(TRUE); ! 640: ioReturn = IO_R_SUCCESS; ! 641: } ! 642: else if (strcmp(parameterName, APPLE96_DISABLE_TIMESTAMP) == 0) { ! 643: EnableTimestamp(FALSE); ! 644: ioReturn = IO_R_SUCCESS; ! 645: } ! 646: else if (strcmp(parameterName, APPLE96_PRESERVE_FIRST_TIMESTAMP) == 0) { ! 647: PreserveTimestamp(TRUE); ! 648: ioReturn = IO_R_SUCCESS; ! 649: } ! 650: else if (strcmp(parameterName, APPLE96_PRESERVE_LAST_TIMESTAMP) == 0) { ! 651: PreserveTimestamp(FALSE); ! 652: ioReturn = IO_R_SUCCESS; ! 653: } ! 654: else { ! 655: ioReturn = [super setIntValues ! 656: : parameterArray ! 657: forParameter : parameterName ! 658: count : count ! 659: ]; ! 660: } ! 661: /* Radar 1670762 RESULT(ioReturn); */ ! 662: return (ioReturn); ! 663: } ! 664: ! 665: /** ! 666: * Called by clients and user-interaction to retrieve information from ! 667: * the device. Note that non-privileged clients can call getIntValues ! 668: * and it may be used to *set* timestamp parameters. ! 669: */ ! 670: - (IOReturn) getIntValues ! 671: : (unsigned *) parameterArray ! 672: forParameter : (IOParameterName) parameterName ! 673: count : (unsigned *) count; /* in/out */ ! 674: { ! 675: IOReturn ioReturn = IO_R_INVALID_ARG; ! 676: ! 677: /* Radar 1670762 ENTRY("Sgi getIntValues"); */ ! 678: if (strcmp(parameterName, APPLE96_AUTOSENSE) == 0) { ! 679: if (*count == 1) { ! 680: parameterArray[0] = gOptionAutoSenseEnable; ! 681: ioReturn = IO_R_SUCCESS; ! 682: } ! 683: } ! 684: else if (strcmp(parameterName, APPLE96_CMD_QUEUE) == 0) { ! 685: if (*count == 1) { ! 686: parameterArray[0] = gOptionCmdQueueEnable; ! 687: ioReturn = IO_R_SUCCESS; ! 688: } ! 689: } ! 690: else if (strcmp(parameterName, APPLE96_SYNC) == 0) { ! 691: if (*count == 1) { ! 692: parameterArray[0] = gOptionSyncModeEnable; ! 693: ioReturn = IO_R_SUCCESS; ! 694: } ! 695: } ! 696: else if (strcmp(parameterName, APPLE96_FAST_SCSI) == 0) { ! 697: if (*count == 1) { ! 698: parameterArray[0] = gOptionFastModeEnable; ! 699: ioReturn = IO_R_SUCCESS; ! 700: } ! 701: } ! 702: else if (strcmp(parameterName, APPLE96_ENABLE_DISCONNECT) == 0) { /* Radar 2005639 */ ! 703: if (*count == 1) { ! 704: parameterArray[0] = gOptionDisconnectEnable; ! 705: ioReturn = IO_R_SUCCESS; ! 706: } ! 707: } ! 708: else if (strcmp(parameterName, APPLE_MAX_THREADS) == 0) { /* Radar 2005639 */ ! 709: if (*count == 1) { ! 710: parameterArray[0] = MAX_CLIENT_THREADS; ! 711: ioReturn = IO_R_SUCCESS; ! 712: } ! 713: } ! 714: else if (strcmp(parameterName, APPLE96_RESET_TIMESTAMP) == 0) { ! 715: ResetTimestampIndex(); ! 716: ioReturn = IO_R_SUCCESS; ! 717: } ! 718: else if (strcmp(parameterName, APPLE96_ENABLE_TIMESTAMP) == 0) { ! 719: EnableTimestamp(TRUE); ! 720: ioReturn = IO_R_SUCCESS; ! 721: } ! 722: else if (strcmp(parameterName, APPLE96_DISABLE_TIMESTAMP) == 0) { ! 723: EnableTimestamp(FALSE); ! 724: ioReturn = IO_R_SUCCESS; ! 725: } ! 726: else if (strcmp(parameterName, APPLE96_PRESERVE_FIRST_TIMESTAMP) == 0) { ! 727: PreserveTimestamp(TRUE); ! 728: ioReturn = IO_R_SUCCESS; ! 729: } ! 730: else if (strcmp(parameterName, APPLE96_PRESERVE_LAST_TIMESTAMP) == 0) { ! 731: PreserveTimestamp(FALSE); ! 732: ioReturn = IO_R_SUCCESS; ! 733: } ! 734: else if (strcmp(parameterName, APPLE96_STORE_TIMESTAMP) == 0) { ! 735: /* ! 736: * Count ! 737: * 1: tag, <zero>, current time ! 738: * 2: tag, value, current time ! 739: * 4: tag, value, user's time ! 740: */ ! 741: switch (*count) { ! 742: case 1: ! 743: StoreTimestamp(parameterArray[0], 0); ! 744: ioReturn = IO_R_SUCCESS; ! 745: break; ! 746: case 2: ! 747: StoreTimestamp(parameterArray[0], parameterArray[1]); ! 748: ioReturn = IO_R_SUCCESS; ! 749: break; ! 750: case 4: ! 751: StoreNSecTimestamp( ! 752: parameterArray[0], ! 753: parameterArray[1], ! 754: *((ns_time_t *) ¶meterArray[2]) ! 755: ); ! 756: ioReturn = IO_R_SUCCESS; ! 757: break; ! 758: default: ! 759: break; /* Failure */ ! 760: } ! 761: } ! 762: else if (strcmp(parameterName, APPLE96_READ_TIMESTAMP) == 0) { ! 763: /* ! 764: * Read the timestamp array: ! 765: * parameterArray -> result buffer (TimestampDataRecord vector) ! 766: * count -> maximum number of integers to return ! 767: * <- set to the actual number of integers returned. ! 768: * Note that, because count is a number of integers, clients should ! 769: * call this as follows: ! 770: * TimestampDataRecord myTimestamps[123]; ! 771: * unsigned count; ! 772: * count = sizeof (myTimestamps) / sizeof (unsigned); ! 773: * [scsiDevice getIntValues ! 774: * : (unsigned int *) myTimestamps ! 775: * forParameter : APPLE96_READ_TIMESTAMP ! 776: * count : &count ! 777: * ]; ! 778: * count = (count * sizeof (unsigned)) / sizeof (TimestampDataRecord); ! 779: * for (i = 0; i < count; i++) { ! 780: * Process(myTimestamps[i]); ! 781: * } ! 782: */ ! 783: unsigned vectorSize = ((*count) * sizeof(unsigned)) ! 784: / sizeof (TimestampDataRecord); ! 785: ReadTimestampVector((TimestampDataPtr) parameterArray, &vectorSize); ! 786: *count = (vectorSize * sizeof (TimestampDataRecord)) ! 787: / sizeof (unsigned); ! 788: ioReturn = IO_R_SUCCESS; ! 789: } ! 790: else { ! 791: ioReturn = [super getIntValues : parameterArray ! 792: forParameter : parameterName ! 793: count : count]; ! 794: } ! 795: /* RESULT(ioReturn); */ ! 796: return (ioReturn); ! 797: } ! 798: ! 799: ! 800: #endif /* APPLE96_ENABLE_GET_SET */ ! 801: ! 802: @end /* Apple96_SCSI */ ! 803:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.