|
|
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: /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved. ! 25: * ! 26: * SCSIDisk.m - Implementation of exported methods of SCSI Disk device class. ! 27: * ! 28: * HISTORY ! 29: * ! 30: * 30-Jul-98 Dan Markarian at Apple. See Radar 2260508, 2258860. If the ! 31: * SCSIDisk driver attempts to probe a non-zero LUN and a ! 32: * target exists on LUN 0 that is actively doing (tagged) I/O, ! 33: * the target may abort all commands with an overlapped command ! 34: * error, causing the original command to fail without completion. ! 35: * Suggested work-arounds (for MacOS X Server, release 1): probe ! 36: * only LUN 0. If a target is discovered, reserve all LUNs for ! 37: * that target. This code must be revisited for IOKit. ! 38: * ! 39: * 11-Feb-91 Doug Mitchell at NeXT ! 40: * Created. ! 41: */ ! 42: ! 43: #define MACH_USER_API 1 ! 44: #undef KERNEL_PRIVATE ! 45: ! 46: #import <bsd/sys/types.h> ! 47: #import <driverkit/return.h> ! 48: #import <driverkit/IODisk.h> ! 49: #import <driverkit/SCSIDiskPrivate.h> ! 50: #import <driverkit/SCSIDiskTypes.h> ! 51: #import <driverkit/SCSIDisk.h> ! 52: #import <driverkit/SCSIDiskKern.h> ! 53: #import <driverkit/SCSIStructInlines.h> ! 54: #import <bsd/dev/scsireg.h> ! 55: #import <driverkit/xpr_mi.h> ! 56: #import <kernserv/prototypes.h> ! 57: #import <mach/mach_interface.h> ! 58: #import <driverkit/kernelDiskMethods.h> ! 59: #import <machkit/NXLock.h> ! 60: ! 61: #ifdef DEBUG ! 62: #define SCSI_SA_TEST 0 ! 63: #else DEBUG ! 64: #define SCSI_SA_TEST 0 ! 65: #endif DEBUG ! 66: ! 67: /* ! 68: * FIXME - ensure that diskUnit doesn't exceed NUM_SD_DEV. ! 69: */ ! 70: static int diskUnit = 0; ! 71: ! 72: @implementation SCSIDisk ! 73: ! 74: + (IODeviceStyle)deviceStyle ! 75: { ! 76: return IO_IndirectDevice; ! 77: } ! 78: ! 79: /* ! 80: * The protocol we need as an indirect device. ! 81: */ ! 82: static Protocol *protocols[] = { ! 83: @protocol(IOSCSIControllerExported), ! 84: nil ! 85: }; ! 86: ! 87: + (Protocol **)requiredProtocols ! 88: { ! 89: return protocols; ! 90: } ! 91: ! 92: ! 93: + initialize ! 94: { ! 95: if(self == [SCSIDisk class]) { ! 96: sd_init_idmap(); ! 97: } ! 98: return [super initialize]; ! 99: } ! 100: ! 101: /* ! 102: * probe is invoked at load time. It determines what devices are on the ! 103: * bus and alloc's and init:'s an instance of this class for each one. ! 104: */ ! 105: + (BOOL)probe : deviceDescription; ! 106: { ! 107: char Target, Lun; ! 108: sdInitReturn_t irtn = SDR_ERROR; ! 109: SCSIDisk *diskId = nil; ! 110: IODevAndIdInfo *idMap = sd_idmap(); ! 111: id controllerId = [deviceDescription directDevice]; ! 112: BOOL brtn = NO; ! 113: SCSIDisk *diskIdArray[SCSI_NLUNS]; ! 114: int nLuns; ! 115: /* ! 116: * Radar 2005639 ! 117: */ ! 118: unsigned int paramValue[1]; ! 119: unsigned int count = 1; ! 120: IOReturn ioReturn; ! 121: ! 122: /* asm volatile("int3"); */ ! 123: ! 124: #if hppa ! 125: /* search from the top down on hp since that was done before */ ! 126: for(Target=[controllerId numberOfTargets]-1; Target>=0; Target--) ! 127: #else ! 128: for(Target=0; Target<[controllerId numberOfTargets]; Target++) ! 129: #endif ! 130: { ! 131: ! 132: #if 0 // Prior to Radar Fix #2260508 ! 133: for(Lun=nLuns=0; Lun<SCSI_NLUNS; Lun++) { ! 134: #else // Radar Fix #2260508 ! 135: for(Lun=nLuns=0; Lun<1; Lun++) { ! 136: #endif // Radar Fix #2260508 ! 137: if(diskId == nil) { ! 138: /* ! 139: * Create an instance, do some basic ! 140: * initialization. Set up a default ! 141: * device name for error reporting during ! 142: * initialization. ! 143: */ ! 144: diskId = [SCSIDisk alloc]; ! 145: [diskId setName:"SCSIDisk"]; ! 146: /* ! 147: * Radar 2005639. If the controller implements ! 148: * the getIntValues APPLE_MAX_THREADS selector, ! 149: * instantiate with the specified number of ! 150: * of threads, otherwise let the diskID ! 151: * instantiate itself with its default number. ! 152: */ ! 153: ioReturn = [controllerId getIntValues ! 154: : ¶mValue[0] ! 155: forParameter : APPLE_MAX_THREADS ! 156: count : &count]; ! 157: if (ioReturn == IO_R_SUCCESS && count == 1) { ! 158: IOLog("%s: %s requests %d threads\n", ! 159: [self name], ! 160: [controllerId name], ! 161: paramValue[0] ! 162: ); ! 163: [diskId initResourcesWithThreadCount ! 164: : paramValue[0]]; ! 165: } ! 166: else { ! 167: IOLog( ! 168: "%s: %s does not support %s selector, using default\n", ! 169: [self name], ! 170: [controllerId name], ! 171: APPLE_MAX_THREADS ! 172: ); ! 173: [diskId initResources]; ! 174: } ! 175: [diskId setDevAndIdInfo:&(idMap[diskUnit])]; ! 176: } ! 177: if([controllerId reserveTarget:Target ! 178: lun:Lun ! 179: forOwner:diskId]) { ! 180: /* ! 181: * Someone already has this one. ! 182: */ ! 183: continue; ! 184: } ! 185: diskId->_isReserved = 1; ! 186: #if 1 // Radar Fix #2260508 ! 187: /* ! 188: * A valid target at LUN 0 has been reserved: reserve ! 189: * all non-zero LUNs as well. Note that _controller ! 190: * must be set before calling this next method, so go ! 191: * ahead and set it ourselves since the diskId object ! 192: * might be newly allocated (and yet-uninitialized). ! 193: */ ! 194: diskId->_controller = controllerId; ! 195: [diskId reserveNonZeroLunsOnTarget:Target]; ! 196: #endif // Radar Fix #2260508 ! 197: irtn = [diskId SCSIDiskInit:(int)diskUnit ! 198: targetId:Target ! 199: lun:Lun ! 200: controller:controllerId]; ! 201: [diskId setDeviceDescription:deviceDescription]; ! 202: switch(irtn) { ! 203: case SDR_GOOD: ! 204: /* ! 205: * Postpone registering this device ! 206: * until we have looked at all other LUNs. ! 207: * This prevents I/O to multiple LUNs ! 208: * while we are probing, which is not handled ! 209: * well by some devices. ! 210: */ ! 211: diskIdArray[nLuns++] = diskId; ! 212: diskUnit++; ! 213: diskId = nil; ! 214: brtn = YES; ! 215: break; ! 216: ! 217: default: ! 218: #if 1 // Radar Fix #2260508 ! 219: /* ! 220: * LUN 0 will be unreserved: unreserve all ! 221: * non-zero LUNs first. Note _controller ! 222: * is already set at this point. ! 223: */ ! 224: [diskId releaseNonZeroLunsOnTarget:Target]; ! 225: #endif // Radar Fix #2260508 ! 226: [controllerId releaseTarget:Target ! 227: lun:Lun ! 228: forOwner:diskId]; ! 229: diskId->_isReserved = 0; ! 230: ! 231: if(irtn == SDR_SELECTTO) { ! 232: /* ! 233: * Skip the rest of the luns on ! 234: * this target. ! 235: */ ! 236: goto nextTarget; ! 237: } ! 238: /* ! 239: * else try next lun. ! 240: */ ! 241: } ! 242: } /* for lun */ ! 243: nextTarget: ! 244: /* Now we have looked at all luns. */ ! 245: for (Lun=0; Lun < nLuns; Lun++) { ! 246: SCSIDisk *thisId = diskIdArray[Lun]; ! 247: /* ! 248: * All right! Have IODisk superclass take ! 249: * care of the rest. ! 250: */ ! 251: [thisId setDeviceKind:"SCSIDisk"]; ! 252: [thisId setIsPhysical:YES]; ! 253: [thisId registerDevice]; ! 254: thisId->_isRegistered = 1; ! 255: } ! 256: continue; ! 257: } /* for target */ ! 258: ! 259: /* ! 260: * Free up leftover owner and id. At this point, diskId does NOT have ! 261: * a target/lun reserved. ! 262: */ ! 263: if(diskId) { ! 264: [diskId free]; ! 265: } ! 266: ! 267: #if SCSI_SA_TEST ! 268: diskTest("sd0"); ! 269: #endif SCSI_SA_TEST ! 270: return brtn; ! 271: } ! 272: ! 273: /* ! 274: * IODiskReadingAndWriting protocol methods. ! 275: */ ! 276: - (IOReturn) readAt : (unsigned)offset ! 277: length : (unsigned)length ! 278: buffer : (unsigned char *)buffer ! 279: actualLength : (unsigned *)actualLength ! 280: client : (vm_task_t)client ! 281: { ! 282: IOReturn rtn; ! 283: ! 284: xpr_sd("%s read: offset 0x%x length 0x%x\n", ! 285: [self name], offset, length, 4,5); ! 286: rtn = [self deviceRwCommon : SDOP_READ ! 287: block : offset ! 288: length : length ! 289: buffer : buffer ! 290: client: client ! 291: pending : NULL ! 292: actualLength : actualLength]; ! 293: xpr_sd("%s read: RETURNING %s\n", [self name], ! 294: [self stringFromReturn:rtn], 3,4,5); ! 295: return(rtn); ! 296: } ! 297: ! 298: - (IOReturn) readAsyncAt : (unsigned)offset ! 299: length : (unsigned)length ! 300: buffer : (unsigned char *)buffer ! 301: pending : (void *)pending ! 302: client : (vm_task_t)client ! 303: { ! 304: IOReturn rtn; ! 305: ! 306: xpr_sd("%s readAsync: offset 0x%x length 0x%x\n", ! 307: [self name], offset, length, 4,5); ! 308: rtn = [self deviceRwCommon : SDOP_READ ! 309: block : offset ! 310: length : length ! 311: buffer : buffer ! 312: client : client ! 313: pending : (void *)pending ! 314: actualLength : NULL]; ! 315: xpr_sd("%s readAsync: RETURNING %s\n", [self name], ! 316: [self stringFromReturn:rtn], 3,4,5); ! 317: return(rtn); ! 318: } ! 319: ! 320: - (IOReturn) writeAt : (unsigned)offset ! 321: length : (unsigned)length ! 322: buffer : (unsigned char *)buffer ! 323: actualLength : (unsigned *)actualLength ! 324: client : (vm_task_t)client ! 325: { ! 326: IOReturn rtn; ! 327: ! 328: xpr_sd("%s write: offset 0x%x length 0x%x\n", ! 329: [self name], offset, length, 4,5); ! 330: rtn = [self deviceRwCommon : SDOP_WRITE ! 331: block : offset ! 332: length : length ! 333: buffer : buffer ! 334: client: client ! 335: pending : NULL ! 336: actualLength : actualLength]; ! 337: xpr_sd("%s deviceWrite: RETURNING %s\n", [self name], ! 338: [self stringFromReturn:rtn], 3,4,5); ! 339: return(rtn); ! 340: } ! 341: ! 342: - (IOReturn) writeAsyncAt : (unsigned)offset ! 343: length : (unsigned)length ! 344: buffer : (unsigned char *)buffer ! 345: pending : (void *)pending ! 346: client : (vm_task_t)client ! 347: { ! 348: IOReturn rtn; ! 349: ! 350: xpr_sd("%s writeAsync: offset 0x%x length 0x%x\n", ! 351: [self name], offset, length, 4,5); ! 352: rtn = [self deviceRwCommon : SDOP_WRITE ! 353: block : offset ! 354: length : length ! 355: buffer : buffer ! 356: client : client ! 357: pending : (void *)pending ! 358: actualLength : NULL]; ! 359: xpr_sd("%s writeAsync: RETURNING %s\n", [self name], ! 360: [self stringFromReturn:rtn], 3,4,5); ! 361: return(rtn); ! 362: } ! 363: ! 364: ! 365: - (void) synchronizeCache ! 366: { ! 367: IOSCSIRequest scsiReq; ! 368: cdb_10_t *cdbp = &scsiReq.cdb.cdb_c10; ! 369: sdBuf_t *sdBuf; ! 370: ! 371: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 372: scsiReq.target = _target; ! 373: scsiReq.lun = _lun; ! 374: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE; ! 375: scsiReq.disconnect = 1; ! 376: ! 377: sdBuf = [self allocSdBuf:NULL]; ! 378: sdBuf->command = SDOP_CDB_WRITE; ! 379: sdBuf->scsiReq = &scsiReq; ! 380: sdBuf->retryDisable = 1; ! 381: sdBuf->needsDisk = 0; ! 382: ! 383: /* Zeroing the lba and count fields will cause the drive to ! 384: * flush everything. We should be able to zero these fields ! 385: * explicitly, but for some reason the 10-byte commands don't ! 386: * have the proper field definitions. ! 387: */ ! 388: bzero(cdbp,10); ! 389: ! 390: cdbp->c10_opcode = 0x35; ! 391: cdbp->c10_lun = _lun; ! 392: ! 393: [self enqueueSdBuf:sdBuf]; ! 394: ! 395: [self freeSdBuf:sdBuf]; ! 396: } ! 397: ! 398: - (IODiskReadyState)updateReadyState ! 399: { ! 400: IOSCSIRequest scsiReq; ! 401: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 402: sdBuf_t *sdBuf; ! 403: IODiskReadyState readyState; ! 404: esense_reply_t senseReply; ! 405: ! 406: xpr_sd("%s updateReadyState\n", [self name], 2,3,4,5); ! 407: ! 408: if( NO == _isReserved) { ! 409: return([self lastReadyState]); ! 410: } ! 411: ! 412: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 413: scsiReq.target = _target; ! 414: scsiReq.lun = _lun; ! 415: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE; ! 416: scsiReq.disconnect = 1; ! 417: ! 418: sdBuf = [self allocSdBuf:NULL]; ! 419: sdBuf->command = SDOP_CDB_WRITE; ! 420: sdBuf->scsiReq = &scsiReq; ! 421: sdBuf->retryDisable = 1; ! 422: sdBuf->needsDisk = 0; ! 423: ! 424: cdbp->c6_opcode = C6OP_TESTRDY; ! 425: cdbp->c6_lun = _lun; ! 426: ! 427: [self enqueueSdBuf:sdBuf]; ! 428: ! 429: /* ! 430: * FIXME - how to distinguish not ready from no disk??? ! 431: */ ! 432: switch(scsiReq.driverStatus) { ! 433: case SR_IOST_GOOD: ! 434: readyState = IO_Ready; ! 435: break; ! 436: default: ! 437: readyState = IO_NotReady; ! 438: break; ! 439: ! 440: } ! 441: xpr_sd("%s updateReadyState: DONE; state = %s\n", ! 442: [self name], ! 443: IOFindNameForValue(readyState, readyStateValues), 3,4,5); ! 444: [self freeSdBuf:sdBuf]; ! 445: return(readyState); ! 446: } ! 447: ! 448: /* ! 449: * IOPhysicalDiskMethods protocol methods. ! 450: */ ! 451: - (IOReturn) ejectPhysical ! 452: { ! 453: return [self scsiStartStop:SS_EJECT inhibitRetry:NO]; ! 454: } ! 455: ! 456: ! 457: /* ! 458: * Get physical parameters (dev_size, block_size, etc.) from new disk. ! 459: */ ! 460: - (IOReturn)updatePhysicalParameters ! 461: { ! 462: capacity_reply_t capacityData; ! 463: mode_sel_data_t modeData; ! 464: sc_status_t rtn; ! 465: int block; ! 466: void *dataBuf; ! 467: void *freePtr; ! 468: unsigned freeCnt; ! 469: u_int block_size; ! 470: BOOL wp = NO; ! 471: int i; ! 472: ! 473: rtn = [self updateReadyState]; ! 474: if(rtn) { ! 475: return IO_R_NOT_READY; ! 476: } ! 477: rtn = [self sdReadCapacity:&capacityData]; ! 478: if(rtn) { ! 479: return(IO_R_IO); ! 480: } ! 481: [self setDiskSize:scsi_lastlba(&capacityData) + 1]; ! 482: [self setBlockSize:scsi_blklen(&capacityData)]; ! 483: ! 484: /* ! 485: * Try reading a block to see if disk is formatted. ! 486: */ ! 487: block_size = [self blockSize]; ! 488: dataBuf = [_controller allocateBufferOfLength:block_size ! 489: actualStart:&freePtr ! 490: actualLength:&freeCnt]; ! 491: block = 10; ! 492: for(i=0; i<5; i++) { ! 493: rtn = [self sdRawRead:block blockCnt:1 buffer:dataBuf]; ! 494: if(rtn == IO_R_SUCCESS) { ! 495: break; ! 496: } ! 497: block += 10; ! 498: } ! 499: if(rtn == IO_R_SUCCESS) ! 500: [self setFormattedInternal:1]; ! 501: else ! 502: [self setFormattedInternal:0]; ! 503: ! 504: IOFree(freePtr, freeCnt); ! 505: ! 506: /* ! 507: * Mark CD-ROMs as write-protected; use a mode sense for the others. ! 508: */ ! 509: ! 510: if(_inquiryDeviceType == DEVTYPE_CDROM) ! 511: wp = YES; ! 512: else { ! 513: bzero(&modeData, sizeof(mode_sel_data_t)); ! 514: rtn = [self sdModeSense:&modeData]; ! 515: ! 516: if (modeData.msd_header.msh_wp) ! 517: wp = YES; ! 518: } ! 519: ! 520: [self setWriteProtected: wp]; ! 521: ! 522: return(IO_R_SUCCESS); ! 523: } ! 524: ! 525: /* ! 526: * Called by volCheck thread when WS has told us that a requested disk is ! 527: * not present. Pending I/Os which require a disk to be present must be ! 528: * aborted. ! 529: */ ! 530: - (void)abortRequest ! 531: { ! 532: sdBuf_t *sdBuf; ! 533: ! 534: xpr_sd("%s: abortRequest\n", [self name], 2,3,4,5); ! 535: ! 536: sdBuf = [self allocSdBuf:NULL]; ! 537: sdBuf->command = SDOP_ABORT; ! 538: sdBuf->needsDisk = 0; ! 539: [self enqueueSdBuf:sdBuf]; ! 540: xpr_sd("%s abortRequest: done %s\n", [self name], 2,3,4,5); ! 541: [self freeSdBuf:sdBuf]; ! 542: return; ! 543: } ! 544: ! 545: /* ! 546: * Called by the volCheck thread when a transition to "ready" is detected. ! 547: * Pending I/Os which require a disk may proceed. All we have to do is ! 548: * wakeup the I/O threads which are waiting for something to show up ! 549: * in an I/O queue. ! 550: */ ! 551: - (void)diskBecameReady ! 552: { ! 553: xpr_sd("diskBecameReady: %s\n", [self name], 2,3,4,5); ! 554: [_ioQLock lock]; ! 555: [_ioQLock unlockWith:WORK_AVAILABLE]; ! 556: } ! 557: ! 558: /* ! 559: * Inquire if disk is present; if not, and 'prompt' is YES, ask for it. ! 560: * Returns IO_R_NO_DISK if: ! 561: * prompt YES, disk not present, and user cancels request for disk. ! 562: * prompt NO, disk not present. ! 563: * Else returns IO_R_SUCCESS. ! 564: */ ! 565: - (IOReturn)isDiskReady : (BOOL)prompt ! 566: { ! 567: sdBuf_t *sdBuf; ! 568: IOReturn rtn; ! 569: ! 570: xpr_sd("%s: diskBecameReady\n", [self name], 2,3,4,5); ! 571: ! 572: if( NO == _isReserved) ! 573: return(IO_R_NO_DISK); ! 574: ! 575: if([self lastReadyState] == IO_Ready) { ! 576: /* ! 577: * This one's easy... ! 578: */ ! 579: return(IO_R_SUCCESS); ! 580: } ! 581: if(!prompt) { ! 582: return(IO_R_NO_DISK); ! 583: } ! 584: sdBuf = [self allocSdBuf:NULL]; ! 585: sdBuf->command = SDOP_PROBEDISK; ! 586: sdBuf->needsDisk = 1; ! 587: rtn = [self enqueueSdBuf:sdBuf]; ! 588: xpr_sd("%s diskBecameReady: returning %s\n", [self name], ! 589: [self stringFromReturn:rtn], 3,4,5); ! 590: [self freeSdBuf:sdBuf]; ! 591: return(rtn); ! 592: } ! 593: ! 594: /* ! 595: * We have to override IODisk's setLastReadyState: so we know when to ! 596: * clear our local ejectPending flag. ! 597: */ ! 598: - (void)setLastReadyState : (IODiskReadyState)readyState ! 599: { ! 600: xpr_sd("sd setLastReadyState\n", 1,2,3,4,5); ! 601: if(_ejectPending && (readyState != IO_Ejecting)) ! 602: _ejectPending = 0; ! 603: [super setLastReadyState:readyState]; ! 604: } ! 605: ! 606: /* ! 607: * Exported methods unique to the SCSIDisk class. ! 608: * Note caller must provide well-aligned DMA buffers. ! 609: */ ! 610: - (IOReturn) sdCdbRead : (IOSCSIRequest *)scsiReq /* SCSI parameters */ ! 611: buffer:(void *)buffer /* data destination */ ! 612: client:(vm_task_t)client; ! 613: { ! 614: sdBuf_t *sdBuf; ! 615: IOReturn rtn; ! 616: ! 617: xpr_sd("sd%d sdCdbRead: opcode = 0x%x\n", [self unit], ! 618: scsiReq->cdb.cdb_opcode, 3,4,5); ! 619: ! 620: sdBuf = [self allocSdBuf:NULL]; ! 621: sdBuf->command = SDOP_CDB_READ; ! 622: sdBuf->scsiReq = scsiReq; ! 623: sdBuf->buf = buffer; ! 624: sdBuf->client = client; ! 625: sdBuf->pending = NULL; ! 626: sdBuf->needsDisk = 0; ! 627: rtn = [self enqueueSdBuf:sdBuf]; ! 628: xpr_sd("sd%d sdCdbRead: returning %s\n", [self unit], ! 629: [self stringFromReturn:rtn], 3,4,5); ! 630: [self freeSdBuf:sdBuf]; ! 631: return(rtn); ! 632: } ! 633: ! 634: - (IOReturn) sdCdbWrite : (IOSCSIRequest *)scsiReq /* SCSI parameters */ ! 635: buffer:(void *)buffer /* data destination */ ! 636: client:(vm_task_t)client ! 637: { ! 638: sdBuf_t *sdBuf; ! 639: IOReturn rtn; ! 640: ! 641: xpr_sd("sd%d sdCdbWrite: opcode = 0x%x\n", [self unit], ! 642: scsiReq->cdb.cdb_opcode, 3,4,5); ! 643: ! 644: sdBuf = [self allocSdBuf:NULL]; ! 645: sdBuf->command = SDOP_CDB_WRITE; ! 646: sdBuf->scsiReq = scsiReq; ! 647: sdBuf->buf = buffer; ! 648: sdBuf->client = client; ! 649: sdBuf->pending = NULL; ! 650: sdBuf->needsDisk = 0; ! 651: rtn = [self enqueueSdBuf:sdBuf]; ! 652: xpr_sd("sd%d sdCdbWrite: returning %s\n", [self unit], ! 653: [self stringFromReturn:rtn], 3,4,5); ! 654: [self freeSdBuf:sdBuf]; ! 655: return(rtn); ! 656: } ! 657: ! 658: - (int)target ! 659: { ! 660: return _target; ! 661: } ! 662: ! 663: - (int)lun ! 664: { ! 665: return _lun; ! 666: } ! 667: ! 668: /* ! 669: * This is mainly here for the convenience of 486 CDROM boot. It's cheap so ! 670: * we'll leave it in for other platforms too. ! 671: */ ! 672: - (unsigned char)inquiryDeviceType ! 673: { ! 674: return _inquiryDeviceType; ! 675: } ! 676: ! 677: - controller ! 678: { ! 679: return _controller; ! 680: } ! 681: ! 682: - getDevicePath:(char *)path maxLength:(int)maxLen useAlias:(BOOL)doAlias ! 683: { ! 684: if( [super getDevicePath:path maxLength:maxLen useAlias:doAlias]) { ! 685: ! 686: char unitStr[ 12 ]; ! 687: int len = maxLen - strlen( path); ! 688: ! 689: sprintf( unitStr, "/@%x", [self target]); ! 690: len -= strlen( unitStr); ! 691: if( len < 0) ! 692: return( nil); ! 693: strcat( path, unitStr); ! 694: if( [self lun]) { ! 695: sprintf( unitStr, ",%x", [self lun]); ! 696: len -= strlen( unitStr); ! 697: if( len < 0) ! 698: return( nil); ! 699: strcat( path, unitStr); ! 700: } ! 701: return( self); ! 702: } ! 703: return( nil); ! 704: } ! 705: ! 706: - (char *) matchDevicePath:(char *)matchPath ! 707: { ! 708: BOOL matches = NO; ! 709: char * unitStr; ! 710: extern long int strtol(const char *nptr, char **endptr, int base); ! 711: ! 712: unitStr = [super matchDevicePath:matchPath]; ! 713: if( unitStr) { ! 714: unitStr = (char *)strchr( unitStr, '@'); ! 715: if( unitStr) { ! 716: matches = ([self target] == strtol( unitStr + 1, &unitStr, 16)); ! 717: if( matches && (*unitStr == ',')) ! 718: matches = ([self lun] == strtol( unitStr + 1, &unitStr, 16)); ! 719: } ! 720: } ! 721: if( matches) ! 722: return( unitStr); ! 723: else ! 724: return( NULL); ! 725: } ! 726: ! 727: - property_IOUnit:(char *)result length:(unsigned int *)maxLen ! 728: { ! 729: if( [self lun]) ! 730: sprintf( result, "%d,%d", [self target], [self lun]); ! 731: else ! 732: sprintf( result, "%d", [self target]); ! 733: ! 734: return( self); ! 735: } ! 736: ! 737: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen ! 738: { ! 739: static const char * inquiryDevTypeStrings[ 9 ] = { ! 740: 0, IOTypeTape, IOTypePrinter, 0, ! 741: IOTypeWORM, IOTypeCDROM, IOTypeScanner, IOTypeOptical, ! 742: IOTypeChanger ! 743: }; ! 744: ! 745: [super property_IODeviceType:types length:maxLen]; ! 746: ! 747: if( (_inquiryDeviceType <= 8) && inquiryDevTypeStrings[ _inquiryDeviceType ]) { ! 748: strcat( types, " "); ! 749: strcat( types, inquiryDevTypeStrings[ _inquiryDeviceType ]); ! 750: } ! 751: return( self); ! 752: } ! 753: ! 754: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.