|
|
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: * SCSIDiskPrivate.m - Implementation of Private methods for SCSIDisk 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: * ! 40: * 11-Feb-91 Doug Mitchell at NeXT ! 41: * Created. ! 42: */ ! 43: ! 44: #define MACH_USER_API 1 ! 45: #undef KERNEL_PRIVATE ! 46: ! 47: #import <sys/types.h> ! 48: #import <driverkit/SCSIDiskPrivate.h> ! 49: #import <driverkit/SCSIDiskTypes.h> ! 50: #import <driverkit/SCSIDiskThread.h> ! 51: #import <driverkit/SCSIDisk.h> ! 52: #import <driverkit/IODiskPartition.h> ! 53: #import <driverkit/scsiTypes.h> ! 54: #import <bsd/dev/scsireg.h> ! 55: #import <driverkit/xpr_mi.h> ! 56: #import <driverkit/return.h> ! 57: #import <driverkit/align.h> ! 58: #import <driverkit/generalFuncs.h> ! 59: #import <kernserv/prototypes.h> ! 60: #import <mach/mach_interface.h> ! 61: #import <machkit/NXLock.h> ! 62: ! 63: static int moveString(char *inp, char *outp, int inlength, int outlength); ! 64: ! 65: @implementation SCSIDisk(Private) ! 66: ! 67: /* ! 68: * One-time only initialization. ! 69: */ ! 70: - initResources ! 71: { ! 72: /* ! 73: * Radar 2005639: Initialize the instance with the ! 74: * compiled-in number of threads. ! 75: */ ! 76: #if defined(i386) || defined(hppa) ! 77: return ([self initResourcesWithThreadCount : NUM_SD_THREADS_MAX]); ! 78: #else ! 79: return ([self initResourcesWithThreadCount : NUM_SD_THREADS_MIN]); ! 80: #endif ! 81: } ! 82: ! 83: - initResourcesWithThreadCount ! 84: : (int) threadCount ! 85: { ! 86: int threadNum; ! 87: ! 88: queue_init(&_ioQueueDisk); ! 89: queue_init(&_ioQueueNodisk); ! 90: _ioQLock = [NXConditionLock alloc]; ! 91: [_ioQLock initWith:NO_WORK_AVAILABLE]; ! 92: ! 93: /* ! 94: * This gets re-init'd per updateReadyState by IODiskPartitionProbe:. ! 95: */ ! 96: [self setLastReadyState:IO_NotReady]; ! 97: _ejectLock = [NXConditionLock alloc]; ! 98: [_ejectLock initWith:0]; ! 99: _numDiskIos = 0; ! 100: _ejectPending = NO; ! 101: _isReserved = 0; ! 102: _isRegistered = 0; ! 103: ! 104: ! 105: /* ! 106: * Start up some I/O threads to perform the actual work of this device. ! 107: * FIXME - there should only be one thread if target does not ! 108: * implement command queueing, and more (at least two, max TBD) ! 109: * if target does implement command queueing. ! 110: */ ! 111: _numThreads = 0; ! 112: /* ! 113: * Radar 2005639: use the requested number of threads. ! 114: */ ! 115: for(threadNum=0; threadNum < threadCount; threadNum++) ! 116: { ! 117: _thread[threadNum] = IOForkThread((IOThreadFunc)sdIoThread, ! 118: self); ! 119: _numThreads++; ! 120: } ! 121: return self; ! 122: } ! 123: ! 124: /* ! 125: * Device-specific initialization. We just do enough here to do some ! 126: * I/O and to find out if the requested target/lun is a SCSI disk device. ! 127: * This function is "reusable" for a given instance of SCSIDisk; initResources ! 128: * must have been called exactly once prior to any use of this method. ! 129: */ ! 130: ! 131: #define DRIVE_TYPE_LENGTH 80 ! 132: ! 133: - (sdInitReturn_t)SCSIDiskInit :(int)iunit /* IODevice unit # */ ! 134: targetId : (u_char)Target ! 135: lun : (u_char)Lun ! 136: controller : controllerId ! 137: { ! 138: inquiry_reply_t inquiryData; ! 139: sc_status_t rtn; ! 140: char driveType[DRIVE_TYPE_LENGTH]; /* name from Inquiry */ ! 141: char *outp; ! 142: char deviceName[30]; ! 143: char location[IO_STRING_LENGTH]; ! 144: ! 145: xpr_sd("SCSIDiskInit: iunit %d target %d lun %d\n", ! 146: iunit, Target, Lun, 4,5); ! 147: ! 148: /* ! 149: * init common instance variables. ! 150: */ ! 151: _controller = controllerId; ! 152: _target = Target; ! 153: _lun = Lun; ! 154: [self setUnit:iunit]; ! 155: sprintf(deviceName, "sd%d", iunit); ! 156: [self setName:deviceName]; ! 157: ! 158: /* ! 159: * Try an Inquiry command. ! 160: */ ! 161: bzero(&inquiryData, sizeof(inquiry_reply_t)); ! 162: rtn = [self sdInquiry:&inquiryData]; ! 163: switch(rtn) { ! 164: case SR_IOST_GOOD: ! 165: break; ! 166: case SR_IOST_SELTO: ! 167: return(SDR_SELECTTO); ! 168: default: ! 169: return(SDR_ERROR); ! 170: } ! 171: ! 172: /* ! 173: * Is it a disk? ! 174: */ ! 175: if(inquiryData.ir_qual != DEVQUAL_OK) { ! 176: return(SDR_NOTADISK); ! 177: } ! 178: switch(inquiryData.ir_devicetype) { ! 179: case DEVTYPE_DISK: ! 180: case DEVTYPE_WORM: ! 181: case DEVTYPE_OPTICAL: ! 182: case DEVTYPE_CDROM: ! 183: break; ! 184: default: ! 185: return(SDR_NOTADISK); ! 186: } ! 187: ! 188: /* ! 189: * The top 3 bits (ir_qual) have to be 0, so throw 'em out. ! 190: */ ! 191: _inquiryDeviceType = inquiryData.ir_devicetype; ! 192: if(inquiryData.ir_removable) ! 193: [self setRemovable:1]; ! 194: ! 195: /* ! 196: * Compress multiple blanks out of the vendor id and product ID. ! 197: */ ! 198: outp = driveType; ! 199: outp += moveString((char *)&inquiryData.ir_vendorid, ! 200: outp, ! 201: 8, ! 202: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 203: if(*(outp - 1) != ' ') ! 204: *outp++ = ' '; ! 205: outp += moveString((char *)&inquiryData.ir_productid, ! 206: outp, ! 207: 16, ! 208: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 209: if(*(outp - 1) != ' ') ! 210: *outp++ = ' '; ! 211: outp += moveString((char *)&inquiryData.ir_revision, ! 212: outp, ! 213: 4, ! 214: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 215: *outp = '\0'; ! 216: [self setDriveName:driveType]; ! 217: sprintf(location,"Target %d LUN %d at %s", _target, _lun, ! 218: [controllerId name]); ! 219: [self setLocation:location]; ! 220: IOLog("%s: %s\n", deviceName, driveType); ! 221: ! 222: /* ! 223: * Do a Test Unit Ready to clear a possible Unit Attention condition. ! 224: * We don't care about the result. ! 225: */ ! 226: [self updateReadyState]; ! 227: ! 228: /* ! 229: * Start up motor. We'll ignore errors on this one too. ! 230: */ ! 231: [self scsiStartStop:SS_START inhibitRetry:YES]; ! 232: ! 233: /* ! 234: * Let's find out some more info. An error on the ! 235: * updatePhysicalParameters could mean no disk present; that's OK... ! 236: */ ! 237: [self setFormattedInternal:0]; // until we do a successful r/w ! 238: rtn = [self updatePhysicalParameters]; ! 239: if(rtn) { ! 240: xpr_sd("SCSIDiskInit: updatePhysicalParameters failed; " ! 241: "continuing\n", ! 242: 1,2,3,4,5); ! 243: } ! 244: ! 245: /* ! 246: * log device name. DiskObject will log block_size and capacity. ! 247: */ ! 248: ! 249: bzero(driveType, DRIVE_TYPE_LENGTH); ! 250: ! 251: /* ! 252: * Compress multiple blanks out of the vendor id and product ID. ! 253: */ ! 254: outp = driveType; ! 255: outp += moveString((char *)&inquiryData.ir_vendorid, ! 256: outp, ! 257: 8, ! 258: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 259: if(*(outp - 1) != ' ') ! 260: *outp++ = ' '; ! 261: outp += moveString((char *)&inquiryData.ir_productid, ! 262: outp, ! 263: 16, ! 264: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 265: if(*(outp - 1) != ' ') ! 266: *outp++ = ' '; ! 267: outp += moveString((char *)&inquiryData.ir_revision, ! 268: outp, ! 269: 32, ! 270: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 271: *outp = '\0'; ! 272: [self setDriveName:driveType]; ! 273: sprintf(location,"Target %d LUN %d at %s", _target, _lun, ! 274: [controllerId name]); ! 275: [self setLocation:location]; ! 276: [super init]; ! 277: return(SDR_GOOD); ! 278: } ! 279: ! 280: /* ! 281: * Copy inp to outp for up to inlength input characters or outlength output ! 282: * characters. Compress multiple spaces and eliminate nulls. Returns number ! 283: * of characters copied to outp. ! 284: */ ! 285: static int moveString(char *inp, char *outp, int inlength, int outlength) ! 286: { ! 287: int lastCharSpace = 0; ! 288: char *outpStart = outp; ! 289: ! 290: while(inlength && outlength) { ! 291: switch(*inp) { ! 292: case '\0': ! 293: inp++; ! 294: inlength--; ! 295: continue; ! 296: case ' ': ! 297: if(lastCharSpace) { ! 298: inp++; ! 299: inlength--; ! 300: continue; ! 301: } ! 302: lastCharSpace = 1; ! 303: goto copyit; ! 304: default: ! 305: lastCharSpace = 0; ! 306: copyit: ! 307: *outp++ = *inp++; ! 308: inlength--; ! 309: outlength--; ! 310: break; ! 311: } ! 312: } ! 313: return(outp - outpStart); ! 314: } ! 315: ! 316: /* ! 317: * Free up local resources. ! 318: */ ! 319: - free ! 320: { ! 321: int threadNum; ! 322: sdBuf_t *sdBuf; ! 323: ! 324: xpr_sd("SCSIDisk free\n", 1,2,3,4,5); ! 325: ! 326: /* ! 327: * Send a "thread abort" command to each thread. ! 328: */ ! 329: sdBuf = [self allocSdBuf:NULL]; ! 330: sdBuf->command = SDOP_ABORT_THREAD; ! 331: sdBuf->needsDisk = 0; ! 332: for(threadNum=0; threadNum<_numThreads; threadNum++) { ! 333: [self enqueueSdBuf:sdBuf]; ! 334: } ! 335: [self freeSdBuf:sdBuf]; ! 336: ! 337: /* ! 338: * Release our target/lun reservation if we have one. ! 339: */ ! 340: if(_isReserved) { ! 341: #if 1 // Radar Fix #2260508 ! 342: /* ! 343: * LUN 0 will be unreserved. Unreserve ! 344: * all the non-zero LUNs first. ! 345: */ ! 346: [self releaseNonZeroLunsOnTarget:_target]; ! 347: #endif // Radar Fix #2260508 ! 348: [_controller releaseTarget:_target ! 349: lun:_lun ! 350: forOwner:self]; ! 351: } ! 352: [_ioQLock free]; ! 353: return([super free]); ! 354: } ! 355: ! 356: - (IOReturn) reacquireTarget ! 357: { ! 358: IOReturn ret = IO_R_NOT_OPEN; ! 359: ! 360: if(NO == _isReserved) { ! 361: ret = IO_R_SUCCESS; ! 362: _isReserved = YES; ! 363: if( [self isRemovable]) ! 364: [self setLastReadyState:IO_NotReady]; // cause a volCheck probe ! 365: else if( IO_Ready == [self updateReadyState]) { ! 366: id descr; ! 367: // duplicate the volCheck probe of IODiskPartition ! 368: [self updatePhysicalParameters]; ! 369: [self diskBecameReady]; ! 370: descr = [IODeviceDescription new]; ! 371: [descr setDirectDevice:self]; ! 372: if( NO == [IODiskPartition probe:descr]) ! 373: [descr free]; ! 374: } ! 375: } else ! 376: IOLog("SCSIDisk unexpected reacquireTarget\n"); ! 377: ! 378: return( ret); ! 379: } ! 380: ! 381: - (IOReturn) requestReleaseTarget ! 382: { ! 383: IOReturn ret = IO_R_NOT_OPEN; ! 384: id diskPart; ! 385: ! 386: if(_isReserved) { ! 387: if( _allowLoans) { ! 388: diskPart = [self nextLogicalDisk]; // a partition always exists ! 389: ! 390: ret = [diskPart requestRelease]; ! 391: if( ret) ! 392: return( ret); ! 393: ! 394: [self synchronizeCache]; ! 395: [self setLastReadyState:IO_Ready]; // stop volCheck activity ! 396: _isReserved = NO; ! 397: ret = IO_R_SUCCESS; ! 398: } ! 399: } else ! 400: IOLog("SCSIDisk unexpected requestReleaseTarget\n"); ! 401: ! 402: return( ret); ! 403: } ! 404: ! 405: - (IOReturn)getCharValues : (unsigned char *)parameterArray ! 406: forParameter : (IOParameterName)parameterName ! 407: count : (unsigned *)count // in/out ! 408: { ! 409: ! 410: if( 0 == strncmp("IOSCSIDiskAllowLoans", parameterName, strlen("IOSCSIDiskAllowLoans"))) ! 411: _allowLoans = 1; ! 412: else if( 0 == strncmp("IOSCSIDiskDisallowLoans", parameterName, strlen("IOSCSIDiskDisallowLoans"))) ! 413: _allowLoans = 0; ! 414: ! 415: else return( [super getCharValues:parameterArray ! 416: forParameter:parameterName ! 417: count:count]); ! 418: ! 419: return( IO_R_SUCCESS); ! 420: } ! 421: ! 422: /* ! 423: * Internal I/O routines. ! 424: */ ! 425: ! 426: /* ! 427: * Inquiry. inquiryReply does not have to be well aligned. ! 428: * Retries and error logging disabled. ! 429: */ ! 430: - (sc_status_t)sdInquiry : (inquiry_reply_t *)inquiryReply ! 431: { ! 432: IOSCSIRequest scsiReq; ! 433: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 434: sdBuf_t *sdBuf; ! 435: inquiry_reply_t *alignedReply; ! 436: void *freep; ! 437: int freecnt; ! 438: sc_status_t rtn; ! 439: IODMAAlignment dmaAlign; ! 440: ! 441: xpr_sd("sd%d sdInquiry\n", [self unit], 2,3,4,5); ! 442: ! 443: /* ! 444: * Get some well-aligned memory. ! 445: */ ! 446: alignedReply = [_controller allocateBufferOfLength: ! 447: sizeof(inquiry_reply_t) ! 448: actualStart:&freep ! 449: actualLength:&freecnt]; ! 450: bzero(alignedReply, sizeof(inquiry_reply_t)); ! 451: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 452: scsiReq.target = _target; ! 453: scsiReq.lun = _lun; ! 454: scsiReq.read = YES; ! 455: ! 456: /* ! 457: * Get appropriate alignment from controller. ! 458: */ ! 459: [_controller getDMAAlignment:&dmaAlign]; ! 460: if(dmaAlign.readLength > 1) { ! 461: scsiReq.maxTransfer = IOAlign(int, sizeof(inquiry_reply_t), ! 462: dmaAlign.readLength); ! 463: } ! 464: else { ! 465: scsiReq.maxTransfer = sizeof(inquiry_reply_t); ! 466: } ! 467: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE; ! 468: scsiReq.disconnect = 1; ! 469: ! 470: sdBuf = [self allocSdBuf:NULL]; ! 471: sdBuf->command = SDOP_CDB_READ; ! 472: sdBuf->scsiReq = &scsiReq; ! 473: sdBuf->buf = alignedReply; ! 474: sdBuf->client = IOVmTaskSelf(); ! 475: cdbp->c6_opcode = C6OP_INQUIRY; ! 476: cdbp->c6_lun = _lun; ! 477: cdbp->c6_len = sizeof(inquiry_reply_t); ! 478: sdBuf->needsDisk = 0; ! 479: sdBuf->retryDisable = 1; ! 480: ! 481: [self enqueueSdBuf:sdBuf]; ! 482: ! 483: if(scsiReq.driverStatus == SR_IOST_GOOD) { ! 484: unsigned required = (char *)(&alignedReply->ir_zero3) - ! 485: (char *)(alignedReply); ! 486: if(scsiReq.bytesTransferred < required) { ! 487: IOLog("%s: bad DMA Transfer count (%d) on Inquiry\n", ! 488: [self name], scsiReq.bytesTransferred); ! 489: rtn = SR_IOST_HW; ! 490: } ! 491: else { ! 492: /* ! 493: * Copy data back to caller's struct. Zero the ! 494: * portion of alignedReply which did not get valid ! 495: * data; the last flush out of the DMA pipe could ! 496: * have written trash to it (and our caller ! 497: * expects NULL data). ! 498: */ ! 499: unsigned zeroSize; ! 500: ! 501: zeroSize = sizeof(*alignedReply) - ! 502: scsiReq.bytesTransferred; ! 503: if(zeroSize) { ! 504: bzero((char *)alignedReply + ! 505: scsiReq.bytesTransferred, ! 506: zeroSize); ! 507: } ! 508: *inquiryReply = *alignedReply; ! 509: rtn = scsiReq.driverStatus; ! 510: } ! 511: } ! 512: else { ! 513: rtn = scsiReq.driverStatus; ! 514: } ! 515: IOFree(freep, freecnt); ! 516: xpr_sd("sdInquiry: returning %s\n", ! 517: IOFindNameForValue(rtn, IOScStatusStrings), ! 518: 2,3,4,5); ! 519: return rtn; ! 520: } ! 521: ! 522: /* ! 523: * Read Capacity. capacityReply does not have to be well aligned. Fails ! 524: * if disk not ready. ! 525: */ ! 526: - (sc_status_t)sdReadCapacity : (capacity_reply_t *)capacityReply ! 527: { ! 528: IOSCSIRequest scsiReq; ! 529: cdb_10_t *cdbp = &scsiReq.cdb.cdb_c10; ! 530: sdBuf_t *sdBuf; ! 531: capacity_reply_t *alignedReply; ! 532: void *freep; ! 533: int freecnt; ! 534: sc_status_t rtn; ! 535: IODMAAlignment dmaAlign; ! 536: ! 537: xpr_sd("sd%d sdReadCapacity\n", [self unit], 2,3,4,5); ! 538: ! 539: /* ! 540: * Get some well-aligned memory. ! 541: */ ! 542: alignedReply = [_controller allocateBufferOfLength: ! 543: sizeof(capacity_reply_t) ! 544: actualStart:&freep ! 545: actualLength:&freecnt]; ! 546: ! 547: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 548: scsiReq.target = _target; ! 549: scsiReq.lun = _lun; ! 550: scsiReq.read = YES; ! 551: ! 552: /* ! 553: * Get appropriate alignment from controller. ! 554: */ ! 555: [_controller getDMAAlignment:&dmaAlign]; ! 556: if(dmaAlign.readLength > 1) { ! 557: scsiReq.maxTransfer = IOAlign(int, sizeof(capacity_reply_t), ! 558: dmaAlign.readLength); ! 559: } ! 560: else { ! 561: scsiReq.maxTransfer = sizeof(capacity_reply_t); ! 562: } ! 563: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE; ! 564: scsiReq.disconnect = 1; ! 565: ! 566: sdBuf = [self allocSdBuf:NULL]; ! 567: sdBuf->command = SDOP_CDB_READ; ! 568: sdBuf->scsiReq = &scsiReq; ! 569: sdBuf->buf = alignedReply; ! 570: sdBuf->client = IOVmTaskSelf(); ! 571: cdbp->c10_opcode = C10OP_READCAPACITY; ! 572: cdbp->c10_lun = _lun; ! 573: sdBuf->needsDisk = 0; ! 574: ! 575: [self enqueueSdBuf:sdBuf]; ! 576: ! 577: if(scsiReq.driverStatus == SR_IOST_GOOD) { ! 578: #if !i386 ! 579: if(scsiReq.bytesTransferred != sizeof(capacity_reply_t)) { ! 580: IOLog("%s: bad DMA Transfer count (%d) on Read" ! 581: " Capacity\n", ! 582: [self name], scsiReq.bytesTransferred); ! 583: rtn = SR_IOST_HW; ! 584: } ! 585: else { ! 586: #else ! 587: { ! 588: #endif ! 589: /* ! 590: * Copy data back to caller's struct. ! 591: */ ! 592: *capacityReply = *alignedReply; ! 593: rtn = scsiReq.driverStatus; ! 594: } ! 595: } ! 596: else { ! 597: rtn = scsiReq.driverStatus; ! 598: } ! 599: IOFree(freep, freecnt); ! 600: xpr_sd("sdReadCapacity: returning %s\n", ! 601: IOFindNameForValue(rtn, IOScStatusStrings), ! 602: 2,3,4,5); ! 603: return rtn; ! 604: } ! 605: ! 606: ! 607: /* ! 608: * Mode Sense. ! 609: */ ! 610: - (sc_status_t)sdModeSense : (mode_sel_data_t *)modeSenseReply ! 611: { ! 612: IOSCSIRequest scsiReq; ! 613: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 614: sdBuf_t *sdBuf; ! 615: mode_sel_data_t *alignedReply; ! 616: void *freep; ! 617: int freecnt; ! 618: sc_status_t rtn; ! 619: IODMAAlignment dmaAlign; ! 620: ! 621: xpr_sd("sd%d sdModeSense\n", [self unit], 2,3,4,5); ! 622: ! 623: /* ! 624: * Get some well-aligned memory. ! 625: */ ! 626: alignedReply = [_controller allocateBufferOfLength: ! 627: sizeof(mode_sel_data_t) ! 628: actualStart:&freep ! 629: actualLength:&freecnt]; ! 630: ! 631: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 632: scsiReq.target = _target; ! 633: scsiReq.lun = _lun; ! 634: scsiReq.read = YES; ! 635: ! 636: /* ! 637: * Get appropriate alignment from controller. ! 638: */ ! 639: [_controller getDMAAlignment:&dmaAlign]; ! 640: if(dmaAlign.readLength > 1) { ! 641: scsiReq.maxTransfer = IOAlign(int, sizeof(mode_sel_data_t), ! 642: dmaAlign.readLength); ! 643: } ! 644: else { ! 645: scsiReq.maxTransfer = sizeof(mode_sel_data_t); ! 646: } ! 647: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE; ! 648: scsiReq.disconnect = 1; ! 649: ! 650: sdBuf = [self allocSdBuf:NULL]; ! 651: sdBuf->command = SDOP_CDB_READ; ! 652: sdBuf->scsiReq = &scsiReq; ! 653: sdBuf->buf = alignedReply; ! 654: sdBuf->client = IOVmTaskSelf(); ! 655: cdbp->c6_opcode = C6OP_MODESENSE; ! 656: cdbp->c6_lun = _lun; ! 657: cdbp->c6_len = sizeof(mode_sel_data_t); ! 658: sdBuf->needsDisk = 1; ! 659: ! 660: [self enqueueSdBuf:sdBuf]; ! 661: ! 662: if(scsiReq.driverStatus == SR_IOST_GOOD) { ! 663: ! 664: /* ! 665: * Copy data back to caller's struct. ! 666: */ ! 667: *modeSenseReply = *alignedReply; ! 668: rtn = scsiReq.driverStatus; ! 669: } ! 670: else { ! 671: rtn = scsiReq.driverStatus; ! 672: } ! 673: ! 674: IOFree(freep, freecnt); ! 675: ! 676: xpr_sd("sdModeSense: returning %s\n", ! 677: IOFindNameForValue(rtn, IOScStatusStrings), ! 678: 2,3,4,5); ! 679: return rtn; ! 680: } ! 681: ! 682: /* ! 683: * Read data; retries and error reporting disabled. Assumes disk is present. ! 684: */ ! 685: - (IOReturn)sdRawRead : (int)block ! 686: blockCnt:(int)blockCnt ! 687: buffer:(void *)buffer ! 688: { ! 689: sdBuf_t *sdBuf; ! 690: IOReturn rtn; ! 691: ! 692: xpr_sd("sdRawRead block %d cnt %d\n", block, blockCnt, 3,4,5); ! 693: sdBuf = [self allocSdBuf:NULL]; ! 694: sdBuf->command = SDOP_READ; ! 695: sdBuf->block = block; ! 696: sdBuf->blockCnt = blockCnt; ! 697: sdBuf->buf = buffer; ! 698: sdBuf->client = IOVmTaskSelf(); ! 699: sdBuf->needsDisk = 1; ! 700: sdBuf->retryDisable = 1; ! 701: rtn = [self enqueueSdBuf:sdBuf]; ! 702: [self freeSdBuf:sdBuf]; ! 703: xpr_sd("sdRawRead: returning %s\n", [self stringFromReturn:rtn], ! 704: 2,3,4,5); ! 705: return(rtn); ! 706: } ! 707: ! 708: /* ! 709: * Start, stop, eject. ! 710: */ ! 711: - (IOReturn)scsiStartStop : (startStop_t)cmd ! 712: inhibitRetry : (BOOL)inhibitRetry ! 713: { ! 714: IOSCSIRequest scsiReq; ! 715: sdBuf_t *sdBuf; ! 716: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 717: IOReturn rtn; ! 718: ! 719: xpr_sd("%s: scsiStartStop: cmd 0x%x\n", [self name], cmd,3,4,5); ! 720: ! 721: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 722: scsiReq.target = _target; ! 723: scsiReq.lun = _lun; ! 724: scsiReq.timeoutLength = SD_TIMEOUT_EJECT; ! 725: scsiReq.disconnect = 1; ! 726: ! 727: sdBuf = [self allocSdBuf:NULL]; ! 728: sdBuf->scsiReq = &scsiReq; ! 729: sdBuf->retryDisable = inhibitRetry ? 1 : 0; ! 730: sdBuf->needsDisk = 1; ! 731: ! 732: cdbp->c6_opcode = C6OP_STARTSTOP; ! 733: cdbp->c6_lun = _lun; ! 734: ! 735: switch(cmd) { ! 736: case SS_EJECT: ! 737: cdbp->c6_len = C6S_SS_EJECT; ! 738: sdBuf->command = SDOP_EJECT; ! 739: break; ! 740: case SS_STOP: ! 741: cdbp->c6_len = C6S_SS_STOP; ! 742: sdBuf->command = SDOP_CDB_WRITE; ! 743: break; ! 744: case SS_START: ! 745: cdbp->c6_len = C6S_SS_START; ! 746: sdBuf->command = SDOP_CDB_WRITE; ! 747: break; ! 748: } ! 749: ! 750: rtn = [self enqueueSdBuf:sdBuf]; ! 751: xpr_sd("%s scsiStartStop: returning %s\n", [self name], ! 752: [self stringFromReturn:rtn], 3,4,5); ! 753: [self freeSdBuf:sdBuf]; ! 754: return(rtn); ! 755: } ! 756: ! 757: /* ! 758: * Common read/write routine. ! 759: */ ! 760: - (IOReturn) deviceRwCommon : (sdOp_t)command ! 761: block: (u_int) deviceBlock ! 762: length : (u_int)length ! 763: buffer : (void *)buffer ! 764: client : (vm_task_t)client ! 765: pending : (void *)pending ! 766: actualLength : (u_int *)actualLength ! 767: { ! 768: sdBuf_t *sdBuf; ! 769: IOReturn rtn; ! 770: u_int blocksReq; ! 771: u_int block_size; ! 772: u_int dev_size; ! 773: ! 774: /* ! 775: * Note we have to 'fault in' a possible non-present disk in ! 776: * order to get its physical parameters... ! 777: */ ! 778: rtn = [self isDiskReady:YES]; ! 779: switch(rtn) { ! 780: case IO_R_SUCCESS: ! 781: break; ! 782: case IO_R_NO_DISK: ! 783: xpr_sd("%s deviceRwCommon: disk not present\n", ! 784: [self name], 2,3,4,5); ! 785: return(rtn); ! 786: default: ! 787: IOLog("%s deviceRwCommon: bogus return from isDiskReady " ! 788: "(%s)\n", ! 789: [self name], [self stringFromReturn:rtn]); ! 790: return(rtn); ! 791: } ! 792: ! 793: if(![self isFormatted]) ! 794: return(IO_R_UNFORMATTED); ! 795: block_size = [self blockSize]; ! 796: dev_size = [self diskSize]; ! 797: ! 798: /* ! 799: * Verify access and legal parameters. ! 800: */ ! 801: if(length % block_size) { ! 802: xpr_sd("deviceRwCommon: unaligned length\n", 1,2,3,4,5); ! 803: return(IO_R_INVALID); ! 804: } ! 805: blocksReq = length / block_size; ! 806: if((deviceBlock + blocksReq) > dev_size) { ! 807: if(deviceBlock >= dev_size) { ! 808: xpr_sd("deviceRwCommon: invalid " ! 809: "deviceBlock/byte count\n", 1,2,3,4,5); ! 810: return(IO_R_INVALID_ARG); ! 811: } ! 812: /* ! 813: * Truncate. ! 814: */ ! 815: blocksReq = dev_size - deviceBlock; ! 816: xpr_sd("deviceRwCommon: truncating to %d blocks\n", blocksReq, ! 817: 2,3,4,5); ! 818: } ! 819: sdBuf = [self allocSdBuf:pending]; ! 820: sdBuf->command = command; ! 821: sdBuf->block = deviceBlock; ! 822: sdBuf->blockCnt = blocksReq; ! 823: sdBuf->buf = buffer; ! 824: sdBuf->client = client; ! 825: sdBuf->needsDisk = 1; ! 826: rtn = [self enqueueSdBuf:sdBuf]; ! 827: if(pending == NULL) { ! 828: /* ! 829: * Sync I/O. ! 830: */ ! 831: *actualLength = sdBuf->bytesXfr; ! 832: [self freeSdBuf:sdBuf]; ! 833: } ! 834: return(rtn); ! 835: } ! 836: ! 837: /* ! 838: * -- Enqueue an sdBuf on _ioQueue<Disk,Nodisk> ! 839: * -- wake up one of the I/O threads ! 840: * -- wait for I/O complete (if sdBuf->pending == NULL) ! 841: */ ! 842: - (IOReturn)enqueueSdBuf:(sdBuf_t *)sdBuf ! 843: { ! 844: queue_head_t *q; ! 845: ! 846: #ifdef DDM_DEBUG ! 847: if(sdBuf->pending) { ! 848: xpr_sd("enqueueSdBuf: sdBuf 0x%x, ASYNC\n", sdBuf, 2,3,4,5); ! 849: } ! 850: else { ! 851: xpr_sd("enqueueSdBuf: sdBuf 0x%x, SYNC\n", sdBuf, 2,3,4,5); ! 852: } ! 853: #endif DDM_DEBUG ! 854: ! 855: sdBuf->status = IO_R_INVALID; ! 856: [_ioQLock lock]; ! 857: /* ! 858: * TBD - sort by disk block eventually. ! 859: */ ! 860: if(sdBuf->needsDisk) ! 861: q = &_ioQueueDisk; ! 862: else ! 863: q = &_ioQueueNodisk; ! 864: queue_enter(q, sdBuf, sdBuf_t *, link); ! 865: [_ioQLock unlockWith:WORK_AVAILABLE]; ! 866: if(sdBuf->pending != NULL) ! 867: return(IO_R_SUCCESS); ! 868: ! 869: /* ! 870: * wait for I/O complete. ! 871: */ ! 872: [sdBuf->waitLock lockWhen:YES]; ! 873: [sdBuf->waitLock unlockWith:NO]; // for easy reuse ! 874: xpr_sd("enqueueSdBuf: I/O Complete sdBuf 0x%x status %s\n", ! 875: sdBuf, [self stringFromReturn:sdBuf->status], 3,4,5); ! 876: return(sdBuf->status); ! 877: } ! 878: ! 879: /* ! 880: * Allocate and free sdBuf_t's. ! 881: * ! 882: * TBD - we might keep around a queue of free sdBuf_t's. ! 883: */ ! 884: - (sdBuf_t *)allocSdBuf : (void *)pending ! 885: { ! 886: sdBuf_t *sdBuf = IOMalloc(sizeof(sdBuf_t)); ! 887: ! 888: bzero(sdBuf, sizeof(sdBuf_t)); ! 889: if(pending == NULL) { ! 890: sdBuf->waitLock = [NXConditionLock alloc]; ! 891: [sdBuf->waitLock initWith:NO]; ! 892: } ! 893: else ! 894: sdBuf->pending = pending; ! 895: return(sdBuf); ! 896: } ! 897: ! 898: - (void)freeSdBuf : (sdBuf_t *)sdBuf ! 899: { ! 900: if(!sdBuf->pending) { ! 901: [sdBuf->waitLock free]; ! 902: } ! 903: IOFree(sdBuf, sizeof(sdBuf_t)); ! 904: } ! 905: ! 906: #if 1 // Radar Fix #2260508 ! 907: - (void) reserveNonZeroLunsOnTarget : (int) target ! 908: { ! 909: // ! 910: // Reserves all non-zero LUNs for the specified target. If a given ! 911: // LUN is already reserved by someone else, reserveTarget is smart ! 912: // enough to leave it alone and reject our reservation request (no ! 913: // errors are logged). ! 914: // ! 915: // Assumptions: ! 916: // o _controller instance variable is already set ! 917: // ! 918: ! 919: unsigned char tempLun; ! 920: ! 921: for (tempLun = 1; tempLun < SCSI_NLUNS; tempLun++) ! 922: { ! 923: [_controller reserveTarget:target lun:tempLun forOwner:self]; ! 924: } ! 925: } ! 926: ! 927: - (void) releaseNonZeroLunsOnTarget : (int) target ! 928: { ! 929: // ! 930: // Unreserves all non-zero LUNs for the specified target. If a given ! 931: // LUN has been reserved by someone other than us, the releaseTarget ! 932: // method is smart enough to leave the LUN reserved (however, an error ! 933: // will be logged). ! 934: // ! 935: // Assumptions: ! 936: // o _controller instance variable is already set ! 937: // ! 938: ! 939: unsigned char tempLun; ! 940: ! 941: // Release the luns in reverse order to avoid a problem when another ! 942: // client is simultaneously trying to acquire the luns. (This is, ! 943: // of course, impossible, but it can't hurt to be suspicious.) ! 944: ! 945: for (tempLun = SCSI_NLUNS - 1; tempLun >= 1; tempLun--) ! 946: { ! 947: [_controller releaseTarget:target lun:tempLun forOwner:self]; ! 948: } ! 949: } ! 950: #endif // Radar Fix #2260508 ! 951: ! 952: @end ! 953: ! 954: ! 955:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.