|
|
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: * IOLogicalDisk.m ! 27: * ! 28: * HISTORY ! 29: * 05-Mar-91 Doug Mitchell at NeXT ! 30: * Created. ! 31: */ ! 32: ! 33: #import <driverkit/return.h> ! 34: #import <driverkit/IODisk.h> ! 35: #ifdef KERNEL ! 36: #import <kernserv/prototypes.h> ! 37: #import <mach/mach_interface.h> ! 38: #import <driverkit/kernelDiskMethods.h> ! 39: #else KERNEL ! 40: #import <mach/mach.h> ! 41: #import <bsd/libc.h> ! 42: #endif KERNEL ! 43: #import <driverkit/IOLogicalDisk.h> ! 44: #import <driverkit/Device_ddm.h> ! 45: #import <driverkit/generalFuncs.h> ! 46: #import <driverkit/SCSIDisk.h> ! 47: ! 48: @interface IOLogicalDisk(private) ! 49: - (IOReturn)_diskParamCommon :(u_int)logicalOffset ! 50: length : (u_int)bytesReq ! 51: deviceOffset : (unsigned *)deviceOffset ! 52: bytesToMove : (u_int *)bytesToMove; ! 53: ! 54: - (IOReturn)computePartition :(u_int)logicalOffset ! 55: length : (u_int)bytesReq ! 56: byteOffset : (unsigned long long *)byteOffset ! 57: bytesToMove : (u_int *)bytesToMove; ! 58: ! 59: /* This must be a class method since it's called by ! 60: * a class method in DiskPartition. ! 61: */ ! 62: ! 63: + (IOReturn) reblock : (id)physicalDisk ! 64: : (BOOL)read ! 65: : (unsigned long long)offset /* bytes */ ! 66: : (unsigned)length /* bytes */ ! 67: : (unsigned char *)buffer ! 68: : (vm_task_t)client ! 69: : (void *)pending ! 70: : (unsigned)physsize; /* phys blocksize */ ! 71: @end ! 72: ! 73: @implementation IOLogicalDisk ! 74: ! 75: /* ! 76: * Standard IODiskDeviceReadingAndWriting methods. We translate into raw device ! 77: * parameters and pass along to _physicalDisk. ! 78: */ ! 79: #ifdef KERNEL ! 80: ! 81: - (IOReturn) readAt : (unsigned)offset ! 82: length : (unsigned)length ! 83: buffer : (unsigned char *)buffer ! 84: actualLength : (unsigned *)actualLength ! 85: client : (vm_task_t)client ! 86: { ! 87: IOReturn rtn; ! 88: unsigned bytesToMove; ! 89: unsigned long long byteposition; ! 90: ! 91: rtn = [self computePartition:offset ! 92: length : length ! 93: byteOffset : &byteposition ! 94: bytesToMove:&bytesToMove]; ! 95: ! 96: if (rtn) { ! 97: return(rtn); ! 98: } ! 99: ! 100: /* If the request is aligned with the physical block size, we ! 101: * send it directly to the driver. If not, we have to use the ! 102: * (synchronous) reblocking IO function to handle size and/or ! 103: * alignment mismatches. ! 104: */ ! 105: ! 106: if (byteposition % _physicalBlockSize || length % _physicalBlockSize) { ! 107: ! 108: return([[self class] commonReadWrite ! 109: : _physicalDisk ! 110: : YES /* it's a read */ ! 111: : byteposition /* byte offset */ ! 112: : (unsigned)bytesToMove /* bytes */ ! 113: : (unsigned char *)buffer ! 114: : (vm_task_t)client ! 115: : (void *)NULL ! 116: : (u_int *)actualLength]); ! 117: ! 118: } else { /* neatly aligned */ ! 119: ! 120: return([_physicalDisk readAt:(byteposition / _physicalBlockSize) ! 121: length:bytesToMove ! 122: buffer:buffer ! 123: actualLength:actualLength ! 124: client:client]); ! 125: } ! 126: } ! 127: ! 128: - (IOReturn) readAsyncAt : (unsigned)offset ! 129: length : (unsigned)length ! 130: buffer : (unsigned char *)buffer ! 131: pending : (void *)pending ! 132: client : (vm_task_t)client ! 133: { ! 134: IOReturn rtn; ! 135: unsigned bytesToMove; ! 136: unsigned long long byteposition; ! 137: ! 138: rtn = [self computePartition:offset ! 139: length : length ! 140: byteOffset : &byteposition ! 141: bytesToMove:&bytesToMove]; ! 142: ! 143: if (rtn) { ! 144: return(rtn); ! 145: } ! 146: ! 147: /* If the request is aligned with the physical block size, we ! 148: * send it directly to the driver. If not, we have to use the ! 149: * (synchronous) reblocking IO function to handle size and/or ! 150: * alignment mismatches. ! 151: */ ! 152: ! 153: if (byteposition % _physicalBlockSize || length % _physicalBlockSize) { ! 154: ! 155: return([[self class] commonReadWrite ! 156: : _physicalDisk ! 157: : YES ! 158: : byteposition /* byte offset */ ! 159: : (unsigned)bytesToMove /* bytes */ ! 160: : (unsigned char *)buffer ! 161: : (vm_task_t)client ! 162: : (void *)pending ! 163: : (u_int *)NULL]); ! 164: ! 165: } else { /* neatly aligned */ ! 166: return([_physicalDisk readAsyncAt:(byteposition / _physicalBlockSize) ! 167: length:bytesToMove ! 168: buffer:buffer ! 169: pending:pending ! 170: client:client]); ! 171: } ! 172: } ! 173: ! 174: - (IOReturn) writeAt : (unsigned)offset ! 175: length : (unsigned)length ! 176: buffer : (unsigned char *)buffer ! 177: actualLength : (unsigned *)actualLength ! 178: client : (vm_task_t)client ! 179: { ! 180: unsigned deviceBlock; ! 181: IOReturn rtn; ! 182: unsigned bytesToMove; ! 183: unsigned long long byteposition; ! 184: ! 185: if ([self isWriteProtected]) { ! 186: return IO_R_NOT_WRITABLE; ! 187: } ! 188: ! 189: rtn = [self computePartition:offset ! 190: length : length ! 191: byteOffset : &byteposition ! 192: bytesToMove:&bytesToMove]; ! 193: ! 194: if (rtn) { ! 195: return(rtn); ! 196: } ! 197: ! 198: /* If the request is aligned with the physical block size, we ! 199: * send it directly to the driver. If not, we have to use the ! 200: * (synchronous) reblocking IO function to handle size and/or ! 201: * alignment mismatches. ! 202: */ ! 203: ! 204: if (byteposition % _physicalBlockSize || length % _physicalBlockSize) { ! 205: ! 206: return([[self class] commonReadWrite ! 207: : _physicalDisk ! 208: : NO /* it's a write */ ! 209: : byteposition /* byte offset */ ! 210: : (unsigned)bytesToMove /* bytes */ ! 211: : (unsigned char *)buffer ! 212: : (vm_task_t)client ! 213: : (void *)NULL ! 214: : (u_int *)actualLength]); ! 215: ! 216: } else { /* neatly aligned */ ! 217: ! 218: return([_physicalDisk writeAt:(byteposition / _physicalBlockSize) ! 219: length:bytesToMove ! 220: buffer:buffer ! 221: actualLength:actualLength ! 222: client:client]); ! 223: } ! 224: } ! 225: ! 226: - (IOReturn) writeAsyncAt : (unsigned)offset ! 227: length : (unsigned)length ! 228: buffer : (unsigned char *)buffer ! 229: pending : (void *)pending ! 230: client : (vm_task_t)client ! 231: { ! 232: unsigned deviceBlock; ! 233: IOReturn rtn; ! 234: unsigned bytesToMove; ! 235: unsigned long long byteposition; ! 236: ! 237: if ([self isWriteProtected]) { ! 238: return IO_R_NOT_WRITABLE; ! 239: } ! 240: ! 241: rtn = [self computePartition:offset ! 242: length : length ! 243: byteOffset : &byteposition ! 244: bytesToMove:&bytesToMove]; ! 245: ! 246: if (rtn) { ! 247: return(rtn); ! 248: } ! 249: ! 250: /* If the request is aligned with the physical block size, we ! 251: * send it directly to the driver. If not, we have to use the ! 252: * (synchronous) reblocking IO function to handle size and/or ! 253: * alignment mismatches. ! 254: */ ! 255: ! 256: if (byteposition % _physicalBlockSize || length % _physicalBlockSize) { ! 257: ! 258: return([[self class] commonReadWrite ! 259: : _physicalDisk ! 260: : NO ! 261: : byteposition /* byte offset */ ! 262: : (unsigned)bytesToMove /* bytes */ ! 263: : (unsigned char *)buffer ! 264: : (vm_task_t)client ! 265: : (void *)pending ! 266: : (u_int *)NULL]); ! 267: ! 268: } else { /* neatly aligned */ ! 269: ! 270: return([_physicalDisk writeAsyncAt:(byteposition / _physicalBlockSize) ! 271: length:bytesToMove ! 272: buffer:buffer ! 273: pending:pending ! 274: client:client]); ! 275: } ! 276: } ! 277: ! 278: #else KERNEL ! 279: ! 280: //xxxxx These copies of the routines have not been updated for reblocking. ! 281: // They aren't used. ! 282: ! 283: - (IOReturn) readAt : (unsigned)offset ! 284: length : (unsigned)length ! 285: buffer : (unsigned char *)buffer ! 286: actualLength : (unsigned *)actualLength ! 287: { ! 288: unsigned deviceBlock; ! 289: IOReturn rtn; ! 290: unsigned bytesToMove; ! 291: ! 292: if(rtn = [self _diskParamCommon:offset ! 293: length : length ! 294: deviceOffset : &deviceBlock ! 295: bytesToMove:&bytesToMove]) ! 296: return(rtn); ! 297: return([_physicalDisk readAt:deviceBlock ! 298: length:bytesToMove ! 299: buffer:buffer ! 300: actualLength:actualLength]); ! 301: } ! 302: ! 303: - (IOReturn) readAsyncAt : (unsigned)offset ! 304: length : (unsigned)length ! 305: buffer : (unsigned char *)buffer ! 306: pending : (void *)pending ! 307: { ! 308: unsigned deviceBlock; ! 309: IOReturn rtn; ! 310: unsigned bytesToMove; ! 311: ! 312: if(rtn = [self _diskParamCommon:offset ! 313: length : length ! 314: deviceOffset : &deviceBlock ! 315: bytesToMove:&bytesToMove]) ! 316: return(rtn); ! 317: return([_physicalDisk readAsyncAt:deviceBlock ! 318: length:bytesToMove ! 319: buffer:buffer ! 320: pending:pending]); ! 321: } ! 322: ! 323: - (IOReturn) writeAt : (unsigned)offset ! 324: length : (unsigned)length ! 325: buffer : (unsigned char *)buffer ! 326: actualLength : (unsigned *)actualLength ! 327: { ! 328: unsigned deviceBlock; ! 329: IOReturn rtn; ! 330: unsigned bytesToMove; ! 331: ! 332: if ([self isWriteProtected]) ! 333: return IO_R_NOT_WRITABLE; ! 334: if(rtn = [self _diskParamCommon:offset ! 335: length : length ! 336: deviceOffset : &deviceBlock ! 337: bytesToMove:&bytesToMove]) ! 338: return(rtn); ! 339: return([_physicalDisk writeAt:deviceBlock ! 340: length:bytesToMove ! 341: buffer:buffer ! 342: actualLength:actualLength]); ! 343: } ! 344: ! 345: - (IOReturn) writeAsyncAt : (unsigned)offset ! 346: length : (unsigned)length ! 347: buffer : (unsigned char *)buffer ! 348: pending : (void *)pending ! 349: { ! 350: unsigned deviceBlock; ! 351: IOReturn rtn; ! 352: unsigned bytesToMove; ! 353: ! 354: if ([self isWriteProtected]) ! 355: return IO_R_NOT_WRITABLE; ! 356: if(rtn = [self _diskParamCommon:offset ! 357: length : length ! 358: deviceOffset : &deviceBlock ! 359: bytesToMove:&bytesToMove]) ! 360: return(rtn); ! 361: return([_physicalDisk writeAsyncAt:deviceBlock ! 362: length:bytesToMove ! 363: buffer:buffer ! 364: pending:pending]); ! 365: } ! 366: ! 367: #endif KERNEL ! 368: ! 369: - (IODiskReadyState)updateReadyState ! 370: { ! 371: return [_physicalDisk updateReadyState]; ! 372: } ! 373: ! 374: /* ! 375: * Open a connection to physDevice. FIXME: when do we close?? ! 376: */ ! 377: - (IOReturn)connectToPhysicalDisk : physicalDisk ! 378: { ! 379: IOReturn rtn = IO_R_SUCCESS; ! 380: ! 381: xpr_disk("connectToPhysicalDiskice\n", 1,2,3,4,5); ! 382: _physicalDisk = physicalDisk; ! 383: [self setIsPhysical:0]; ! 384: ! 385: /* ! 386: * Get some instance variables which must be the same as the ! 387: * physDevice's. ! 388: */ ! 389: _physicalBlockSize = [physicalDisk blockSize]; ! 390: [self setRemovable:[physicalDisk isRemovable]]; ! 391: [self setFormattedInternal:[physicalDisk isFormatted]]; ! 392: [self setWriteProtected:[physicalDisk isWriteProtected]]; ! 393: [self setLogicalDisk:nil]; ! 394: #ifdef KERNEL ! 395: [self setDevAndIdInfo:[physicalDisk devAndIdInfo]]; ! 396: #endif KERNEL ! 397: return(rtn); ! 398: } ! 399: ! 400: - (void)setPartitionBase : (unsigned)partBase ! 401: { ! 402: _partitionBase = partBase; ! 403: } ! 404: ! 405: ! 406: /* ! 407: * Determine if this LogicalDisk (or any other LogicalDisks in the ! 408: * logicalDisk list) are currently open. Returns NO if none open, else ! 409: * YES. ! 410: */ ! 411: - (BOOL)isOpen ! 412: { ! 413: if([self isInstanceOpen]) ! 414: return(YES); ! 415: else if([self nextLogicalDisk]) ! 416: return([[self nextLogicalDisk] isOpen]); ! 417: else ! 418: return(NO); ! 419: } ! 420: ! 421: /* ! 422: * Free self and any objects in logicalDisk chain. ! 423: */ ! 424: - free ! 425: { ! 426: id nextLd; ! 427: ! 428: nextLd = [self nextLogicalDisk]; ! 429: if(nextLd) { ! 430: [nextLd free]; ! 431: } ! 432: return([super free]); ! 433: } ! 434: ! 435: - physicalDisk ! 436: { ! 437: return(_physicalDisk); ! 438: } ! 439: ! 440: - (unsigned)physicalBlockSize ! 441: { ! 442: return(_physicalBlockSize); ! 443: } ! 444: ! 445: - (void)setPhysicalBlockSize : (unsigned)size ! 446: { ! 447: _physicalBlockSize = size; ! 448: } ! 449: ! 450: /* ! 451: * Pass this on to _physicalDisk. ! 452: */ ! 453: - (IOReturn)isDiskReady : (BOOL)prompt ! 454: { ! 455: return [_physicalDisk isDiskReady:prompt]; ! 456: } ! 457: ! 458: /* ! 459: * Determine if any logical disks in the _logicalDisk chain except ! 460: * for self are open. ! 461: */ ! 462: - (BOOL)isAnyOtherOpen ! 463: { ! 464: id logDisk = [_physicalDisk nextLogicalDisk]; ! 465: while(logDisk) { ! 466: if((logDisk != self) && [logDisk isInstanceOpen]) { ! 467: return YES; ! 468: } ! 469: logDisk = [logDisk nextLogicalDisk]; ! 470: } ! 471: return NO; ! 472: } ! 473: ! 474: - (BOOL)isInstanceOpen ! 475: { ! 476: return _instanceOpen; ! 477: } ! 478: ! 479: - (void)setInstanceOpen : (BOOL)isOpen ! 480: { ! 481: _instanceOpen = (isOpen ? YES : NO); ! 482: } ! 483: ! 484: /*-----------------------------------------*/ ! 485: ! 486: /* Common read/write function; handles reblocking of misaligned requests. */ ! 487: ! 488: + (IOReturn) commonReadWrite : (id)physicalDisk ! 489: : (BOOL)read ! 490: : (unsigned long long)byteposition ! 491: : (unsigned)length /* bytes */ ! 492: : (unsigned char *)buffer ! 493: : (vm_task_t)client ! 494: : (void *)pending ! 495: : (u_int *)actualLength ! 496: { ! 497: IOReturn rtn = IO_R_SUCCESS; ! 498: unsigned long aligncount; /* bytes */ ! 499: unsigned long integralblocks; ! 500: unsigned long integralbytes; ! 501: unsigned long transfer; ! 502: unsigned long originallength; ! 503: unsigned long physsize; /* physical blocksize */ ! 504: // unsigned char *origbuf; ! 505: u_int tempactual; ! 506: ! 507: //origbuf = buffer; ! 508: originallength = length; ! 509: tempactual = 0; ! 510: physsize = [physicalDisk blockSize]; ! 511: ! 512: /* If the beginning of the request is not properly aligned ! 513: * with the device block size, or it's less than a block, ! 514: * we have to reblock it here to get ourselves aligned. ! 515: */ ! 516: ! 517: if ((byteposition % physsize) || (length < physsize)) { ! 518: ! 519: /* Compute the number of bytes needed ! 520: * to bring us into sync with the real size. ! 521: */ ! 522: aligncount = physsize - (byteposition % physsize); ! 523: if (aligncount > length) { /* a short read of less than a real block */ ! 524: aligncount = length; ! 525: } ! 526: ! 527: rtn = [[IOLogicalDisk class] reblock ! 528: : physicalDisk ! 529: : read /* read or write */ ! 530: : byteposition /* start byte position */ ! 531: : aligncount /* byte count */ ! 532: : buffer ! 533: : client ! 534: : pending ! 535: : physsize]; ! 536: length -= aligncount; /* update length (bytes) */ ! 537: byteposition += aligncount; /* update start byte position */ ! 538: buffer += aligncount; /* update buffer */ ! 539: } ! 540: ! 541: /* Now we're aligned. Transfer any integral-block "middle" part ! 542: * of the request. The integer divide below excludes any "odd" bytes ! 543: * at the end of the request which aren't part of an integral number ! 544: * of device blocks. ! 545: */ ! 546: ! 547: if (length > 0 && (rtn == IO_R_SUCCESS)) { /* there's more left to do */ ! 548: ! 549: integralblocks = length / physsize; /* zero if no full blocks */ ! 550: ! 551: if (integralblocks) { /* transfer this many aligned blocks */ ! 552: integralbytes = integralblocks * physsize; ! 553: ! 554: if (read) { ! 555: rtn = [physicalDisk readAt:(byteposition / physsize) ! 556: length:integralbytes ! 557: buffer:buffer ! 558: actualLength:&tempactual ! 559: client:client]; ! 560: } else { ! 561: rtn = [physicalDisk writeAt:(byteposition / physsize) ! 562: length:integralbytes ! 563: buffer:buffer ! 564: actualLength:&tempactual ! 565: client:client]; ! 566: } ! 567: ! 568: length -= integralbytes; /* update length (bytes) */ ! 569: byteposition += integralbytes; /* update start block */ ! 570: buffer += integralbytes; /* update buffer */ ! 571: } ! 572: } ! 573: ! 574: /* If there are any "odd" bytes at the end of the request, ! 575: * transfer these now via reblocking. ! 576: */ ! 577: ! 578: if (length > 0 && (rtn == IO_R_SUCCESS)) { /* there's more to do */ ! 579: ! 580: rtn = [[IOLogicalDisk class] reblock ! 581: : physicalDisk ! 582: : read ! 583: : byteposition ! 584: : length ! 585: : buffer ! 586: : client ! 587: : pending ! 588: : physsize]; ! 589: } ! 590: ! 591: /* We only remember the actual length if the transfer succeeds. */ ! 592: ! 593: if (rtn == IO_R_SUCCESS) { ! 594: tempactual = originallength; ! 595: } ! 596: ! 597: /* Since we've been doing sync IOs here, we have to force a ! 598: * completion if the caller's request was async. Done here, ! 599: * this is ugly, but we have little choice with the current design. ! 600: */ ! 601: ! 602: if (pending) { /* async: force an I/O completion (ugly) */ ! 603: [physicalDisk completeTransfer ! 604: : pending ! 605: withStatus : rtn ! 606: actualLength : tempactual]; ! 607: } else { /* sync */ ! 608: *actualLength = tempactual; ! 609: } ! 610: ! 611: return(rtn); ! 612: } ! 613: @end ! 614: ! 615: /* ! 616: * Generate device-specific parameters from logical parameters. ! 617: */ ! 618: @implementation IOLogicalDisk(private) ! 619: ! 620: - (IOReturn)_diskParamCommon :(unsigned)logicalOffset ! 621: length : (unsigned)length ! 622: deviceOffset : (unsigned*)deviceOffset ! 623: bytesToMove : (unsigned *)bytesToMove ! 624: { ! 625: unsigned ratio = 0; // bogus compiler warning ! 626: int deviceBlocks; ! 627: int logicalBlocks; ! 628: unsigned block_size; ! 629: unsigned dev_size; ! 630: IOReturn rtn; ! 631: const char *name = [self name]; ! 632: ! 633: /* ! 634: * Note we have to 'fault in' a possible non-present physical disk in ! 635: * order to get its physical parameters... ! 636: */ ! 637: rtn = [_physicalDisk isDiskReady:YES]; ! 638: switch(rtn) { ! 639: case IO_R_SUCCESS: ! 640: break; ! 641: case IO_R_NO_DISK: ! 642: xpr_err("%s diskParamCommon: disk not present\n", ! 643: name, 2,3,4,5); ! 644: return(rtn); ! 645: default: ! 646: IOLog("%s deviceRwCommon: bogus return from isDiskReady " ! 647: "(%s)\n", ! 648: name, [self stringFromReturn:rtn]); ! 649: return(rtn); ! 650: } ! 651: ! 652: block_size = [self blockSize]; ! 653: dev_size = [self diskSize]; ! 654: ! 655: if(length % block_size) { ! 656: IOLog("%s: Bytes requested not multiple of block size\n", ! 657: name); ! 658: return(IO_R_INVALID_ARG); ! 659: } ! 660: logicalBlocks = length / block_size; ! 661: if((logicalOffset + logicalBlocks) > dev_size) { ! 662: if(logicalOffset >= dev_size) ! 663: return(IO_R_INVALID_ARG); ! 664: ! 665: /* ! 666: * Truncate. ! 667: */ ! 668: logicalBlocks = dev_size - logicalOffset; ! 669: } ! 670: ratio = block_size / _physicalBlockSize; ! 671: deviceBlocks = logicalBlocks * ratio; ! 672: *deviceOffset = (logicalOffset * ratio) + _partitionBase; ! 673: *bytesToMove = deviceBlocks * _physicalBlockSize; ! 674: return(IO_R_SUCCESS); ! 675: } ! 676: ! 677: - (IOReturn)computePartition :(unsigned)logicalOffset ! 678: length : (unsigned)length ! 679: byteOffset : (unsigned long long *)byteOffset ! 680: bytesToMove : (unsigned *)bytesToMove ! 681: { ! 682: unsigned physicalBlocksize; ! 683: unsigned logicalBlocksize; ! 684: IOReturn rtn; ! 685: const char *name = [self name]; ! 686: ! 687: unsigned long long partbase; ! 688: unsigned long long partsize; ! 689: unsigned long long partend; ! 690: unsigned long long reqbase; ! 691: ! 692: /* ! 693: * Note we have to 'fault in' a possible non-present physical disk in ! 694: * order to get its physical parameters... ! 695: */ ! 696: rtn = [_physicalDisk isDiskReady:YES]; ! 697: switch(rtn) { ! 698: case IO_R_SUCCESS: ! 699: break; ! 700: case IO_R_NO_DISK: ! 701: xpr_err("%s diskParamCommon: disk not present\n", ! 702: name, 2,3,4,5); ! 703: return(rtn); ! 704: default: ! 705: IOLog("%s deviceRwCommon: bogus return from isDiskReady " ! 706: "(%s)\n", ! 707: name, [self stringFromReturn:rtn]); ! 708: return(rtn); ! 709: } ! 710: ! 711: /* We compute partition information here based on the notion of ! 712: * block size, but for better results these boundaries should ! 713: * have been set up in bytes from the start. ! 714: */ ! 715: physicalBlocksize = [_physicalDisk blockSize]; ! 716: logicalBlocksize = [self blockSize]; ! 717: ! 718: /* If we don't (yet) know our logical block size, we have to ! 719: * default to the physical block size. ! 720: */ ! 721: if (logicalBlocksize == 0) { /* we don't know (yet)*/ ! 722: logicalBlocksize = physicalBlocksize; ! 723: } ! 724: ! 725: /* The partition base is usually in physical blocks, except when ! 726: * we are reblocking HFS on CD-ROM. In that case, all computations ! 727: * are done in 512-byte logical blocks. ! 728: * ! 729: * Is there a better way to detect that we're an HFS partition? ! 730: */ ! 731: if (logicalBlocksize != physicalBlocksize && ! 732: logicalBlocksize == 512) { /* must be HFS */ ! 733: partbase = (unsigned long long)_partitionBase * ! 734: (unsigned long long)logicalBlocksize; ! 735: } else { ! 736: partbase = (unsigned long long)_partitionBase * ! 737: (unsigned long long)physicalBlocksize; ! 738: } ! 739: partsize = (unsigned long long)[self diskSize] * ! 740: (unsigned long long)logicalBlocksize; ! 741: partend = partbase + partsize; ! 742: ! 743: /* The caller's block offset is in units expressed by the ! 744: * partitioning scheme. NeXT labeled disks are usually 1024 bytes, ! 745: * HFS is always 512.) ! 746: */ ! 747: reqbase = ((unsigned long long)logicalOffset * ! 748: (unsigned long long)logicalBlocksize) + partbase; ! 749: ! 750: if (reqbase < partbase || reqbase > partend) { ! 751: return(IO_R_INVALID_ARG); ! 752: } ! 753: ! 754: if ((reqbase + length) > partend) { ! 755: length = partend - reqbase; /* truncate the request */ ! 756: } ! 757: ! 758: *byteOffset = reqbase; ! 759: *bytesToMove = length; ! 760: return(IO_R_SUCCESS); ! 761: } ! 762: ! 763: /* Copy data to (write) or from (read) a misaligned part of a physical block: */ ! 764: ! 765: #define MAX_REBLOCK_SIZE 2048 ! 766: ! 767: + (IOReturn) reblock : (id)physicalDisk ! 768: : (BOOL)read ! 769: : (unsigned long long)offset /* bytes */ ! 770: : (unsigned)length /* bytes */ ! 771: : (unsigned char *)buffer ! 772: : (vm_task_t)client ! 773: : (void *)pending ! 774: : (unsigned)physsize /* phys blocksize */ ! 775: { ! 776: IOReturn rtn; ! 777: unsigned long physblock; ! 778: int bufoffset; ! 779: u_int tempactual; ! 780: id controller; ! 781: char *reblockbuf; ! 782: void *freePtr; ! 783: unsigned freeCnt; ! 784: ! 785: /* Allocate a buffer to hold the (larger) device block. This isn't ! 786: * efficient since we allocate and free the buffer each time through, ! 787: * but we're just trying to make the thing work for now. ! 788: */ ! 789: ! 790: controller = [physicalDisk controller]; ! 791: reblockbuf = (char *)[controller allocateBufferOfLength:MAX_REBLOCK_SIZE ! 792: actualStart:&freePtr ! 793: actualLength:&freeCnt]; ! 794: ! 795: bzero(reblockbuf,MAX_REBLOCK_SIZE); ! 796: ! 797: /* Figure out which physical block we need, and load it: */ ! 798: ! 799: physblock = offset / physsize; ! 800: ! 801: rtn = [physicalDisk readAt ! 802: :physblock ! 803: length:physsize ! 804: buffer:reblockbuf ! 805: actualLength:&tempactual ! 806: client:client]; ! 807: ! 808: if (rtn != IO_R_SUCCESS) { ! 809: return(rtn); ! 810: } ! 811: ! 812: /* Now copy what the client wants, in the direction specified: */ ! 813: ! 814: bufoffset = offset % physsize; ! 815: ! 816: if (read) { ! 817: bcopy(&reblockbuf[bufoffset],buffer,length); /* read : buf to client */ ! 818: } else { ! 819: bcopy(buffer,&reblockbuf[bufoffset],length); /* write: client to buf */ ! 820: ! 821: /* If writing, flush the buffer to the device: */ ! 822: rtn = [physicalDisk writeAt:physblock ! 823: length:physsize ! 824: buffer:reblockbuf ! 825: actualLength:&tempactual ! 826: client:client]; ! 827: } ! 828: ! 829: IOFree(freePtr,freeCnt); ! 830: return(IO_R_SUCCESS); ! 831: } ! 832: ! 833: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.