|
|
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: * IODisk.m - implementation of generic disk object. ! 27: * ! 28: * HISTORY ! 29: * 31-Jan-91 Doug Mitchell at NeXT ! 30: * Created. ! 31: */ ! 32: ! 33: #import <bsd/sys/types.h> ! 34: #import <driverkit/return.h> ! 35: #import <mach/kern_return.h> ! 36: #import <driverkit/IODisk.h> ! 37: #import <driverkit/Device_ddm.h> ! 38: #ifdef KERNEL ! 39: #import <kernserv/prototypes.h> ! 40: #import <mach/mach_interface.h> ! 41: #else KERNEL ! 42: #import <mach/mach.h> ! 43: #import <bsd/libc.h> ! 44: #endif KERNEL ! 45: #import <driverkit/IOLogicalDisk.h> ! 46: #import <driverkit/IODiskPartition.h> ! 47: #import <driverkit/volCheck.h> ! 48: #import <machkit/NXLock.h> ! 49: #import <driverkit/generalFuncs.h> ! 50: #import <bsd/sys/errno.h> ! 51: #import <driverkit/IODeviceDescription.h> ! 52: ! 53: #ifdef ppc //bknight - 12/16/97 - Radar #2004660 ! 54: #define GROK_APPLE 1 ! 55: #endif //bknight - 12/16/97 - Radar #2004660 ! 56: ! 57: /* ! 58: * For stringFromReturn:. ! 59: */ ! 60: static IONamedValue diskIoReturnValues[] = { ! 61: {IO_R_NO_LABEL, "No Label" }, ! 62: {IO_R_UNFORMATTED, "Disk Not Formatted" }, ! 63: {IO_R_NO_DISK, "Disk Not Present" }, ! 64: {IO_R_NO_BLOCK_ZERO, "Can\'t Read Block 0" }, ! 65: {IO_R_NO_NEXT_PART, "No NeXT partition" }, ! 66: {0, NULL } ! 67: }; ! 68: ! 69: #ifdef DDM_DEBUG ! 70: /* ! 71: * For xpr's. ! 72: */ ! 73: IONamedValue readyStateValues[] = { ! 74: {IO_Ready, "Ready" }, ! 75: {IO_NotReady, "Not Ready" }, ! 76: {IO_NoDisk, "No Disk" }, ! 77: {IO_Ejecting, "Ejecting" }, ! 78: {0, NULL } ! 79: }; ! 80: #endif DDM_DEBUG ! 81: ! 82: @implementation IODisk ! 83: ! 84: /* ! 85: * Public methods. ! 86: */ ! 87: ! 88: /* ! 89: * Public methods to get and set disk parameters. May be overridden by ! 90: * subclass. ! 91: */ ! 92: ! 93: - (unsigned)diskSize ! 94: { ! 95: return(_diskSize); ! 96: } ! 97: ! 98: - (unsigned)blockSize ! 99: { ! 100: return(_blockSize); ! 101: } ! 102: ! 103: - (IOReturn)setFormatted : (BOOL)formattedFlag ! 104: { ! 105: ! 106: /* ! 107: * This is illegal if any attached logicalDisks are open. ! 108: * In the Unix world, this is normally only done on the raw ! 109: * device, an IODiskPartition, which overrides this method. ! 110: */ ! 111: #ifdef KERNEL ! 112: IOPanic("setFormatted: on IODisk"); ! 113: #else KERNEL ! 114: id targ = (id)self; ! 115: ! 116: xpr_disk("DiskObject %s: setFormatted flag = %d\n", ! 117: [self name], formattedFlag, 3,4,5); ! 118: ! 119: if(_nextLogicalDisk && [_nextLogicalDisk isOpen]) { ! 120: xpr_err("%s: setFormatted with logicalDisk open\n", ! 121: [self name], 2,3,4,5); ! 122: return(IO_R_BUSY); ! 123: } ! 124: if(formattedFlag) { ! 125: /* ! 126: * Update our internal device parameters. ! 127: * FIXME - maybe check for respondsTo:. ! 128: */ ! 129: [targ updatePhysicalParameters]; ! 130: _formatted = 1; ! 131: } ! 132: else ! 133: _formatted = 0; ! 134: /* ! 135: * Let any attached logical disks know about this, using the internal ! 136: * version of setFormatted to avoid having our setFormattedInternal: ! 137: * being called back.. ! 138: */ ! 139: if(_nextLogicalDisk) ! 140: [_nextLogicalDisk setFormattedInternal:formattedFlag]; ! 141: #endif KERNEL ! 142: return(IO_R_SUCCESS); ! 143: } ! 144: ! 145: - (BOOL)isFormatted ! 146: { ! 147: return(_formatted); ! 148: } ! 149: ! 150: - (BOOL)isRemovable ! 151: { ! 152: return(_removable); ! 153: } ! 154: ! 155: - (const char *)driveName ! 156: { ! 157: return(_driveName); ! 158: } ! 159: ! 160: - (BOOL)isPhysical ! 161: { ! 162: return(_isPhysical); ! 163: } ! 164: ! 165: - (BOOL)isWriteProtected ! 166: { ! 167: return(_writeProtected); ! 168: } ! 169: ! 170: /* ! 171: * Eject current disk. ! 172: */ ! 173: - (IOReturn) eject ! 174: { ! 175: ! 176: #ifdef KERNEL ! 177: IOPanic("IODisk eject in kernel illegal\n"); ! 178: return(IO_R_UNSUPPORTED); ! 179: #else KERNEL ! 180: ! 181: id targ = (id)self; ! 182: ! 183: if(!_removable) ! 184: return(IO_R_UNSUPPORTED); ! 185: xpr_disk("DiskObject %s eject:\n", [self name], 2,3,4,5); ! 186: ! 187: /* ! 188: * We can't allow this if any logical disks are attached. ! 189: * Normally in the Unix world, eject is invoked on an IODiskPartition, ! 190: * which overrides this method and ends up calling physDev's ! 191: * ejectPhysical. If we're here, that means we must be a ! 192: * physical device. ! 193: */ ! 194: if(_nextLogicalDisk) { ! 195: xpr_disk("DiskObject eject: Logical Disk(s)" ! 196: " Attached\n", 1,2,3,4,5); ! 197: IOLog("%s: Eject attempt with attached logical disks", ! 198: [self name]); ! 199: return(IO_R_OPEN); ! 200: } ! 201: ! 202: /* ! 203: * We know nothing about this disk... ! 204: */ ! 205: _formatted = 0; ! 206: ! 207: /* ! 208: * Can't send this method to self, it's in IOPhysicalDiskMethods ! 209: * protocol. ! 210: * FIXME - probably should check for respondsTo:. ! 211: */ ! 212: return([targ ejectPhysical]); ! 213: #endif KERNEL ! 214: } ! 215: ! 216: /* ! 217: * Get/set parameters used only by subclasses. ! 218: */ ! 219: - (void)setDiskSize : (unsigned)size ! 220: { ! 221: _diskSize = size; ! 222: } ! 223: ! 224: - (void)setBlockSize : (unsigned)size ! 225: { ! 226: _blockSize = size; ! 227: } ! 228: ! 229: - (void)setIsPhysical : (BOOL)isPhysFlag ! 230: { ! 231: _isPhysical = isPhysFlag ? YES : NO; ! 232: } ! 233: ! 234: - nextLogicalDisk ! 235: { ! 236: return(_nextLogicalDisk); ! 237: } ! 238: ! 239: - (void) setRemovable : (BOOL)removableFlag ! 240: { ! 241: _removable = removableFlag ? YES : NO; ! 242: return; ! 243: } ! 244: ! 245: - (void)setDriveName : (const char *)name ! 246: { ! 247: int len; ! 248: ! 249: len = strlen((char *)name); ! 250: if(len >= MAXDNMLEN) ! 251: len = MAXDNMLEN - 1; ! 252: strncpy(_driveName, name, len); ! 253: _driveName[MAXDNMLEN - 1] = '\0'; ! 254: } ! 255: ! 256: - (IODiskReadyState)lastReadyState ! 257: { ! 258: return(_lastReadyState); ! 259: } ! 260: ! 261: - (void)setLastReadyState : (IODiskReadyState)readyState ! 262: { ! 263: _lastReadyState = readyState; ! 264: } ! 265: ! 266: - (void)setWriteProtected : (BOOL)writeProtectedFlag ! 267: { ! 268: _writeProtected = writeProtectedFlag ? YES : NO; ! 269: } ! 270: ! 271: ! 272: /* ! 273: * internal setFormatted - avoids logical disk interaction. ! 274: */ ! 275: - (void)setFormattedInternal:(BOOL)formattedFlag ! 276: { ! 277: xpr_disk("DiskObject %s: setFormattedInternal flag = %d\n", ! 278: [self name], formattedFlag, 3,4,5); ! 279: _formatted = formattedFlag ? YES : NO; ! 280: } ! 281: ! 282: /* ! 283: * Statistics support. ! 284: */ ! 285: - (void)addToBytesRead : (unsigned)bytesRead ! 286: totalTime : (ns_time_t)totalTime ! 287: latentTime : (ns_time_t)latentTime ! 288: { ! 289: unsigned long long ms_ll; ! 290: ! 291: _readOps++; ! 292: _bytesRead += bytesRead; ! 293: ms_ll = totalTime / (1000 * 1000); ! 294: _readTotalTime += ms_ll; ! 295: ms_ll = latentTime / (1000 * 1000); ! 296: _readLatentTime += ms_ll; ! 297: } ! 298: ! 299: - (void)addToBytesWritten : (unsigned)bytesWritten ! 300: totalTime : (ns_time_t)totalTime ! 301: latentTime : (ns_time_t)latentTime ! 302: { ! 303: unsigned long long ms_ll; ! 304: ! 305: _writeOps++; ! 306: _bytesWritten += bytesWritten; ! 307: ms_ll = totalTime / (1000 * 1000); ! 308: _writeTotalTime += ms_ll; ! 309: ms_ll = latentTime / (1000 * 1000); ! 310: _writeLatentTime += ms_ll; ! 311: } ! 312: ! 313: - (void)incrementReadRetries ! 314: { ! 315: _readRetries++; ! 316: } ! 317: ! 318: - (void)incrementReadErrors ! 319: { ! 320: _readErrors++; ! 321: } ! 322: ! 323: - (void)incrementWriteRetries ! 324: { ! 325: _writeRetries++; ! 326: } ! 327: ! 328: - (void)incrementWriteErrors ! 329: { ! 330: _writeErrors++; ! 331: } ! 332: ! 333: - (void)incrementOtherRetries ! 334: { ! 335: _otherRetries++; ! 336: } ! 337: ! 338: - (void)incrementOtherErrors ! 339: { ! 340: _otherErrors++; ! 341: } ! 342: ! 343: ! 344: /* ! 345: * For gathering cumulative statistics. ! 346: */ ! 347: - (IOReturn)getIntValues : (unsigned *)parameterArray ! 348: forParameter : (IOParameterName)parameterName ! 349: count : (unsigned *)count; // in/out ! 350: { ! 351: unsigned int paramArray[IO_DISK_STAT_ARRAY_SIZE]; ! 352: int i; ! 353: int maxCount = *count; ! 354: ! 355: if(maxCount == 0) { ! 356: maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH; ! 357: } ! 358: if(strcmp(parameterName, IO_DISK_STATS) == 0) { ! 359: paramArray[IO_Reads] = _readOps; ! 360: paramArray[IO_BytesRead] = _bytesRead; ! 361: paramArray[IO_TotalReadTime] = _readTotalTime; ! 362: paramArray[IO_LatentReadTime] = _readLatentTime; ! 363: paramArray[IO_ReadRetries] = _readRetries; ! 364: paramArray[IO_ReadErrors] = _readErrors; ! 365: paramArray[IO_Writes] = _writeOps; ! 366: paramArray[IO_BytesWritten] = _bytesWritten; ! 367: paramArray[IO_TotalWriteTime] = _writeTotalTime; ! 368: paramArray[IO_LatentWriteTime] = _writeLatentTime; ! 369: paramArray[IO_WriteRetries] = _writeRetries; ! 370: paramArray[IO_WriteErrors] = _writeErrors; ! 371: paramArray[IO_OtherRetries] = _otherRetries; ! 372: paramArray[IO_OtherErrors] = _otherErrors; ! 373: ! 374: *count = 0; ! 375: for(i=0; i<IO_DISK_STAT_ARRAY_SIZE; i++) { ! 376: if(*count == maxCount) ! 377: break; ! 378: parameterArray[i] = paramArray[i]; ! 379: (*count)++; ! 380: } ! 381: return IO_R_SUCCESS; ! 382: } ! 383: else if(strcmp(parameterName, IO_IS_A_DISK) == 0) { ! 384: /* ! 385: * No data; just let caller know we're a disk. ! 386: */ ! 387: *count = 0; ! 388: return IO_R_SUCCESS; ! 389: } ! 390: else if(strcmp(parameterName, IO_IS_A_PHYSICAL_DISK) == 0) { ! 391: *count = 1; ! 392: parameterArray[0] = _isPhysical ? 1 : 0; ! 393: return IO_R_SUCCESS; ! 394: } ! 395: else { ! 396: return [super getIntValues : parameterArray ! 397: forParameter : parameterName ! 398: count : count]; ! 399: ! 400: } ! 401: } ! 402: ! 403: /* ! 404: * Register a connection with LogicalDisk. If we already have a logicalDisk, ! 405: * this is a nop - subclasses might override this method to perform ! 406: * other operations in that case. ! 407: */ ! 408: - (void) setLogicalDisk : diskId ! 409: { ! 410: xpr_disk("setLogicalDisk: log %s self %s oldLog %s\n", ! 411: (diskId ? [diskId name] : "nil"), ! 412: [self name], ! 413: (_nextLogicalDisk ? [_nextLogicalDisk name] : "nil"), 4,5); ! 414: #ifdef GROK_APPLE //bknight - 12/16/97 - Radar #2004660 ! 415: /* ! 416: * bknight - 12/16/97 - This was changed in order to prevent a ! 417: * space leak caused by IODiskPartition instances for HFS partitions ! 418: * on disks that get ejected. It changes the meaning of this call ! 419: * to be either "set to nil" or "insert at the end of the list beginning ! 420: * at", depending on the value of the argument. With this change, ! 421: * it becomes important that the _nextLogicalDisk field gets set to nil ! 422: * before being used - including being used by this routine, which means ! 423: * that it must be set to nil before setting it to a non-nil value. ! 424: * Otherwise, there would be a use-before-definition bug. Anyhow, it ! 425: * it appears that all the callers do a setLogicalDisk:nil before ! 426: * ever calling it with a non-nil argument, so this is safe. ! 427: * However, if new call sites are added, this needs to be taken into ! 428: * account, or we need to split it into two methods each having the ! 429: * appropriate functionality: either "set the field" or "add to the list". ! 430: */ ! 431: if( ! diskId ) { ! 432: _nextLogicalDisk = diskId; ! 433: } ! 434: else if ( ! _nextLogicalDisk && self != diskId ) { ! 435: _nextLogicalDisk = diskId; ! 436: } ! 437: else if ( _nextLogicalDisk ) { ! 438: [_nextLogicalDisk setLogicalDisk: diskId]; ! 439: } ! 440: #else GROK_APPLE //bknight - 12/16/97 - Radar #2004660 ! 441: if(_nextLogicalDisk == nil) { ! 442: _nextLogicalDisk = diskId; ! 443: } ! 444: #endif GROK_APPLE //bknight - 12/16/97 - Radar #2004660 ! 445: ! 446: } ! 447: ! 448: /* ! 449: * Invoked by instance of subclass upon completion of device initialization. ! 450: * The code here is only executed for physical disks. ! 451: * ! 452: * All device parameters (_diskSize, _blockSize, _formatted, _removable, ! 453: * _lastReadyState) must be valid at this time. ! 454: */ ! 455: #define ALWAYS_VCREGISTER 1 ! 456: ! 457: - registerDevice ! 458: { ! 459: id targ = (id)self; // IODisk doesn't implement updateReadyState ! 460: id ret; ! 461: ! 462: xpr_disk("DiskObject registerDisk\n", 1,2,3,4,5); ! 463: if(!_isPhysical) { ! 464: ret = [super registerDevice]; ! 465: goto out; ! 466: } ! 467: ! 468: /* ! 469: * Do some trivial initialization. ! 470: */ ! 471: ! 472: _nextLogicalDisk = nil; ! 473: _LogicalDiskLock = [NXLock new]; ! 474: ! 475: _readOps = 0; ! 476: _bytesRead = 0; ! 477: _readTotalTime = 0; ! 478: _readLatentTime = 0; ! 479: _readRetries = 0; ! 480: _readErrors = 0; ! 481: _writeOps = 0; ! 482: _bytesWritten = 0; ! 483: _writeTotalTime = 0; ! 484: _writeLatentTime = 0; ! 485: _writeRetries = 0; ! 486: _writeErrors = 0; ! 487: _otherRetries = 0; ! 488: _otherErrors = 0; ! 489: ! 490: /* ! 491: * For physical disks, this will cause probes of IODiskPartition. ! 492: */ ! 493: ret = [super registerDevice]; ! 494: ! 495: /* ! 496: * sign up for disk insertion/ready detect notification. ! 497: */ ! 498: if(ret != nil && ( ! 499: ALWAYS_VCREGISTER || ! 500: _removable || ! 501: ([targ updateReadyState] != IO_Ready))) { ! 502: /* ! 503: * Make sure the disk conforms to the appropriate protocol. ! 504: */ ! 505: if(! [[self class] ! 506: conformsTo:@protocol(IOPhysicalDiskMethods)] ) { ! 507: IOLog("Warning: %s, class %s, does not conform to " ! 508: "IOPhysicalDiskMethods\n", ! 509: [self name], [[self class] name]); ! 510: goto out; ! 511: } ! 512: #ifdef KERNEL ! 513: volCheckRegister(self, ! 514: _devAndIdInfo->blockDev, ! 515: _devAndIdInfo->rawDev); ! 516: #else KERNEL ! 517: volCheckRegister(self, 0, 0); ! 518: #endif KERNEL ! 519: } ! 520: ! 521: out: ! 522: return ret; ! 523: } ! 524: ! 525: /* ! 526: * Lock/Unlock device for LogicalDisk-specific methods. Invoked only by ! 527: * LogicalDisks which are attached to this device. ! 528: */ ! 529: - (void)lockLogicalDisks ! 530: { ! 531: [_LogicalDiskLock lock]; ! 532: } ! 533: ! 534: - (void)unlockLogicalDisks ! 535: { ! 536: [_LogicalDiskLock unlock]; ! 537: } ! 538: ! 539: /* ! 540: * Convert an IOReturn to text. Overrides superclass's method of same name ! 541: * to allow for additional IOReturn's defined in IODisk.h. ! 542: */ ! 543: - (const char *)stringFromReturn : (IOReturn)rtn ! 544: { ! 545: IONamedValue *valArray = diskIoReturnValues; ! 546: ! 547: for( ; valArray->name; valArray++) { ! 548: if(valArray->value == rtn) ! 549: return(valArray->name); ! 550: } ! 551: /* ! 552: * Not found here. Pass up to superclass. ! 553: */ ! 554: return([super stringFromReturn:rtn]); ! 555: } ! 556: ! 557: /* ! 558: * Convert an IOReturn to an errno. ! 559: */ ! 560: - (int)errnoFromReturn : (IOReturn)rtn ! 561: { ! 562: switch(rtn) { ! 563: case IO_R_NO_DISK: ! 564: return(ENXIO); ! 565: case IO_R_NO_LABEL: ! 566: return(ENXIO); // ??? ! 567: case IO_R_UNFORMATTED: ! 568: return(EINVAL); ! 569: default: ! 570: /* ! 571: * Not found here. Pass up to superclass. ! 572: */ ! 573: return([super errnoFromReturn:rtn]); ! 574: ! 575: } ! 576: } ! 577: ! 578: /* ! 579: * volCheck module support. ! 580: */ ! 581: ! 582: static inline int ! 583: diskTypeToPR(IODiskType diskType) ! 584: { ! 585: switch(diskType) { ! 586: case IO_SCSI: ! 587: return PR_DRIVE_SCSI; ! 588: case IO_Floppy: ! 589: return PR_DRIVE_FLOPPY; ! 590: case IO_Other: ! 591: return -1; ! 592: } ! 593: } ! 594: ! 595: /* ! 596: * Request a "please insert disk" panel. ! 597: */ ! 598: - (void)requestInsertionPanelForDiskType : (IODiskType)diskType ! 599: { ! 600: volCheckRequest(self, diskTypeToPR(diskType)); ! 601: } ! 602: ! 603: /* ! 604: * Notify volCheck thread that specified device is in a "disk ejecting" state. ! 605: */ ! 606: - (void)diskIsEjecting : (IODiskType)diskType ! 607: { ! 608: volCheckEjecting(self, diskTypeToPR(diskType)); ! 609: ! 610: } ! 611: ! 612: /* ! 613: * Notify volCheck that disk has gone not ready. Typically called on ! 614: * gross error detection. ! 615: */ ! 616: - (void)diskNotReady ! 617: { ! 618: volCheckNotReady(self); ! 619: } ! 620: ! 621: /* ! 622: * To be optionally overridden by subclass. IODisk version returns NO. ! 623: * If subclass's version returns NO, and the drive is a removable media ! 624: * drive, the drive will not be polled once per second while ready state ! 625: * is IO_NotReady or IO_NoDisk; instead; polling will only occur when ! 626: * an DKIOCCHECKINSERT ioctl is executed on the vol driver. ! 627: */ ! 628: - (BOOL)needsManualPolling ! 629: { ! 630: return NO; ! 631: } ! 632: ! 633: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen ! 634: { ! 635: if( [self isRemovable]) ! 636: strcat( types, " "IOTypeRemovableDisk); ! 637: if( [self isWriteProtected]) ! 638: strcat( types, " "IOTypeWriteProtectedDisk); ! 639: ! 640: return( self); ! 641: } ! 642: ! 643: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen ! 644: { ! 645: strcpy( classes, IOClassBlock); ! 646: if( [self isPhysical]) ! 647: strcat( classes, " "IOClassDisk); ! 648: return( self); ! 649: } ! 650: ! 651: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.