1/* 2 * Copyright (c) 1998-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <sys/types.h> // (miscfs/devfs/devfs.h, ...) 25 26#include <miscfs/devfs/devfs.h> // (devfs_make_node, ...) 27#include <sys/buf.h> // (buf_t, ...) 28#include <sys/fcntl.h> // (FWRITE, ...) 29#include <sys/ioccom.h> // (IOCGROUP, ...) 30#include <sys/proc.h> // (proc_is64bit, ...) 31#include <sys/stat.h> // (S_ISBLK, ...) 32#include <sys/systm.h> // (DEV_BSIZE, ...) 33#include <IOKit/assert.h> 34#include <IOKit/IOBSD.h> 35#include <IOKit/IODeviceTreeSupport.h> 36#include <IOKit/IOLib.h> 37#include <IOKit/IOKitKeys.h> 38#include <IOKit/IOMemoryDescriptor.h> 39#include <IOKit/IOMessage.h> 40#include <IOKit/IOSubMemoryDescriptor.h> 41#include <IOKit/storage/IOBlockStorageDevice.h> 42#include <IOKit/storage/IOBlockStorageDriver.h> 43#include <IOKit/storage/IOMedia.h> 44#include <IOKit/storage/IOMediaBSDClient.h> 45///w:start 46#if !TARGET_OS_EMBEDDED 47#include <IOKit/pwr_mgt/RootDomain.h> 48#endif /* !TARGET_OS_EMBEDDED */ 49///w:stop 50 51#define super IOService 52OSDefineMetaClassAndStructors(IOMediaBSDClient, IOService) 53 54const UInt32 kMinorsAddCountBits = 6; 55const UInt32 kMinorsAddCountMask = (1 << kMinorsAddCountBits) - 1; 56const UInt32 kMinorsAddCount = (1 << kMinorsAddCountBits); 57const UInt32 kMinorsMaxCountBits = 16; 58const UInt32 kMinorsMaxCountMask = (1 << kMinorsMaxCountBits) - 1; 59const UInt32 kMinorsMaxCount = (1 << kMinorsMaxCountBits); 60const UInt32 kMinorsBucketCount = kMinorsMaxCount / kMinorsAddCount; 61const UInt32 kAnchorsAddCount = 2; 62const UInt32 kAnchorsMaxCount = kMinorsMaxCount; 63 64#define kMsgNoWhole "%s: No whole media found for media \"%s\".\n", getName() 65#define kMsgNoLocation "%s: No location is found for media \"%s\".\n", getName() 66 67extern "C" 68{ 69 int dkclose(dev_t dev, int flags, int devtype, proc_t proc); 70 int dkioctl(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc); 71 int dkioctl_bdev(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc); 72 int dkioctl_cdev(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc); 73 int dkopen(dev_t dev, int flags, int devtype, proc_t proc); 74 int dkread(dev_t dev, uio_t uio, int flags); 75 int dksize(dev_t dev); 76 void dkstrategy(buf_t bp); 77 int dkwrite(dev_t dev, uio_t uio, int flags); 78} // extern "C" 79 80static struct bdevsw bdevswFunctions = 81{ 82 /* d_open */ dkopen, 83 /* d_close */ dkclose, 84 /* d_strategy */ dkstrategy, 85 /* d_ioctl */ dkioctl_bdev, 86 /* d_dump */ eno_dump, 87 /* d_psize */ dksize, 88 /* d_type */ D_DISK 89}; 90 91struct cdevsw cdevswFunctions = 92{ 93 /* d_open */ dkopen, 94 /* d_close */ dkclose, 95 /* d_read */ dkread, 96 /* d_write */ dkwrite, 97 /* d_ioctl */ dkioctl_cdev, 98 /* d_stop */ eno_stop, 99 /* d_reset */ eno_reset, 100 /* d_ttys */ 0, 101 /* d_select */ eno_select, 102 /* d_mmap */ eno_mmap, 103 /* d_strategy */ eno_strat, 104 /* d_getc */ eno_getc, 105 /* d_putc */ eno_putc, 106 /* d_type */ D_DISK 107}; 108 109struct dio { dev_t dev; uio_t uio; void * drvdata; }; 110 111typedef struct dio * dio_t; 112typedef void * dkr_t; /* dkreadwrite request */ 113typedef enum { DKRTYPE_BUF, DKRTYPE_DIO } dkrtype_t; 114 115static int dkreadwrite(dkr_t dkr, dkrtype_t dkrtype); 116static void dkreadwritecompletion(void *, void *, IOReturn, UInt64); 117 118inline int32_t getminor(dev_t dev) 119{ 120 return minor(dev); 121} 122 123const UInt32 kInvalidAnchorID = (UInt32) (-1); 124 125struct AnchorSlot 126{ 127 UInt32 isAssigned:1; // (slot is occupied) 128 UInt32 isObsolete:1; // (slot is to be removed once references gone) 129 130 IOService * anchor; // (anchor object) 131 void * key; // (anchor key) 132 IONotifier * notifier; // (anchor termination notification, post-stop) 133}; 134 135class AnchorTable 136{ 137protected: 138 AnchorSlot * _table; 139 UInt32 _tableCount; 140 141 static IOReturn anchorWasNotified( void * target, 142 void * parameter, 143 UInt32 messageType, 144 IOService * provider, 145 void * messageArgument, 146 vm_size_t messageArgumentSize ); 147 148public: 149 AnchorTable(); 150 ~AnchorTable(); 151 152 UInt32 insert(IOService * anchor, void * key); 153 UInt32 locate(IOService * anchor); 154 UInt32 locate(IOService * anchor, void * key); 155 void obsolete(UInt32 anchorID); 156 void remove(UInt32 anchorID); 157 UInt32 update(IOService * anchor, void * key); 158 159 bool isObsolete(UInt32 anchorID); 160}; 161 162const UInt32 kInvalidMinorID = (UInt32) (-1); 163 164struct MinorSlot 165{ 166 UInt32 isAssigned:1; // (slot is occupied) 167 UInt32 isObsolete:1; // (slot is to be removed, close pending) 168 UInt32 isOrphaned:1; // (slot is in open flux, close pending) 169 170 UInt32 anchorID; // (minor's associated anchor ID) 171 IOMediaBSDClient * client; // (minor's media bsd client object) 172 IOMedia * media; // (minor's media object) 173 char * name; // (minor's name, private allocation) 174 175 UInt64 bdevBlockSize; // (block device's preferred block size) 176 void * bdevNode; // (block device's devfs node) 177 UInt32 bdevOpen; // (block device's open count) 178 IOStorageAccess bdevOpenLevel; // (block device's open level) 179 180 void * cdevNode; // (character device's devfs node) 181 UInt32 cdevOpen; // (character device's open count) 182 IOStorageAccess cdevOpenLevel; // (character device's open level) 183#if TARGET_OS_EMBEDDED 184 IOStorageOptions cdevOptions; 185#endif /* TARGET_OS_EMBEDDED */ 186}; 187 188class MinorTable 189{ 190protected: 191 class 192 { 193 public: 194 MinorSlot ** buckets; 195 196 inline MinorSlot & operator[](const int i) 197 { 198 return (buckets[i >> kMinorsAddCountBits])[i & kMinorsAddCountMask]; 199 } 200 } _table; 201 202 UInt32 _tableCount; 203 204public: 205 MinorTable(); 206 ~MinorTable(); 207 208 UInt32 insert( IOMedia * media, 209 UInt32 anchorID, 210 IOMediaBSDClient * client, 211 char * slicePath ); 212 213 UInt32 update( IOMedia * media, 214 UInt32 anchorID, 215 IOMediaBSDClient * client, 216 char * slicePath ); 217 218 UInt32 locate(IOMedia * media); 219 void obsolete(UInt32 minorID); 220 void remove(UInt32 minorID); 221 222 bool isObsolete(UInt32 minorID); 223 224 MinorSlot * getMinor(UInt32 minorID); 225 226 UInt32 getOpenCountForAnchorID(UInt32 anchorID); 227 bool hasReferencesToAnchorID(UInt32 anchorID, bool excludeOrphans); 228}; 229 230const UInt32 kInvalidMajorID = (UInt32) (-1); 231 232class IOMediaBSDClientGlobals 233{ 234protected: 235 AnchorTable * _anchors; // (table of anchors) 236 MinorTable * _minors; // (table of minors) 237 238 UInt32 _majorID; // (major ID) 239 240 IOLock * _openLock; // (lock for opens, closes) 241 IOLock * _stateLock; // (lock for state, tables) 242///w:start 243#if !TARGET_OS_EMBEDDED 244 thread_call_t _assertionCall; 245 IOPMDriverAssertionID _assertionID; 246 IOLock * _assertionLock; 247 AbsoluteTime _assertionTime; 248#endif /* !TARGET_OS_EMBEDDED */ 249///w:stop 250 251public: 252 IOMediaBSDClientGlobals(); 253 ~IOMediaBSDClientGlobals(); 254 255 AnchorTable * getAnchors(); 256 MinorTable * getMinors(); 257 MinorSlot * getMinor(UInt32 minorID); 258 259 UInt32 getMajorID(); 260 261 bool isValid(); 262 263 void lockOpen(); 264 void unlockOpen(); 265 266 void lockState(); 267 void unlockState(); 268///w:start 269#if !TARGET_OS_EMBEDDED 270 thread_call_t getAssertionCall(); 271 272 IOPMDriverAssertionID getAssertionID(); 273 void setAssertionID(IOPMDriverAssertionID assertionID); 274 275 AbsoluteTime getAssertionTime(); 276 void setAssertionTime(AbsoluteTime assertionTime); 277 278 void lockAssertion(); 279 void unlockAssertion(); 280#endif /* !TARGET_OS_EMBEDDED */ 281///w:stop 282}; 283 284static IOMediaBSDClientGlobals gIOMediaBSDClientGlobals; 285 286bool IOMediaBSDClient::init(OSDictionary * properties) 287{ 288 // 289 // Initialize this object's minimal state. 290 // 291 292 // Ask our superclass' opinion. 293 294 if ( super::init(properties) == false ) return false; 295 296 // Determine whether our minimal global state has been initialized. 297 298 if ( gIOMediaBSDClientGlobals.isValid() == false ) return false; 299 300 // Initialize this object's minimal state. 301 302 _anchors = gIOMediaBSDClientGlobals.getAnchors(); 303 _minors = gIOMediaBSDClientGlobals.getMinors(); 304 305 return true; 306} 307 308void IOMediaBSDClient::free() 309{ 310 // 311 // Free all of this object's outstanding resources. 312 // 313 314 super::free(); 315} 316 317bool IOMediaBSDClient::start(IOService * provider) 318{ 319 // 320 // This method is called once we have been attached to the provider object. 321 // 322 323 IOMedia * media = (IOMedia *) provider; 324 325 // Ask our superclass' opinion. 326 327 if ( super::start(provider) == false ) return false; 328 329 // Disable access to tables. 330 331 gIOMediaBSDClientGlobals.lockState(); 332 333 // Create bdevsw and cdevsw nodes for the new media object. 334 335 createNodes(media); 336 337 // Enable access to tables. 338 339 gIOMediaBSDClientGlobals.unlockState(); 340 341 // Register this object so it can be found via notification requests. It is 342 // not being registered to have I/O Kit attempt to have drivers match on it, 343 // which is the reason most other services are registered -- that's not the 344 // intention of this registerService call. 345 346 registerService(); 347 348 return true; 349} 350 351bool IOMediaBSDClient::terminate(IOOptionBits options) 352{ 353 // 354 // This method is called when we are to terminate from the provider object. 355 // 356 357 UInt32 minorID; 358 359 // Ask our superclass' opinion. 360 361 if ( super::terminate(options) == false ) return false; 362 363 // Disable access to tables. 364 365 gIOMediaBSDClientGlobals.lockState(); 366 367 // Find the minor assigned to this media. 368 369 minorID = gIOMediaBSDClientGlobals.getMinors()->locate(getProvider()); 370 371 if ( minorID != kInvalidMinorID ) 372 { 373 MinorSlot * minor; 374 375 minor = gIOMediaBSDClientGlobals.getMinors()->getMinor(minorID); 376 377 // Remove the minor from the minor table. If an open is still 378 // outstanding, we mark the minor as obsolete for removal when 379 // the close comes in later. 380 381 if ( minor->bdevOpen || minor->cdevOpen ) 382 { 383 gIOMediaBSDClientGlobals.getMinors()->obsolete(minorID); 384 } 385 else 386 { 387 gIOMediaBSDClientGlobals.getMinors()->remove(minorID); 388 } 389 } 390 391 // Enable access to tables. 392 393 gIOMediaBSDClientGlobals.unlockState(); 394 395 return true; 396} 397 398IOMedia * IOMediaBSDClient::getWholeMedia( IOMedia * media, 399 UInt32 * slicePathSize, 400 char * slicePath ) 401{ 402 // 403 // Find the whole media that roots this media tree. A null return value 404 // indicates no whole media was found or a malformed tree was detected. 405 // 406 // If slicePathSize is non-zero, the size required to fit the slice path 407 // (including the zero terminator) is passed back as a result. 408 // 409 // If slicePathSize and slicePath are both non-zero, the slice path will 410 // be written into the slicePath buffer. The value slicePathSize points 411 // to must be the size of the slicePath buffer, which is used for sanity 412 // checking in this method. 413 // 414 // This method assumes that the table (and termination) lock is held. 415 // 416 417 UInt32 depth = 1; 418 UInt32 position = sizeof('\0'); 419 IOService * service = 0; 420 421 assert(slicePath == 0 || slicePathSize != 0); 422 423 // Search the registry for the parent whole media for this media. 424 425 for ( service = media; service; service = service->getProvider() ) 426 { 427 if ( OSDynamicCast(IOMedia, service) ) // (is it a media?) 428 { 429 if ( ((IOMedia *)service)->isWhole() ) // (is it a whole media?) 430 { 431 if ( slicePath ) // (are we building the slice path?) 432 { 433 slicePath[*slicePathSize - 1] = 0; // (zero terminate path) 434 435 if ( position < *slicePathSize ) // (need to move path?) 436 { 437 memmove( slicePath, // (move path to start of buffer) 438 slicePath + (*slicePathSize - position), 439 position ); 440 } 441 } 442 else if ( slicePathSize ) // (report size req'd for slice path?) 443 { 444 *slicePathSize = position; 445 } 446 447 return (IOMedia *)service; // (return the whole media) 448 } 449 450 // Determine whether this non-whole media has a location value. It 451 // must, by definition of a non-whole media, but if it does not, we 452 // should return an error condition. 453 454 const char * location = service->getLocation(); 455 456 if ( location == 0 ) // (no location on non-whole media?) 457 { 458 if ( service == media ) IOLog(kMsgNoLocation, media->getName()); 459 return 0; 460 } 461 462 // Otherwise, it's a valid non-whole media: we compute the required 463 // size for the slice path or build the slice path, if so requested. 464 // Note that the slice path is built backwards from the ends of the 465 // supplied buffer to the beginning of the buffer. 466 467 position += sizeof('s') + strlen(location); 468 469 if ( slicePath ) // (build the slice path?) 470 { 471 char * path = slicePath + *slicePathSize - position; 472 473 if ( position > *slicePathSize ) { assert(0); return 0; } 474 475 *path = 's'; 476 strncpy(path + sizeof('s'), location, strlen(location)); 477 } 478 479 depth += 1; 480 } 481 } 482 483 // If we've fallen through, then the whole media was never found. 484 485 if ( depth == 1 ) IOLog(kMsgNoWhole, media->getName()); 486 487 return 0; 488} 489 490bool IOMediaBSDClient::createNodes(IOMedia * media) 491{ 492 // 493 // Create bdevsw and cdevsw nodes for the given media object. 494 // 495 // This method assumes that the table (and termination) lock is held. 496 // 497 498 IOService * anchor; 499 AnchorTable * anchors = gIOMediaBSDClientGlobals.getAnchors(); 500 UInt32 anchorID; 501 bool anchorNew = false; 502 UInt32 majorID = gIOMediaBSDClientGlobals.getMajorID(); 503 MinorTable * minors = gIOMediaBSDClientGlobals.getMinors(); 504 UInt32 minorID; 505 char * slicePath = 0; 506 UInt32 slicePathSize; 507 IOMedia * whole; 508 509 // 510 // Find the anchor that roots this media tree. The anchor is defined as the 511 // parent of the whole media that roots this media tree. It is an important 512 // object to us because this object stays in place when media is ejected, so 513 // we can continue to maintain the "unit number" of the "drive" such that if 514 // media is re-inserted, it will show up under the same "unit number". You 515 // can think of the typical anchor as being the drive, if it helps, although 516 // it could be one of many other kinds of drivers (eg. a RAID scheme). 517 // 518 519 whole = getWholeMedia(media, &slicePathSize); 520 if ( whole == 0 ) return false; 521 522 anchor = whole->getProvider(); 523 if ( anchor == 0 ) return false; 524 525 // 526 // Determine whether the anchor already exists in the anchor table (obsolete 527 // occurences are skipped in the search, as appropriate, since those anchor 528 // IDs are to be removed soon). If the anchor does not exist, insert it into 529 // anchor table. 530 // 531 532 anchorID = anchors->locate(anchor, whole); 533 534 if ( anchorID == kInvalidAnchorID ) 535 { 536 // 537 // The anchor and key pair does not exist in the table, however we still 538 // have more to check. The anchor might in fact exist in the table, but 539 // have a different key. If such a slot exists, and it isn't referenced 540 // in the minor table, we reuse the slot. 541 // 542 543 anchorID = anchors->update(anchor, whole); 544 } 545 546 if ( anchorID == kInvalidAnchorID ) 547 { 548 anchorID = anchors->insert(anchor, whole); // (get new anchor ID) 549 if ( anchorID == kInvalidAnchorID ) return false; 550 anchorNew = true; 551 } 552 553 // 554 // Allocate space for and build the slice path for the device node names. 555 // 556 557 slicePath = (char *) IOMalloc(slicePathSize); 558 if ( slicePath == 0 ) goto createNodesErr; 559 560 whole = getWholeMedia(media, &slicePathSize, slicePath); 561 assert(whole); 562 563 // 564 // Insert the new media into our minor table (we're almost done :-). 565 // 566 567 minorID = minors->update(media, anchorID, this, slicePath); 568 569 if ( minorID == kInvalidMinorID ) 570 { 571 minorID = minors->insert(media, anchorID, this, slicePath); 572 if ( minorID == kInvalidMinorID ) goto createNodesErr; 573 } 574 575 // 576 // Create the required properties on the media. 577 // 578 579 media->setProperty(kIOBSDNameKey, minors->getMinor(minorID)->name); 580 media->setProperty(kIOBSDUnitKey, anchorID, 32); // ("BSD Unit" ) 581 media->setProperty(kIOBSDMajorKey, majorID, 32); // ("BSD Major") 582 media->setProperty(kIOBSDMinorKey, minorID, 32); // ("BSD Minor") 583 584 // 585 // Clean up outstanding resources. 586 // 587 588 IOFree(slicePath, slicePathSize); 589 590 return true; // (success) 591 592createNodesErr: 593 594 if (anchorNew) anchors->remove(anchorID); 595 if (slicePath) IOFree(slicePath, slicePathSize); 596 597 return false; // (failure) 598} 599 600#ifndef __LP64__ 601AnchorTable * IOMediaBSDClient::getAnchors() 602{ 603 // 604 // Obtain the table of anchors. 605 // 606 607 return _anchors; 608} 609 610MinorTable * IOMediaBSDClient::getMinors() 611{ 612 // 613 // Obtain the table of anchors. 614 // 615 616 return _minors; 617} 618 619MinorSlot * IOMediaBSDClient::getMinor(UInt32 minorID) 620{ 621 // 622 // Obtain information for the specified minor ID. 623 // 624 625 return _minors->getMinor(minorID); 626} 627#endif /* !__LP64__ */ 628 629IOMedia * IOMediaBSDClient::getProvider() const 630{ 631 // 632 // Obtain this object's provider. We override the superclass's method to 633 // return a more specific subclass of IOService -- IOMedia. This method 634 // serves simply as a convenience to subclass developers. 635 // 636 637 return (IOMedia *) IOService::getProvider(); 638} 639 640int IOMediaBSDClient::ioctl( dev_t dev, 641 u_long cmd, 642 caddr_t data, 643 int flags, 644 proc_t proc ) 645{ 646 // 647 // Process a foreign ioctl. 648 // 649 650 return ENOTTY; 651} 652 653#ifdef __LP64__ 654OSMetaClassDefineReservedUnused(IOMediaBSDClient, 0); 655#else /* !__LP64__ */ 656OSMetaClassDefineReservedUsed(IOMediaBSDClient, 0); 657#endif /* !__LP64__ */ 658OSMetaClassDefineReservedUnused(IOMediaBSDClient, 1); 659OSMetaClassDefineReservedUnused(IOMediaBSDClient, 2); 660OSMetaClassDefineReservedUnused(IOMediaBSDClient, 3); 661OSMetaClassDefineReservedUnused(IOMediaBSDClient, 4); 662OSMetaClassDefineReservedUnused(IOMediaBSDClient, 5); 663OSMetaClassDefineReservedUnused(IOMediaBSDClient, 6); 664OSMetaClassDefineReservedUnused(IOMediaBSDClient, 7); 665OSMetaClassDefineReservedUnused(IOMediaBSDClient, 8); 666OSMetaClassDefineReservedUnused(IOMediaBSDClient, 9); 667OSMetaClassDefineReservedUnused(IOMediaBSDClient, 10); 668OSMetaClassDefineReservedUnused(IOMediaBSDClient, 11); 669OSMetaClassDefineReservedUnused(IOMediaBSDClient, 12); 670OSMetaClassDefineReservedUnused(IOMediaBSDClient, 13); 671OSMetaClassDefineReservedUnused(IOMediaBSDClient, 14); 672OSMetaClassDefineReservedUnused(IOMediaBSDClient, 15); 673 674// ============================================================================= 675// BSD Functions 676 677typedef struct 678{ 679 user32_addr_t capacities; 680 uint32_t capacitiesCount; 681 682 uint8_t reserved0064[8]; 683} dk_format_capacities_32_t; 684 685typedef struct 686{ 687 user64_addr_t capacities; 688 uint32_t capacitiesCount; 689 690 uint8_t reserved0096[4]; 691} dk_format_capacities_64_t; 692 693typedef struct 694{ 695 user32_addr_t extents; 696 uint32_t extentsCount; 697 698 uint8_t reserved0064[8]; 699} dk_unmap_32_t; 700 701typedef struct 702{ 703 user64_addr_t extents; 704 uint32_t extentsCount; 705 706 uint8_t reserved0096[4]; 707} dk_unmap_64_t; 708 709static IOStorageAccess DK_ADD_ACCESS(IOStorageAccess a1, IOStorageAccess a2) 710{ 711 static UInt8 table[4][4] = 712 { /* Rea, Wri, R|S, W|S */ 713 /* Rea */ { 000, 001, 002, 003 }, 714 /* Wri */ { 001, 001, 001, 001 }, 715 /* R|S */ { 002, 001, 002, 003 }, 716 /* W|S */ { 003, 001, 003, 003 } 717 }; 718 719 if ( a1 == kIOStorageAccessNone ) return a2; 720 if ( a2 == kIOStorageAccessNone ) return a1; 721 722 a1 = (a1 - 1) >> 1; 723 a2 = (a2 - 1) >> 1; 724 725 if ( a1 > 003 ) return kIOStorageAccessNone; 726 if ( a2 > 003 ) return kIOStorageAccessNone; 727 728 return (table[a1][a2] << 1) + 1; 729} 730 731static bool DKIOC_IS_RESERVED(caddr_t data, uint32_t reserved) 732{ 733 UInt32 index; 734 735 for ( index = 0; index < sizeof(reserved) * 8; index++, reserved >>= 1 ) 736 { 737 if ( (reserved & 1) ) 738 { 739 if ( data[index] ) return true; 740 } 741 } 742 743 return false; 744} 745 746UInt64 _IOMediaBSDClientGetThrottleMask(IOMedia * media) 747{ 748 UInt64 mask; 749 750 mask = 0; 751 752 if ( media ) 753 { 754 int error; 755 756 error = EAGAIN; 757 758 while ( error ) 759 { 760 // Iterate through IOBlockStorageDevice objects. 761 762 IORegistryIterator * devices; 763 764 error = 0; 765 766 mask = 0; 767 768 devices = IORegistryIterator::iterateOver( media, gIOServicePlane, kIORegistryIterateParents ); 769 770 if ( devices ) 771 { 772 IORegistryEntry * device; 773 774 device = devices->getNextObjectRecursive( ); 775 776 while ( device ) 777 { 778 if ( OSDynamicCast( IOBlockStorageDevice, device ) ) 779 { 780 // Iterate through IOMedia objects. 781 782 IORegistryIterator * services; 783 784 services = IORegistryIterator::iterateOver( device, gIOServicePlane ); 785 786 if ( services ) 787 { 788 IORegistryEntry * service; 789 790 service = services->getNextObjectRecursive( ); 791 792 while ( service ) 793 { 794 if ( OSDynamicCast( IOMedia, service ) ) 795 { 796 // Obtain the BSD Unit property. 797 798 OSNumber * unit; 799 800 unit = OSDynamicCast( OSNumber, service->getProperty( kIOBSDUnitKey ) ); 801 802 if ( unit ) 803 { 804 mask |= 1 << ( unit->unsigned32BitValue( ) % 64 ); 805 } 806 } 807 808 service = services->getNextObjectRecursive( ); 809 } 810 811 if ( services->isValid( ) == false ) 812 { 813 error = EAGAIN; 814 } 815 816 services->release( ); 817 } 818 819///w:start 820 OSNumber * number; 821 822 number = OSDynamicCast( OSNumber, device->getProperty( "throttle-unit" ) ); 823 824 if ( number ) 825 { 826 OSDictionary * dictionary; 827 828 dictionary = IOService::serviceMatching( kIOMediaClass ); 829 830 if ( dictionary ) 831 { 832 OSIterator * iterator; 833 834 dictionary->setObject( kIOBSDUnitKey, number ); 835 836 iterator = IOService::getMatchingServices( dictionary ); 837 838 if ( iterator ) 839 { 840 OSObject * object; 841 842 object = iterator->getNextObject( ); 843 844 if ( object ) 845 { 846 mask |= _IOMediaBSDClientGetThrottleMask( ( IOMedia * ) object ); 847 } 848 849 iterator->release( ); 850 } 851 852 dictionary->release( ); 853 } 854 } 855///w:stop 856 devices->exitEntry( ); 857 } 858 859 device = devices->getNextObjectRecursive( ); 860 } 861 862 if ( devices->isValid( ) == false ) 863 { 864 error = EAGAIN; 865 } 866 867 devices->release( ); 868 } 869 } 870 } 871 872 return mask; 873} 874 875int dkopen(dev_t dev, int flags, int devtype, proc_t /* proc */) 876{ 877 // 878 // dkopen opens the device (called on each open). 879 // 880 881 IOStorageAccess access; 882 int error; 883 IOStorageAccess level; 884 IOStorageAccess levelOut; 885 IOMedia * media; 886 MinorSlot * minor; 887 888 assert(S_ISBLK(devtype) || S_ISCHR(devtype)); 889 890 gIOMediaBSDClientGlobals.lockOpen(); // (disable access to opens, closes) 891 gIOMediaBSDClientGlobals.lockState(); // (disable access to state, tables) 892 893 access = kIOStorageAccessReader; 894 access |= (flags & FWRITE) ? kIOStorageAccessReaderWriter : 0; 895 access |= (flags & O_SHLOCK) ? kIOStorageAccessSharedLock : 0; 896 access |= (flags & O_EXLOCK) ? kIOStorageAccessExclusiveLock : 0; 897 898 error = 0; 899 media = 0; 900 minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 901 902 // 903 // Process the open. 904 // 905 906 if ( minor == 0 ) // (is minor valid?) 907 { 908 error = ENXIO; 909 } 910 else if ( minor->isOrphaned ) // (is minor in flux?) 911 { 912 error = EBUSY; 913 } 914 else 915 { 916///w:start 917#ifdef __LP64__ 918 static int root = 0; 919 920 if ( root == 0 ) 921 { 922 root = 1; 923 924 if ( minor->media->isWritable() ) 925 { 926 access |= kIOStorageAccessReaderWriter; 927 } 928 } 929#endif /* __LP64__ */ 930///w:stop 931 level = DK_ADD_ACCESS(minor->bdevOpenLevel, minor->cdevOpenLevel); 932 levelOut = DK_ADD_ACCESS(level, access); 933 934 if ( levelOut == kIOStorageAccessNone ) // (is access valid?) 935 { 936 error = EBUSY; 937 } 938 else if ( (flags & FWRITE) ) // (is client a writer?) 939 { 940 if ( minor->media->isWritable() == false ) 941 { 942 error = EACCES; 943 } 944 } 945 } 946 947 if ( error == 0 ) // (go?) 948 { 949 IOStorageAccess wasOpenLevel; 950 951 if ( S_ISBLK(devtype) ) // (update state) 952 { 953 minor->bdevOpen++; 954 wasOpenLevel = minor->bdevOpenLevel; 955 minor->bdevOpenLevel = DK_ADD_ACCESS(wasOpenLevel, access); 956 } 957 else 958 { 959 minor->cdevOpen++; 960 wasOpenLevel = minor->cdevOpenLevel; 961 minor->cdevOpenLevel = DK_ADD_ACCESS(wasOpenLevel, access); 962 } 963 964 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 965 966 if ( level != levelOut ) // (issue open/upgrade?) 967 { 968 bool success; 969 970 media = minor->media; 971 minor->media->retain(); 972 973 success = minor->media->open(minor->client, 0, levelOut); // (go) 974 975 if ( success == false ) 976 { 977 gIOMediaBSDClientGlobals.lockState(); // (disable access) 978 979 if ( S_ISBLK(devtype) ) // (undo state) 980 { 981 minor->bdevOpen--; 982 minor->bdevOpenLevel = wasOpenLevel; 983 } 984 else 985 { 986 minor->cdevOpen--; 987 minor->cdevOpenLevel = wasOpenLevel; 988 } 989 990 assert(minor->isOrphaned == false); 991 992 if ( !minor->bdevOpen && !minor->cdevOpen && minor->isObsolete ) 993 { 994 gIOMediaBSDClientGlobals.getMinors()->remove(getminor(dev)); 995 } 996 997 gIOMediaBSDClientGlobals.unlockState(); // (enable access) 998 999 error = EBUSY; 1000 } 1001 } 1002 } 1003 else 1004 { 1005 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1006 } 1007 1008 gIOMediaBSDClientGlobals.unlockOpen(); // (enable access to opens, closes) 1009 1010 // 1011 // Wait until I/O Kit has finished to attempt to match storage drivers 1012 // or terminate storage drivers, should the media object have been re- 1013 // registered or its storage driver been terminated as a result of the 1014 // open. 1015 // 1016 1017 if ( media ) 1018 { 1019 media->waitQuiet(); 1020 media->release(); 1021 } 1022 1023 return error; 1024} 1025 1026int dkclose(dev_t dev, int /* flags */, int devtype, proc_t /* proc */) 1027{ 1028 // 1029 // dkclose closes the device (called on last close). 1030 // 1031 1032 IOStorageAccess level; 1033 IOStorageAccess levelOut; 1034 IOMedia * media; 1035 MinorSlot * minor; 1036 1037 assert(S_ISBLK(devtype) || S_ISCHR(devtype)); 1038 1039 gIOMediaBSDClientGlobals.lockOpen(); // (disable access to opens, closes) 1040 gIOMediaBSDClientGlobals.lockState(); // (disable access to state, tables) 1041 1042 media = 0; 1043 minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 1044 1045 level = DK_ADD_ACCESS(minor->bdevOpenLevel, minor->cdevOpenLevel); 1046 1047 if ( S_ISBLK(devtype) ) // (update state) 1048 { 1049 minor->bdevBlockSize = minor->media->getPreferredBlockSize(); 1050 minor->bdevOpen = 0; 1051 minor->bdevOpenLevel = kIOStorageAccessNone; 1052 } 1053 else 1054 { 1055 minor->cdevOpen = 0; 1056 minor->cdevOpenLevel = kIOStorageAccessNone; 1057#if TARGET_OS_EMBEDDED 1058 minor->cdevOptions = 0; 1059#endif /* TARGET_OS_EMBEDDED */ 1060 } 1061 1062 levelOut = DK_ADD_ACCESS(minor->bdevOpenLevel, minor->cdevOpenLevel); 1063 1064 if ( minor->isOrphaned ) // (is minor in flux?) 1065 { 1066 // 1067 // We have determined that the specified minor is in "open flux". This 1068 // means we are in a state where the media object has been closed, only 1069 // the device node is still open. This happens to the minor subsequent 1070 // to a DKIOCEJECT ioctl -- this close resets the flux state to normal. 1071 // 1072 1073 minor->isOrphaned = false; 1074 1075 // If this minor is marked as obsolete, then we've already received the 1076 // media's termination notification, but the minor is yet to be removed 1077 // from the table -- remove it now. 1078 1079 assert(minor->bdevOpen == 0); 1080 assert(minor->cdevOpen == 0); 1081 1082 if ( minor->isObsolete ) 1083 { 1084 gIOMediaBSDClientGlobals.getMinors()->remove(getminor(dev)); 1085 } 1086 1087 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1088 } 1089 else if ( !minor->bdevOpen && !minor->cdevOpen ) 1090 { 1091 // 1092 // We communicate the close down to the media object once all opens are 1093 // gone, on both the block and character device nodes. 1094 // 1095 1096 IOMediaBSDClient * client; 1097 1098 client = minor->client; 1099 minor->client->retain(); 1100 1101 media = minor->media; 1102 minor->media->retain(); 1103 1104 // If this minor is marked as obsolete, then we've already received the 1105 // media's termination notification, but the minor is yet to be removed 1106 // from the table -- remove it now. 1107 1108 if ( minor->isObsolete ) 1109 { 1110 gIOMediaBSDClientGlobals.getMinors()->remove(getminor(dev)); 1111 } 1112 1113 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1114 1115 media->close(client); // (go) 1116 1117 client->release(); 1118 } 1119 else if ( level != levelOut ) 1120 { 1121 // 1122 // We communicate the downgrade down to the media object. 1123 // 1124 1125 media = minor->media; 1126 minor->media->retain(); 1127 1128 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1129 1130 minor->media->open(minor->client, 0, levelOut); // (go) 1131 } 1132 else 1133 { 1134 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1135 } 1136 1137 gIOMediaBSDClientGlobals.unlockOpen(); // (enable access to opens, closes) 1138 1139 // 1140 // Wait until I/O Kit has finished to attempt to match storage drivers, 1141 // should the media object have been re-registered as a result of this 1142 // close. 1143 // 1144 1145 if ( media ) 1146 { 1147 media->waitQuiet(); 1148 media->release(); 1149 } 1150 1151 return 0; 1152} 1153 1154int dkread(dev_t dev, uio_t uio, int /* flags */) 1155{ 1156 // 1157 // dkread reads data from a device. 1158 // 1159 1160 struct dio dio = { dev, uio }; 1161 1162 return dkreadwrite(&dio, DKRTYPE_DIO); 1163} 1164 1165int dkwrite(dev_t dev, uio_t uio, int /* flags */) 1166{ 1167 // 1168 // dkwrite writes data to a device. 1169 // 1170 1171 struct dio dio = { dev, uio }; 1172 1173 return dkreadwrite(&dio, DKRTYPE_DIO); 1174} 1175 1176void dkstrategy(buf_t bp) 1177{ 1178 // 1179 // dkstrategy starts an asynchronous read or write operation. It returns 1180 // to the caller as soon as the operation is queued, and completes it via 1181 // the buf_biodone function. 1182 // 1183 1184 dkreadwrite(bp, DKRTYPE_BUF); 1185} 1186 1187int dkioctl(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc) 1188{ 1189 // 1190 // dkioctl performs operations other than a read or write. 1191 // 1192 1193 int error = 0; 1194 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 1195 1196 if ( minor->isOrphaned ) return EBADF; // (is minor in flux?) 1197 1198 // 1199 // Process the ioctl. 1200 // 1201 1202 switch ( cmd ) 1203 { 1204 case DKIOCGETBLOCKSIZE: // (uint32_t *) 1205 { 1206 // 1207 // This ioctl returns the preferred block size of the media object. 1208 // 1209 1210 *(uint32_t *)data = minor->media->getPreferredBlockSize(); 1211 1212 } break; 1213 1214#ifndef __LP64__ 1215 case DKIOCGETBLOCKCOUNT32: // (uint32_t *) 1216 { 1217 // 1218 // This ioctl returns the size of the media object in blocks. The 1219 // implied block size is returned by DKIOCGETBLOCKSIZE. 1220 // 1221 1222 if ( minor->media->getPreferredBlockSize() ) 1223 *(uint32_t *)data = ( minor->media->getSize() / 1224 minor->media->getPreferredBlockSize() ); 1225 else 1226 *(uint32_t *)data = 0; 1227 1228 } break; 1229#endif /* !__LP64__ */ 1230 1231 case DKIOCGETBLOCKCOUNT: // (uint64_t *) 1232 { 1233 // 1234 // This ioctl returns the size of the media object in blocks. The 1235 // implied block size is returned by DKIOCGETBLOCKSIZE. 1236 // 1237 1238 if ( minor->media->getPreferredBlockSize() ) 1239 *(uint64_t *)data = ( minor->media->getSize() / 1240 minor->media->getPreferredBlockSize() ); 1241 else 1242 *(uint64_t *)data = 0; 1243 1244 } break; 1245 1246 case DKIOCGETMAXBLOCKCOUNTREAD: // (uint64_t *) 1247 { 1248 // 1249 // This ioctl returns the maximum block count for reads. 1250 // 1251 1252 OSNumber * number = OSDynamicCast( 1253 /* class */ OSNumber, 1254 /* object */ minor->media->getProperty( 1255 /* key */ kIOMaximumBlockCountReadKey, 1256 /* plane */ gIOServicePlane ) ); 1257 if ( number ) 1258 *(uint64_t *)data = number->unsigned64BitValue(); 1259 else 1260 *(uint64_t *)data = 0; 1261 1262 } break; 1263 1264 case DKIOCGETMAXBLOCKCOUNTWRITE: // (uint64_t *) 1265 { 1266 // 1267 // This ioctl returns the maximum block count for writes. 1268 // 1269 1270 OSNumber * number = OSDynamicCast( 1271 /* class */ OSNumber, 1272 /* object */ minor->media->getProperty( 1273 /* key */ kIOMaximumBlockCountWriteKey, 1274 /* plane */ gIOServicePlane ) ); 1275 if ( number ) 1276 *(uint64_t *)data = number->unsigned64BitValue(); 1277 else 1278 *(uint64_t *)data = 0; 1279 1280 } break; 1281 1282 case DKIOCGETMAXBYTECOUNTREAD: // (uint64_t *) 1283 { 1284 // 1285 // This ioctl returns the maximum byte count for reads. 1286 // 1287 1288 OSNumber * number = OSDynamicCast( 1289 /* class */ OSNumber, 1290 /* object */ minor->media->getProperty( 1291 /* key */ kIOMaximumByteCountReadKey, 1292 /* plane */ gIOServicePlane ) ); 1293 if ( number ) 1294 *(uint64_t *)data = number->unsigned64BitValue(); 1295 else 1296 *(uint64_t *)data = 0; 1297 1298 } break; 1299 1300 case DKIOCGETMAXBYTECOUNTWRITE: // (uint64_t *) 1301 { 1302 // 1303 // This ioctl returns the maximum byte count for writes. 1304 // 1305 1306 OSNumber * number = OSDynamicCast( 1307 /* class */ OSNumber, 1308 /* object */ minor->media->getProperty( 1309 /* key */ kIOMaximumByteCountWriteKey, 1310 /* plane */ gIOServicePlane ) ); 1311 if ( number ) 1312 *(uint64_t *)data = number->unsigned64BitValue(); 1313 else 1314 *(uint64_t *)data = 0; 1315 1316 } break; 1317 1318 case DKIOCGETMAXSEGMENTCOUNTREAD: // (uint64_t *) 1319 { 1320 // 1321 // This ioctl returns the maximum segment count for reads. 1322 // 1323 1324 OSNumber * number = OSDynamicCast( 1325 /* class */ OSNumber, 1326 /* object */ minor->media->getProperty( 1327 /* key */ kIOMaximumSegmentCountReadKey, 1328 /* plane */ gIOServicePlane ) ); 1329 if ( number ) 1330 *(uint64_t *)data = number->unsigned64BitValue(); 1331 else 1332 *(uint64_t *)data = 0; 1333 1334 } break; 1335 1336 case DKIOCGETMAXSEGMENTCOUNTWRITE: // (uint64_t *) 1337 { 1338 // 1339 // This ioctl returns the maximum segment count for writes. 1340 // 1341 1342 OSNumber * number = OSDynamicCast( 1343 /* class */ OSNumber, 1344 /* object */ minor->media->getProperty( 1345 /* key */ kIOMaximumSegmentCountWriteKey, 1346 /* plane */ gIOServicePlane ) ); 1347 if ( number ) 1348 *(uint64_t *)data = number->unsigned64BitValue(); 1349 else 1350 *(uint64_t *)data = 0; 1351 1352 } break; 1353 1354 case DKIOCGETMAXSEGMENTBYTECOUNTREAD: // (uint64_t *) 1355 { 1356 // 1357 // This ioctl returns the maximum segment byte count for reads. 1358 // 1359 1360 OSNumber * number = OSDynamicCast( 1361 /* class */ OSNumber, 1362 /* object */ minor->media->getProperty( 1363 /* key */ kIOMaximumSegmentByteCountReadKey, 1364 /* plane */ gIOServicePlane ) ); 1365 if ( number ) 1366 *(uint64_t *)data = number->unsigned64BitValue(); 1367 else 1368 *(uint64_t *)data = 0; 1369 1370 } break; 1371 1372 case DKIOCGETMAXSEGMENTBYTECOUNTWRITE: // (uint64_t *) 1373 { 1374 // 1375 // This ioctl returns the maximum segment byte count for writes. 1376 // 1377 1378 OSNumber * number = OSDynamicCast( 1379 /* class */ OSNumber, 1380 /* object */ minor->media->getProperty( 1381 /* key */ kIOMaximumSegmentByteCountWriteKey, 1382 /* plane */ gIOServicePlane ) ); 1383 if ( number ) 1384 *(uint64_t *)data = number->unsigned64BitValue(); 1385 else 1386 *(uint64_t *)data = 0; 1387 1388 } break; 1389 1390 case DKIOCGETMINSEGMENTALIGNMENTBYTECOUNT: // (uint64_t *) 1391 { 1392 // 1393 // This ioctl returns the minimum segment alignment in bytes. 1394 // 1395 1396 OSNumber * number = OSDynamicCast( 1397 /* class */ OSNumber, 1398 /* object */ minor->media->getProperty( 1399 /* key */ kIOMinimumSegmentAlignmentByteCountKey, 1400 /* plane */ gIOServicePlane ) ); 1401 if ( number ) 1402 *(uint64_t *)data = number->unsigned64BitValue(); 1403 else 1404 *(uint64_t *)data = 0; 1405 1406 } break; 1407 1408 case DKIOCGETMAXSEGMENTADDRESSABLEBITCOUNT: // (uint64_t *) 1409 { 1410 // 1411 // This ioctl returns the maximum segment width in bits. 1412 // 1413 1414 OSNumber * number = OSDynamicCast( 1415 /* class */ OSNumber, 1416 /* object */ minor->media->getProperty( 1417 /* key */ kIOMaximumSegmentAddressableBitCountKey, 1418 /* plane */ gIOServicePlane ) ); 1419 if ( number ) 1420 *(uint64_t *)data = number->unsigned64BitValue(); 1421 else 1422 *(uint64_t *)data = 0; 1423 1424 } break; 1425 1426 case DKIOCGETPHYSICALBLOCKSIZE: // (uint32_t *) 1427 { 1428 // 1429 // This ioctl returns the preferred block size of the device. 1430 // 1431 1432 OSNumber * number = OSDynamicCast( 1433 /* class */ OSNumber, 1434 /* object */ minor->media->getProperty( 1435 /* key */ kIOPropertyPhysicalBlockSizeKey, 1436 /* plane */ gIOServicePlane ) ); 1437 if ( number ) 1438 *(uint32_t *)data = number->unsigned32BitValue(); 1439 else 1440 *(uint32_t *)data = minor->media->getPreferredBlockSize(); 1441 1442 } break; 1443 1444 case DKIOCGETCOMMANDPOOLSIZE: // (uint32_t *) 1445 { 1446 // 1447 // This ioctl returns the maximum queue depth of the device. 1448 // 1449 1450 OSNumber * number = OSDynamicCast( 1451 /* class */ OSNumber, 1452 /* object */ minor->media->getProperty( 1453 /* key */ kIOCommandPoolSizeKey, 1454 /* plane */ gIOServicePlane ) ); 1455 if ( number ) 1456 *(uint32_t *)data = number->unsigned32BitValue(); 1457 else 1458 *(uint32_t *)data = 0; 1459 1460 } break; 1461 1462 case DKIOCISFORMATTED: // (uint32_t *) 1463 { 1464 // 1465 // This ioctl returns truth if the media object is formatted. 1466 // 1467 1468 *(uint32_t *)data = minor->media->isFormatted(); 1469 1470 } break; 1471 1472 case DKIOCISWRITABLE: // (uint32_t *) 1473 { 1474 // 1475 // This ioctl returns truth if the media object is writable. 1476 // 1477 1478 *(uint32_t *)data = minor->media->isWritable(); 1479 1480 } break; 1481 1482 case DKIOCEJECT: // (void) 1483 { 1484 // 1485 // This ioctl asks that the media object be ejected from the device. 1486 // 1487 1488 IOMediaBSDClient * client; 1489 IOBlockStorageDriver * driver; 1490 MinorTable * minors; 1491 IOReturn status; 1492 1493 client = minor->client; 1494 driver = (IOBlockStorageDriver *) minor->media->getProvider(); 1495 driver = OSDynamicCast(IOBlockStorageDriver, driver); 1496 minors = gIOMediaBSDClientGlobals.getMinors(); 1497 1498 // Determine whether this media has an IOBlockStorageDriver parent. 1499 1500 if ( driver == 0 ) { error = ENOTTY; break; } 1501 1502 // Disable access to opens, closes, tables. 1503 1504 gIOMediaBSDClientGlobals.lockOpen(); 1505 gIOMediaBSDClientGlobals.lockState(); 1506 1507 // Determine whether there are other opens on the device nodes that 1508 // are associated with this anchor -- the one valid open is the one 1509 // that issued this eject. If all is well, we then attempt to open 1510 // the block storage driver to make the ejection request. 1511 1512 if ( minors->getOpenCountForAnchorID(minor->anchorID) == 1 && 1513 driver->open(client, 0, kIOStorageAccessReaderWriter) ) 1514 { 1515 // Mark the minor as being in "open flux". This means we are in 1516 // a state where the media object has been closed but the device 1517 // node is still open; we must reject all future accesses to the 1518 // device node until it is closed. Note that we do this both on 1519 // success and failure of the ejection call. 1520 1521 minor->isOrphaned = true; 1522 1523 // Enable access to opens, closes, tables. 1524 1525 gIOMediaBSDClientGlobals.unlockState(); 1526 gIOMediaBSDClientGlobals.unlockOpen(); 1527 1528 // Close the media object before the ejection request is made. 1529 1530 minor->media->close(client); 1531 1532 // Retain the media's BSD client object, as it is about 1533 // to be terminated, and we still need it for the close. 1534 1535 client->retain(); 1536 1537 // Eject the media from the drive. 1538 1539 status = driver->ejectMedia(); 1540 error = driver->errnoFromReturn(status); 1541 1542 // Close the block storage driver. 1543 1544 driver->close(client); 1545 1546 // Release the media's BSD client object. 1547 1548 client->release(); 1549 } 1550 else 1551 { 1552 error = EBUSY; 1553 1554 // Enable access to opens, closes, tables. 1555 1556 gIOMediaBSDClientGlobals.unlockState(); 1557 gIOMediaBSDClientGlobals.unlockOpen(); 1558 } 1559 1560 } break; 1561 1562 case DKIOCFORMAT: // (dk_format_capacity_t *) 1563 { 1564 // 1565 // This ioctl asks that the media object be formatted. 1566 // 1567 1568 IOMediaBSDClient * client; 1569 IOBlockStorageDriver * driver; 1570 MinorTable * minors; 1571 dk_format_capacity_t * request; 1572 IOReturn status; 1573 1574 client = minor->client; 1575 driver = (IOBlockStorageDriver *) minor->media->getProvider(); 1576 driver = OSDynamicCast(IOBlockStorageDriver, driver); 1577 minors = gIOMediaBSDClientGlobals.getMinors(); 1578 request = (dk_format_capacity_t *) data; 1579 1580 if ( DKIOC_IS_RESERVED(data, 0xF000) ) { error = EINVAL; break; } 1581 1582 // Determine whether this media has an IOBlockStorageDriver parent. 1583 1584 if ( driver == 0 ) { error = ENOTTY; break; } 1585 1586 // Disable access to opens, closes, tables. 1587 1588 gIOMediaBSDClientGlobals.lockOpen(); 1589 gIOMediaBSDClientGlobals.lockState(); 1590 1591 // Determine whether there are other opens on the device nodes that 1592 // are associated with this anchor -- the one valid open is the one 1593 // that issued the format. If all is well, we then attempt to open 1594 // the block storage driver to make the formatting request. 1595 1596 if ( minors->getOpenCountForAnchorID(minor->anchorID) == 1 && 1597 driver->open(client, 0, kIOStorageAccessReaderWriter) ) 1598 { 1599 UInt64 capacity = request->blockCount * request->blockSize; 1600 1601 // Mark the minor as being in "open flux". This means we are in 1602 // a state where the media object has been closed but the device 1603 // node is still open; we must reject all future accesses to the 1604 // device node until it is closed. Note that we do this both on 1605 // success and failure of the formatting call. 1606 1607 minor->isOrphaned = true; 1608 1609 // Enable access to opens, closes, tables. 1610 1611 gIOMediaBSDClientGlobals.unlockState(); 1612 gIOMediaBSDClientGlobals.unlockOpen(); 1613 1614 // Close the media object before the formatting request is made. 1615 1616 minor->media->close(client); 1617 1618 // Retain the media's BSD client object, as it is about 1619 // to be terminated, and we still need it for the close. 1620 1621 client->retain(); 1622 1623 // Format the media in the drive. 1624 1625 status = driver->formatMedia(capacity); 1626 error = driver->errnoFromReturn(status); 1627 1628 // Wait until I/O Kit has finished to attempt to match storage 1629 // drivers, since the media object will have been re-published. 1630 // This shall ensure the new IOMediaBSDClient reconnects prior 1631 // to our return from DKIOCFORMAT. Note that we still recover 1632 // correctly in case the media object doesn't get re-published, 1633 // as though an ejection had taken place. 1634 1635 driver->waitQuiet(); 1636 1637 // Close the block storage driver. 1638 1639 driver->close(client); 1640 1641 // Release the media's BSD client object. 1642 1643 client->release(); 1644 } 1645 else 1646 { 1647 error = EBUSY; 1648 1649 // Enable access to opens, closes, tables. 1650 1651 gIOMediaBSDClientGlobals.unlockState(); 1652 gIOMediaBSDClientGlobals.unlockOpen(); 1653 } 1654 1655 } break; 1656 1657 case DKIOCGETFORMATCAPACITIES: // (dk_format_capacities_t *) 1658 { 1659 // 1660 // This ioctl returns the feasible format capacities for this media 1661 // object. 1662 // 1663 1664 UInt64 blockSize; 1665 UInt64 * capacities; 1666 UInt32 capacitiesCount; 1667 UInt32 capacitiesMaxCount; 1668 IOBlockStorageDriver * driver; 1669 dk_format_capacities_64_t request; 1670 dk_format_capacities_32_t * request32; 1671 dk_format_capacities_64_t * request64; 1672 1673 driver = (IOBlockStorageDriver *) minor->media->getProvider(); 1674 driver = OSDynamicCast(IOBlockStorageDriver, driver); 1675 request32 = (dk_format_capacities_32_t *) data; 1676 request64 = (dk_format_capacities_64_t *) data; 1677 1678 if ( proc_is64bit(proc) ) 1679 { 1680 if ( DKIOC_IS_RESERVED(data, 0xF000) ) { error = EINVAL; break; } 1681 1682 request.capacities = request64->capacities; 1683 request.capacitiesCount = request64->capacitiesCount; 1684 } 1685 else 1686 { 1687 if ( DKIOC_IS_RESERVED(data, 0xFF00) ) { error = EINVAL; break; } 1688 1689 request.capacities = request32->capacities; 1690 request.capacitiesCount = request32->capacitiesCount; 1691 } 1692 1693 // Determine whether this media has an IOBlockStorageDriver parent. 1694 1695 if ( driver == 0 ) { error = ENOTTY; break; } 1696 1697 // Obtain the format capacities list from the block storage driver. 1698 1699 capacitiesCount = request.capacitiesCount; 1700 capacitiesMaxCount = driver->getFormatCapacities(0, 0); 1701 1702 if ( capacitiesCount ) 1703 { 1704 if ( request.capacities == 0 ) { error = EINVAL; break; } 1705 1706 capacitiesCount = min(capacitiesCount, capacitiesMaxCount); 1707 capacities = IONew(UInt64, capacitiesCount); 1708 1709 if ( capacities == 0 ) { error = ENOMEM; break; } 1710 1711 driver->getFormatCapacities(capacities, capacitiesCount); 1712 1713 blockSize = minor->media->getPreferredBlockSize(); 1714 if ( blockSize == 0 ) blockSize = DEV_BSIZE; 1715 1716 // Construct the format capacities list for client consumption. 1717 1718 for ( UInt32 index = 0; index < capacitiesCount; index++ ) 1719 { 1720 dk_format_capacity_t capacity = { 0 }; 1721 1722 capacity.blockCount = capacities[index] / blockSize; 1723 capacity.blockSize = blockSize; 1724 1725 if ( proc == kernproc ) 1726 { 1727 bcopy( /* src */ &capacity, 1728 /* dst */ (void *) (request.capacities + index * sizeof(dk_format_capacity_t)), 1729 /* n */ sizeof(dk_format_capacity_t) ); 1730 } 1731 else 1732 { 1733 error = copyout( /* kaddr */ &capacity, 1734 /* uaddr */ request.capacities + index * sizeof(dk_format_capacity_t), 1735 /* len */ sizeof(dk_format_capacity_t) ); 1736 } 1737 1738 if ( error ) break; 1739 } 1740 1741 IODelete(capacities, UInt64, capacitiesCount); 1742 1743 if ( capacitiesCount < capacitiesMaxCount ) { error = E2BIG; } 1744 } 1745 1746 if ( proc_is64bit(proc) ) 1747 { 1748 request64->capacitiesCount = request.capacitiesCount; 1749 } 1750 else 1751 { 1752 request32->capacitiesCount = request.capacitiesCount; 1753 } 1754 1755 } break; 1756 1757 case DKIOCSYNCHRONIZECACHE: // (void) 1758 { 1759 // 1760 // This ioctl asks that the media object be flushed onto the device. 1761 // 1762 1763 IOReturn status; 1764 1765 // Flush the media onto the drive. 1766 1767 status = minor->media->synchronizeCache(minor->client); 1768 error = minor->media->errnoFromReturn(status); 1769 1770 } break; 1771 1772 case DKIOCUNMAP: // (dk_unmap_t) 1773 { 1774 // 1775 // This ioctl asks that the media object delete unused data. 1776 // 1777 1778 IOStorageExtent * extents; 1779 dk_unmap_64_t request; 1780 dk_unmap_32_t * request32; 1781 dk_unmap_64_t * request64; 1782 IOReturn status; 1783 1784 assert(sizeof(dk_extent_t) == sizeof(IOStorageExtent)); 1785 1786 request32 = (dk_unmap_32_t *) data; 1787 request64 = (dk_unmap_64_t *) data; 1788 1789 if ( proc_is64bit(proc) ) 1790 { 1791 if ( DKIOC_IS_RESERVED(data, 0xF000) ) { error = EINVAL; break; } 1792 1793 request.extents = request64->extents; 1794 request.extentsCount = request64->extentsCount; 1795 } 1796 else 1797 { 1798 if ( DKIOC_IS_RESERVED(data, 0xFF00) ) { error = EINVAL; break; } 1799 1800 request.extents = request32->extents; 1801 request.extentsCount = request32->extentsCount; 1802 } 1803 1804 // Delete unused data from the media. 1805 1806 if ( request.extents == 0 ) { error = EINVAL; break; } 1807 1808 extents = IONew(IOStorageExtent, request.extentsCount); 1809 1810 if ( extents == 0 ) { error = ENOMEM; break; } 1811 1812 if ( proc == kernproc ) 1813 { 1814 bcopy( /* src */ (void *) request.extents, 1815 /* dst */ extents, 1816 /* n */ request.extentsCount * sizeof(IOStorageExtent) ); 1817 } 1818 else 1819 { 1820 error = copyin( /* uaddr */ request.extents, 1821 /* kaddr */ extents, 1822 /* len */ request.extentsCount * sizeof(IOStorageExtent) ); 1823 } 1824 1825 if ( error == 0 ) 1826 { 1827 status = minor->media->unmap( /* client */ minor->client, 1828 /* extents */ extents, 1829 /* extentsCount */ request.extentsCount ); 1830 1831 error = minor->media->errnoFromReturn(status); 1832 } 1833 1834 IODelete(extents, IOStorageExtent, request.extentsCount); 1835 1836 } break; 1837 1838 case DKIOCREQUESTIDLE: // (void) 1839 { 1840 // 1841 // This ioctl asks that the device enter an idle state. 1842 // 1843 1844 IOBlockStorageDriver * driver; 1845 IOReturn status; 1846 1847 driver = (IOBlockStorageDriver *) minor->media->getProvider(); 1848 driver = OSDynamicCast(IOBlockStorageDriver, driver); 1849 1850 // Determine whether this media has an IOBlockStorageDriver parent. 1851 1852 if ( driver == 0 ) { error = ENOTTY; break; } 1853 1854 // Request that the drive enter an idle state. 1855 1856 status = driver->requestIdle(); 1857 error = minor->media->errnoFromReturn(status); 1858 1859 } break; 1860 1861 case DKIOCGETBSDUNIT: // (uint32_t *) 1862 { 1863 // 1864 // This ioctl returns the BSD unit of the media object. 1865 // 1866 1867 OSNumber * number = OSDynamicCast( 1868 /* class */ OSNumber, 1869 /* object */ minor->media->getProperty( 1870 /* key */ kIOBSDUnitKey ) ); 1871 if ( number ) 1872 *(uint32_t *)data = number->unsigned32BitValue(); 1873 else 1874 *(uint32_t *)data = 0; 1875 1876 } break; 1877 1878 case DKIOCGETFIRMWAREPATH: // (dk_firmware_path_t *) 1879 { 1880 // 1881 // This ioctl returns the open firmware path for this media object. 1882 // 1883 1884 int l = sizeof(((dk_firmware_path_t *)data)->path); 1885 char * p = ((dk_firmware_path_t *)data)->path; 1886 1887 if ( minor->media->getPath(p, &l, gIODTPlane) && strchr(p, ':') ) 1888 strlcpy(p, strchr(p, ':') + 1, l); // (strip the plane name) 1889 else 1890 error = EINVAL; 1891 1892 } break; 1893 1894 case DKIOCISSOLIDSTATE: // (uint32_t *) 1895 { 1896 // 1897 // This ioctl returns truth if the device is solid state. 1898 // 1899 1900 OSDictionary * dictionary = OSDynamicCast( 1901 /* class */ OSDictionary, 1902 /* object */ minor->media->getProperty( 1903 /* key */ kIOPropertyDeviceCharacteristicsKey, 1904 /* plane */ gIOServicePlane ) ); 1905 1906 *(uint32_t *)data = false; 1907 1908 if ( dictionary ) 1909 { 1910 OSString * string = OSDynamicCast( 1911 /* class */ OSString, 1912 /* object */ dictionary->getObject( 1913 /* key */ kIOPropertyMediumTypeKey ) ); 1914 1915 if ( string && string->isEqualTo(kIOPropertyMediumTypeSolidStateKey) ) 1916 *(uint32_t *)data = true; 1917 } 1918 1919 } break; 1920 1921 case DKIOCISVIRTUAL: // (uint32_t *) 1922 { 1923 // 1924 // This ioctl returns truth if the device is virtual. 1925 // 1926 1927 OSDictionary * dictionary = OSDynamicCast( 1928 /* class */ OSDictionary, 1929 /* object */ minor->media->getProperty( 1930 /* key */ kIOPropertyProtocolCharacteristicsKey, 1931 /* plane */ gIOServicePlane ) ); 1932 1933 *(uint32_t *)data = false; 1934 1935 if ( dictionary ) 1936 { 1937 OSString * string = OSDynamicCast( 1938 /* class */ OSString, 1939 /* object */ dictionary->getObject( 1940 /* key */ kIOPropertyPhysicalInterconnectTypeKey ) ); 1941 1942 if ( string && string->isEqualTo(kIOPropertyPhysicalInterconnectTypeVirtual) ) 1943 *(uint32_t *)data = true; 1944 } 1945 1946 } break; 1947 1948 case DKIOCGETBASE: // (uint64_t *) 1949 { 1950 // 1951 // This ioctl returns the base of the media object. 1952 // 1953 1954 *(uint64_t *)data = minor->media->getBase(); 1955 1956 } break; 1957 1958 case DKIOCGETFEATURES: // (uint32_t *) 1959 { 1960 // 1961 // This ioctl returns the features of the media object. 1962 // 1963 1964 OSDictionary * dictionary = OSDynamicCast( 1965 /* class */ OSDictionary, 1966 /* object */ minor->media->getProperty( 1967 /* key */ kIOStorageFeaturesKey, 1968 /* plane */ gIOServicePlane ) ); 1969 1970 *(uint32_t *)data = 0; 1971 1972 if ( dictionary ) 1973 { 1974 OSBoolean * boolean; 1975 1976 boolean = OSDynamicCast( 1977 /* class */ OSBoolean, 1978 /* object */ dictionary->getObject( 1979 /* key */ kIOStorageFeatureUnmap ) ); 1980 1981 if ( boolean == kOSBooleanTrue ) 1982 *(uint32_t *)data |= DK_FEATURE_UNMAP; 1983 1984 boolean = OSDynamicCast( 1985 /* class */ OSBoolean, 1986 /* object */ dictionary->getObject( 1987 /* key */ kIOStorageFeatureForceUnitAccess ) ); 1988 1989 if ( boolean == kOSBooleanTrue ) 1990 *(uint32_t *)data |= DK_FEATURE_FORCE_UNIT_ACCESS; 1991 } 1992 1993 } break; 1994 1995 case DKIOCGETTHROTTLEMASK: // (uint64_t *) 1996 { 1997 // 1998 // This ioctl returns the throttle mask for the media object. 1999 // 2000 2001 *( ( uint64_t * ) data ) = _IOMediaBSDClientGetThrottleMask( minor->media ); 2002 2003 } break; 2004 2005 default: 2006 { 2007 // 2008 // Call the foreign ioctl handler for all other ioctls. 2009 // 2010 2011 error = minor->client->ioctl(dev, cmd, data, flags, proc); 2012 2013 } break; 2014 } 2015 2016 return error; // (return error status) 2017} 2018 2019int dkioctl_bdev(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc) 2020{ 2021 // 2022 // dkioctl_bdev performs operations other than a read or write, specific to 2023 // the block device. 2024 // 2025 2026 int error = 0; 2027 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2028 2029 if ( minor->isOrphaned ) return EBADF; // (is minor in flux?) 2030 2031 // 2032 // Process the ioctl. 2033 // 2034 2035 switch ( cmd ) 2036 { 2037 case DKIOCGETBLOCKSIZE: // (uint32_t *) 2038 { 2039 // 2040 // This ioctl returns the preferred (or overrided) block size of the 2041 // media object. 2042 // 2043 2044 *(uint32_t *)data = minor->bdevBlockSize; 2045 2046 } break; 2047 2048 case DKIOCSETBLOCKSIZE: // (uint32_t *) 2049 { 2050 // 2051 // This ioctl overrides the block size for the media object, for the 2052 // duration of all block device opens at this minor. 2053 // 2054 2055 if ( *(uint32_t *)data > 0 ) 2056 minor->bdevBlockSize = (UInt64) (*(uint32_t *)data); 2057 else 2058 error = EINVAL; 2059 2060 } break; 2061 2062#ifndef __LP64__ 2063 case DKIOCGETBLOCKCOUNT32: // (uint32_t *) 2064 { 2065 // 2066 // This ioctl returns the size of the media object in blocks. The 2067 // implied block size is returned by DKIOCGETBLOCKSIZE. 2068 // 2069 2070 if ( minor->bdevBlockSize ) 2071 *(uint32_t *)data = ( minor->media->getSize() / 2072 minor->bdevBlockSize ); 2073 else 2074 *(uint32_t *)data = 0; 2075 2076 } break; 2077#endif /* !__LP64__ */ 2078 2079 case DKIOCGETBLOCKCOUNT: // (uint64_t *) 2080 { 2081 // 2082 // This ioctl returns the size of the media object in blocks. The 2083 // implied block size is returned by DKIOCGETBLOCKSIZE. 2084 // 2085 2086 if ( minor->bdevBlockSize ) 2087 *(uint64_t *)data = ( minor->media->getSize() / 2088 minor->bdevBlockSize ); 2089 else 2090 *(uint64_t *)data = 0; 2091 2092 } break; 2093 2094 case DKIOCLOCKPHYSICALEXTENTS: // (void) 2095 { 2096 bool success; 2097 2098 success = minor->media->lockPhysicalExtents( minor->client ); 2099 2100 if ( success == false ) 2101 { 2102 error = ENOTSUP; 2103 } 2104 2105 } break; 2106 2107 case DKIOCGETPHYSICALEXTENT: // (dk_physical_extent_t) 2108 { 2109 dk_physical_extent_t * request; 2110 2111 request = ( dk_physical_extent_t * ) data; 2112 2113 if ( DKIOC_IS_RESERVED( data, 0xFFFF0000 ) == false ) 2114 { 2115 IOStorage * media; 2116 2117 media = minor->media->copyPhysicalExtent( minor->client, &request->offset, &request->length ); 2118 2119 if ( media ) 2120 { 2121 OSNumber * majorID; 2122 2123 majorID = OSDynamicCast( OSNumber, media->getProperty( kIOBSDMajorKey ) ); 2124 2125 if ( majorID ) 2126 { 2127 OSNumber * minorID; 2128 2129 minorID = OSDynamicCast( OSNumber, media->getProperty( kIOBSDMinorKey ) ); 2130 2131 if ( minorID ) 2132 { 2133 request->dev = makedev( majorID->unsigned32BitValue( ), minorID->unsigned32BitValue( ) ); 2134 } 2135 else 2136 { 2137 error = ENODEV; 2138 } 2139 } 2140 else 2141 { 2142 error = ENODEV; 2143 } 2144 2145 media->release( ); 2146 } 2147 else 2148 { 2149 error = ENOTSUP; 2150 } 2151 } 2152 else 2153 { 2154 error = EINVAL; 2155 } 2156 2157 } break; 2158 2159 case DKIOCUNLOCKPHYSICALEXTENTS: // (void) 2160 { 2161 minor->media->unlockPhysicalExtents( minor->client ); 2162 2163 } break; 2164 2165 case DKIOCGETMAXPRIORITYCOUNT: // (uint32_t *) 2166 { 2167 // 2168 // This ioctl returns the maximum priority depth of the device. 2169 // 2170 2171 OSNumber * number = OSDynamicCast( 2172 /* class */ OSNumber, 2173 /* object */ minor->media->getProperty( 2174 /* key */ kIOMaximumPriorityCountKey, 2175 /* plane */ gIOServicePlane ) ); 2176 if ( number ) 2177 *(uint32_t *)data = number->unsigned32BitValue(); 2178 else 2179 *(uint32_t *)data = 0; 2180 2181 } break; 2182 2183 default: 2184 { 2185 // 2186 // Call the common ioctl handler for all other ioctls. 2187 // 2188 2189 error = dkioctl(dev, cmd, data, flags, proc); 2190 2191 } break; 2192 } 2193 2194 return error; // (return error status) 2195} 2196 2197int dkioctl_cdev(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc) 2198{ 2199 // 2200 // dkioctl_cdev performs operations other than a read or write, specific to 2201 // the character device. 2202 // 2203 2204 int error = 0; 2205 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2206 2207 if ( minor->isOrphaned ) return EBADF; // (is minor in flux?) 2208 2209 // 2210 // Process the ioctl. 2211 // 2212 2213 switch ( cmd ) 2214 { 2215#if TARGET_OS_EMBEDDED 2216 case _DKIOCSETSTATIC: // (void) 2217 { 2218 minor->cdevOptions |= kIOStorageOptionIsStatic; 2219 2220 } break; 2221#endif /* TARGET_OS_EMBEDDED */ 2222 2223 default: 2224 { 2225 // 2226 // Call the common ioctl handler for all other ioctls. 2227 // 2228 2229 error = dkioctl(dev, cmd, data, flags, proc); 2230 2231 } break; 2232 } 2233 2234 return error; // (return error status) 2235} 2236 2237int dksize(dev_t dev) 2238{ 2239 // 2240 // dksize returns the block size of the media. 2241 // 2242 // This is a departure from BSD 4.4's definition of this function, that is, 2243 // it will not return the size of the disk partition, as would be expected 2244 // in a BSD 4.4 implementation. 2245 // 2246 2247 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2248 2249 if ( minor->isOrphaned ) return 0; // (is minor in flux?) 2250 2251 return (int) minor->bdevBlockSize; // (return block size) 2252} 2253 2254// ============================================================================= 2255// Support For BSD Functions 2256 2257extern "C" task_t get_aiotask(); 2258 2259inline task_t get_kernel_task() 2260{ 2261 return kernel_task; 2262} 2263 2264inline task_t get_user_task() 2265{ 2266 task_t task; 2267 2268 task = get_aiotask(); 2269 2270 if ( task == 0 ) task = current_task(); 2271 2272 return task; 2273} 2274 2275inline dev_t DKR_GET_DEV(dkr_t dkr, dkrtype_t dkrtype) 2276{ 2277 return (dkrtype == DKRTYPE_BUF) 2278 ? buf_device((buf_t)dkr) 2279 : ((dio_t)dkr)->dev; 2280} 2281 2282inline UInt64 DKR_GET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype) 2283{ 2284 return (dkrtype == DKRTYPE_BUF) 2285 ? buf_count((buf_t)dkr) 2286 : uio_resid(((dio_t)dkr)->uio); 2287} 2288 2289inline UInt64 DKR_GET_BYTE_START(dkr_t dkr, dkrtype_t dkrtype) 2290{ 2291 if (dkrtype == DKRTYPE_BUF) 2292 { 2293 buf_t bp = (buf_t)dkr; 2294 MinorSlot * minor; 2295 2296 minor = gIOMediaBSDClientGlobals.getMinor(getminor(buf_device(bp))); 2297 2298 return (UInt64)buf_blkno(bp) * minor->bdevBlockSize; 2299 } 2300 2301 return uio_offset(((dio_t)dkr)->uio); 2302} 2303 2304inline bool DKR_IS_READ(dkr_t dkr, dkrtype_t dkrtype) 2305{ 2306 return (dkrtype == DKRTYPE_BUF) 2307 ? ((buf_flags((buf_t)dkr) & B_READ) == B_READ) 2308 : ((uio_rw(((dio_t)dkr)->uio)) == UIO_READ); 2309} 2310 2311inline bool DKR_IS_ASYNCHRONOUS(dkr_t dkr, dkrtype_t dkrtype) 2312{ 2313 return (dkrtype == DKRTYPE_BUF) 2314 ? true 2315 : false; 2316} 2317 2318inline bool DKR_IS_RAW(dkr_t dkr, dkrtype_t dkrtype) 2319{ 2320 return (dkrtype == DKRTYPE_BUF) 2321 ? false 2322 : true; 2323} 2324 2325inline void DKR_SET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype, UInt64 bcount) 2326{ 2327 if (dkrtype == DKRTYPE_BUF) 2328 buf_setresid((buf_t)dkr, buf_count((buf_t)dkr) - bcount); 2329 else 2330 uio_setresid(((dio_t)dkr)->uio, uio_resid(((dio_t)dkr)->uio) - bcount); 2331} 2332 2333inline void DKR_RUN_COMPLETION(dkr_t dkr, dkrtype_t dkrtype, IOReturn status) 2334{ 2335 if (dkrtype == DKRTYPE_BUF) 2336 { 2337 buf_t bp = (buf_t)dkr; 2338 MinorSlot * minor; 2339 2340 minor = gIOMediaBSDClientGlobals.getMinor(getminor(buf_device(bp))); 2341 2342 buf_seterror(bp, minor->media->errnoFromReturn(status)); // (error?) 2343 buf_biodone(bp); // (complete request) 2344 } 2345} 2346 2347inline IOMemoryDescriptor * DKR_GET_BUFFER(dkr_t dkr, dkrtype_t dkrtype) 2348{ 2349 if (dkrtype == DKRTYPE_BUF) 2350 { 2351 buf_t bp = (buf_t)dkr; 2352 int flags; 2353 2354 flags = buf_flags(bp); 2355 2356 if ( (flags & B_CLUSTER) ) 2357 { 2358 IOOptionBits options = kIOMemoryTypeUPL | kIOMemoryAsReference; 2359 2360 options |= (flags & B_READ) ? kIODirectionIn : kIODirectionOut; 2361 2362 return IOMemoryDescriptor::withOptions( // (multiple-range) 2363 buf_upl(bp), 2364 buf_count(bp), 2365 buf_uploffset(bp), 2366 0, 2367 options ); 2368 } 2369 else 2370 { 2371 return IOMemoryDescriptor::withAddressRange( // (single-range) 2372 buf_dataptr(bp), 2373 buf_count(bp), 2374 (flags & B_READ) ? kIODirectionIn : kIODirectionOut, 2375 (flags & B_PHYS) ? get_user_task() : get_kernel_task() ); 2376 } 2377 } 2378 else 2379 { 2380 IOOptionBits options = kIOMemoryTypeUIO | kIOMemoryAsReference; 2381 uio_t uio = ((dio_t)dkr)->uio; 2382 2383 options |= (uio_rw(uio) == UIO_READ) ? kIODirectionIn : kIODirectionOut; 2384 2385 return IOMemoryDescriptor::withOptions( // (multiple-range) 2386 uio, 2387 uio_iovcnt(uio), 2388 0, 2389 (uio_isuserspace(uio)) ? get_user_task() : get_kernel_task(), 2390 options ); 2391 } 2392} 2393 2394inline void * DKR_GET_DRIVER_DATA(dkr_t dkr, dkrtype_t dkrtype) 2395{ 2396 return (dkrtype == DKRTYPE_BUF) 2397 ? buf_drvdata((buf_t)dkr) 2398 : ((dio_t)dkr)->drvdata; 2399} 2400 2401inline void DKR_SET_DRIVER_DATA(dkr_t dkr, dkrtype_t dkrtype, void * drvdata) 2402{ 2403 if (dkrtype == DKRTYPE_BUF) 2404 buf_setdrvdata((buf_t)dkr, drvdata); 2405 else 2406 ((dio_t)dkr)->drvdata = drvdata; 2407} 2408 2409inline IOStorageAttributes DKR_GET_ATTRIBUTES(dkr_t dkr, dkrtype_t dkrtype) 2410{ 2411 IOStorageAttributes attributes = { 0 }; 2412 2413 if (dkrtype == DKRTYPE_BUF) 2414 { 2415 buf_t bp = (buf_t)dkr; 2416 int flags; 2417 2418 flags = buf_flags(bp); 2419 2420 attributes.bufattr = buf_attr(bp); 2421 2422 attributes.options |= (flags & B_FUA ) ? kIOStorageOptionForceUnitAccess : 0; 2423 attributes.options |= (flags & B_ENCRYPTED_IO ) ? kIOStorageOptionIsEncrypted : 0; 2424 attributes.options |= (flags & B_STATICCONTENT) ? kIOStorageOptionIsStatic : 0; 2425 } 2426#if TARGET_OS_EMBEDDED 2427 else 2428 { 2429 dev_t dev = ((dio_t)dkr)->dev; 2430 MinorSlot * minor; 2431 2432 minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2433 2434 attributes.options |= minor->cdevOptions; 2435 } 2436#endif /* TARGET_OS_EMBEDDED */ 2437 2438 return attributes; 2439} 2440///w:start 2441#if !TARGET_OS_EMBEDDED 2442inline bool DKR_DELAY_IDLE_SLEEP(dkr_t dkr, dkrtype_t dkrtype) 2443{ 2444 return (dkrtype == DKRTYPE_BUF) 2445 ? bufattr_delayidlesleep(buf_attr((buf_t)dkr)) 2446 : false; 2447} 2448#endif /* !TARGET_OS_EMBEDDED */ 2449///w:stop 2450 2451int dkreadwrite(dkr_t dkr, dkrtype_t dkrtype) 2452{ 2453 // 2454 // dkreadwrite performs a read or write operation. 2455 // 2456 2457 IOStorageAttributes attributes; 2458 IOMemoryDescriptor * buffer; 2459 register UInt64 byteCount; 2460 register UInt64 byteStart; 2461 UInt64 mediaSize; 2462 MinorSlot * minor; 2463 IOReturn status; 2464 2465 DKR_SET_DRIVER_DATA(dkr, dkrtype, 0); 2466 2467 minor = gIOMediaBSDClientGlobals.getMinor(getminor(DKR_GET_DEV(dkr, dkrtype))); 2468 2469 if ( minor->isOrphaned ) // (is minor in flux?) 2470 { 2471 status = kIOReturnNoMedia; 2472 goto dkreadwriteErr; 2473 } 2474 2475 if ( minor->media->isFormatted() == false ) // (is media unformatted?) 2476 { 2477 status = kIOReturnUnformattedMedia; 2478 goto dkreadwriteErr; 2479 } 2480 2481 byteCount = DKR_GET_BYTE_COUNT(dkr, dkrtype); // (get byte count) 2482 byteStart = DKR_GET_BYTE_START(dkr, dkrtype); // (get byte start) 2483 mediaSize = minor->media->getSize(); // (get media size) 2484 2485 // 2486 // Reads that start at (or perhaps past) the end-of-media are not considered 2487 // errors, even though no data is transferred, while writes at (or past) the 2488 // end-of-media do indeed return errors under BSD semantics. 2489 // 2490 2491 if ( byteStart >= mediaSize ) // (is start at or past the end-of-media?) 2492 { 2493 status = DKR_IS_READ(dkr,dkrtype) ? kIOReturnSuccess : kIOReturnIOError; 2494 goto dkreadwriteErr; 2495 } 2496 2497 // 2498 // Reads and writes, via the character device, that do not start or end on a 2499 // media block boundary are considered errors under BSD semantics. 2500 // 2501 2502 if ( DKR_IS_RAW(dkr, dkrtype) ) 2503 { 2504 UInt64 mediaBlockSize = minor->media->getPreferredBlockSize(); 2505 2506 if ( (byteStart % mediaBlockSize) || (byteCount % mediaBlockSize) ) 2507 { 2508 status = kIOReturnNotAligned; 2509 goto dkreadwriteErr; 2510 } 2511 } 2512 2513 // 2514 // Build a descriptor which describes the buffer involved in the transfer. 2515 // 2516 2517 buffer = DKR_GET_BUFFER(dkr, dkrtype); 2518 2519 if ( buffer == 0 ) // (no buffer?) 2520 { 2521 status = kIOReturnNoMemory; 2522 goto dkreadwriteErr; 2523 } 2524 2525 // 2526 // Reads and writes that extend beyond the end-of-media are not considered 2527 // errors under BSD semantics. We are to transfer as many bytes as can be 2528 // read or written from the medium and return no error. This differs from 2529 // IOMedia semantics which is to fail the entire request without copying a 2530 // single byte should it include something past the end-of-media. We must 2531 // adapt the IOMedia semantics to look like BSD semantics here. 2532 // 2533 // Clip the transfer buffer should this be a short read or write request. 2534 // 2535 2536 if ( byteCount > mediaSize - byteStart ) // (clip at end-of-media) 2537 { 2538 IOMemoryDescriptor * originalBuffer = buffer; 2539 2540 buffer = IOSubMemoryDescriptor::withSubRange( 2541 /* descriptor */ originalBuffer, 2542 /* withOffset */ 0, 2543 /* withLength */ mediaSize - byteStart, 2544 /* withDirection */ originalBuffer->getDirection() ); 2545 2546 originalBuffer->release(); // (either retained above or about to fail) 2547 2548 if ( buffer == 0 ) // (no buffer?) 2549 { 2550 status = kIOReturnNoMemory; 2551 goto dkreadwriteErr; 2552 } 2553 } 2554 2555 // 2556 // Prepare the transfer. 2557 // 2558 2559 if ( buffer->prepare() != kIOReturnSuccess ) // (prepare the buffer) 2560 { 2561 buffer->release(); 2562 status = kIOReturnVMError; // (wiring or permissions failure) 2563 goto dkreadwriteErr; 2564 } 2565 2566 // 2567 // Execute the transfer. 2568 // 2569 2570 attributes = DKR_GET_ATTRIBUTES(dkr, dkrtype); 2571 2572 DKR_SET_DRIVER_DATA(dkr, dkrtype, buffer); 2573 2574///w:start 2575#if !TARGET_OS_EMBEDDED 2576 if ( DKR_DELAY_IDLE_SLEEP(dkr, dkrtype) ) 2577 { 2578 IOPMDriverAssertionID assertionID; 2579 AbsoluteTime assertionTime; 2580 2581 gIOMediaBSDClientGlobals.lockAssertion(); 2582 2583 clock_interval_to_deadline(60, NSEC_PER_SEC, &assertionTime); 2584 2585 gIOMediaBSDClientGlobals.setAssertionTime(assertionTime); 2586 2587 assertionID = gIOMediaBSDClientGlobals.getAssertionID(); 2588 2589 if ( assertionID == kIOPMUndefinedDriverAssertionID ) 2590 { 2591 assertionID = IOService::getPMRootDomain()->createPMAssertion( 2592 /* type */ kIOPMDriverAssertionReservedBit7, 2593 /* level */ kIOPMDriverAssertionLevelOn, 2594 /* service */ minor->client, 2595 /* description */ "com.apple.iokit.IOStorageFamily" ); 2596 2597 if ( assertionID != kIOPMUndefinedDriverAssertionID ) 2598 { 2599 gIOMediaBSDClientGlobals.setAssertionID(assertionID); 2600 2601 thread_call_enter_delayed( 2602 /* call */ gIOMediaBSDClientGlobals.getAssertionCall(), 2603 /* deadline */ assertionTime ); 2604 } 2605 } 2606 2607 gIOMediaBSDClientGlobals.unlockAssertion(); 2608 } 2609#endif /* !TARGET_OS_EMBEDDED */ 2610///w:stop 2611 if ( DKR_IS_ASYNCHRONOUS(dkr, dkrtype) ) // (an asynchronous request?) 2612 { 2613 IOStorageCompletion completion; 2614 2615 completion.target = dkr; 2616 completion.action = dkreadwritecompletion; 2617 completion.parameter = (void *) dkrtype; 2618 2619 if ( DKR_IS_READ(dkr, dkrtype) ) // (a read?) 2620 { 2621 minor->media->read( /* client */ minor->client, 2622 /* byteStart */ byteStart, 2623 /* buffer */ buffer, 2624 /* attributes */ &attributes, 2625 /* completion */ &completion ); // (go) 2626 } 2627 else // (a write?) 2628 { 2629 minor->media->write( /* client */ minor->client, 2630 /* byteStart */ byteStart, 2631 /* buffer */ buffer, 2632 /* attributes */ &attributes, 2633 /* completion */ &completion ); // (go) 2634 } 2635 2636 status = kIOReturnSuccess; 2637 } 2638 else // (a synchronous request?) 2639 { 2640 if ( DKR_IS_READ(dkr, dkrtype) ) // (a read?) 2641 { 2642 status = minor->media->read( 2643 /* client */ minor->client, 2644 /* byteStart */ byteStart, 2645 /* buffer */ buffer, 2646#ifdef __LP64__ 2647 /* attributes */ &attributes, 2648#endif /* __LP64__ */ 2649 /* actualByteCount */ &byteCount ); // (go) 2650 } 2651 else // (a write?) 2652 { 2653 status = minor->media->write( 2654 /* client */ minor->client, 2655 /* byteStart */ byteStart, 2656 /* buffer */ buffer, 2657#ifdef __LP64__ 2658 /* attributes */ &attributes, 2659#endif /* __LP64__ */ 2660 /* actualByteCount */ &byteCount ); // (go) 2661 } 2662 2663 dkreadwritecompletion(dkr, (void *)dkrtype, status, byteCount); 2664 } 2665 2666 return minor->media->errnoFromReturn(status); // (return error status) 2667 2668dkreadwriteErr: 2669 2670 dkreadwritecompletion(dkr, (void *)dkrtype, status, 0); 2671 2672 return minor->media->errnoFromReturn(status); // (return error status) 2673} 2674 2675void dkreadwritecompletion( void * target, 2676 void * parameter, 2677 IOReturn status, 2678 UInt64 actualByteCount ) 2679{ 2680 // 2681 // dkreadwritecompletion cleans up after a read or write operation. 2682 // 2683 2684 dkr_t dkr = (dkr_t) target; 2685 dkrtype_t dkrtype = (dkrtype_t) (uintptr_t) parameter; 2686 dev_t dev = DKR_GET_DEV(dkr, dkrtype); 2687 void * drvdata = DKR_GET_DRIVER_DATA(dkr, dkrtype); 2688 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2689 2690 if ( drvdata ) // (has a buffer?) 2691 { 2692 IOMemoryDescriptor * buffer = (IOMemoryDescriptor *) drvdata; 2693 2694 buffer->complete(); // (complete the buffer) 2695 buffer->release(); // (release our retain on the buffer) 2696 } 2697 2698 if ( status != kIOReturnSuccess ) // (has an error?) 2699 { 2700 if ( status != kIOReturnNotPermitted ) 2701 { 2702 IOLog("%s: %s.\n", minor->name, minor->media->stringFromReturn(status)); 2703 } 2704 } 2705 2706 if ( DKR_IS_ASYNCHRONOUS(dkr, dkrtype) ) // (an asynchronous request?) 2707 { 2708 DKR_SET_BYTE_COUNT(dkr, dkrtype, actualByteCount); // (set byte count) 2709 DKR_RUN_COMPLETION(dkr, dkrtype, status); // (run completion) 2710 } 2711 else 2712 { 2713 DKR_SET_BYTE_COUNT(dkr, dkrtype, actualByteCount); // (set byte count) 2714 } 2715} 2716///w:start 2717#if !TARGET_OS_EMBEDDED 2718void dkreadwriteassertion(thread_call_param_t param0, thread_call_param_t param1) 2719{ 2720 AbsoluteTime assertionTime; 2721 2722 gIOMediaBSDClientGlobals.lockAssertion(); 2723 2724 assertionTime = gIOMediaBSDClientGlobals.getAssertionTime(); 2725 2726 if ( __OSAbsoluteTime(assertionTime) < mach_absolute_time() ) 2727 { 2728 IOPMDriverAssertionID assertionID; 2729 2730 assertionID = gIOMediaBSDClientGlobals.getAssertionID(); 2731 2732 IOService::getPMRootDomain()->releasePMAssertion(assertionID); 2733 2734 gIOMediaBSDClientGlobals.setAssertionID(kIOPMUndefinedDriverAssertionID); 2735 } 2736 else 2737 { 2738 thread_call_enter_delayed( 2739 /* call */ gIOMediaBSDClientGlobals.getAssertionCall(), 2740 /* deadline */ assertionTime ); 2741 } 2742 2743 gIOMediaBSDClientGlobals.unlockAssertion(); 2744} 2745#endif /* !TARGET_OS_EMBEDDED */ 2746///w:stop 2747 2748// ============================================================================= 2749// AnchorTable Class 2750 2751AnchorTable::AnchorTable() 2752{ 2753 // 2754 // Initialize this object's minimal state. 2755 // 2756 2757 _table = 0; 2758 _tableCount = 0; 2759} 2760 2761AnchorTable::~AnchorTable() 2762{ 2763 // 2764 // Free all of this object's outstanding resources. 2765 // 2766 2767 for ( UInt32 anchorID = 0; anchorID < _tableCount; anchorID++ ) 2768 if ( _table[anchorID].isAssigned ) remove(anchorID); 2769 2770 if ( _table ) IODelete(_table, AnchorSlot, _tableCount); 2771} 2772 2773UInt32 AnchorTable::insert(IOService * anchor, void * key) 2774{ 2775 // 2776 // This method inserts the specified anchor into an unassigned slot in the 2777 // anchor table and returns its ID (or kInvalidAnchorID on a failure). 2778 // 2779 // Note that the anchor is transparently removed from the table should the 2780 // anchor terminate (or it is at least marked obsolete, should references 2781 // to the anchor still exist in the minor table). 2782 // 2783 2784 UInt32 anchorID; 2785 IONotifier * notifier; 2786 2787 // Search for an unassigned slot in the anchor table. 2788 2789 for ( anchorID = 0; anchorID < _tableCount; anchorID++ ) 2790 if ( _table[anchorID].isAssigned == false ) break; 2791 2792 // Was an unassigned slot found? If not, grow the table. 2793 2794 if ( anchorID == _tableCount ) 2795 { 2796 AnchorSlot * newTable; 2797 UInt32 newTableCount; 2798 2799 // We must expand the anchor table since no more slots are available. 2800 2801 if ( _tableCount >= kAnchorsMaxCount ) return kInvalidAnchorID; 2802 2803 newTableCount = min(kAnchorsAddCount + _tableCount, kAnchorsMaxCount); 2804 newTable = IONew(AnchorSlot, newTableCount); 2805 2806 if ( newTable == 0 ) return kInvalidAnchorID; 2807 2808 bzero(newTable, newTableCount * sizeof(AnchorSlot)); 2809 2810 // Copy over the old table's entries, then free the old table. 2811 2812 if ( _table ) 2813 { 2814 bcopy(_table, newTable, _tableCount * sizeof(AnchorSlot)); 2815 IODelete(_table, AnchorSlot, _tableCount); 2816 } 2817 2818 // Obtain the next unassigned index (simple since we know the size of 2819 // the old table), then update our instance variables to reflect the 2820 // new tables. 2821 2822 anchorID = _tableCount; 2823 _table = newTable; 2824 _tableCount = newTableCount; 2825 } 2826 2827 // Create a notification handler for the anchor's termination (post-stop); 2828 // the handler will remove the anchor transparently from the table if the 2829 // anchor terminates (or at least marks it obsolete, if references to the 2830 // anchor still exist in the minor table). 2831 2832 notifier = anchor->registerInterest( 2833 /* type */ gIOGeneralInterest, 2834 /* action */ anchorWasNotified, 2835 /* target */ this, 2836 /* parameter */ 0 ); 2837 2838 if ( notifier == 0 ) return kInvalidAnchorID; 2839 2840 // Zero the new slot, fill it in, and retain the anchor object. 2841 2842 bzero(&_table[anchorID], sizeof(AnchorSlot)); // (zero slot) 2843 2844 _table[anchorID].isAssigned = true; // (fill in slot) 2845 _table[anchorID].isObsolete = false; 2846 _table[anchorID].anchor = anchor; 2847 _table[anchorID].key = key; 2848 _table[anchorID].notifier = notifier; 2849 2850 _table[anchorID].anchor->retain(); // (retain anchor) 2851 2852 return anchorID; 2853} 2854 2855void AnchorTable::remove(UInt32 anchorID) 2856{ 2857 // 2858 // This method removes the specified anchor from the anchor table. 2859 // 2860 2861 assert(anchorID < _tableCount); 2862 assert(_table[anchorID].isAssigned); 2863 2864 // Release the resources retained in the anchor slot and zero it. 2865 2866 _table[anchorID].notifier->remove(); 2867 _table[anchorID].anchor->release(); // (release anchor) 2868 2869 bzero(&_table[anchorID], sizeof(AnchorSlot)); // (zero slot) 2870} 2871 2872void AnchorTable::obsolete(UInt32 anchorID) 2873{ 2874 // 2875 // This method obsoletes the specified anchor, that is, the slot is marked 2876 // as obsolete and will be removed later via the minor table remove method 2877 // once it detects references to the anchor ID drop to 0. Once obsoleted, 2878 // the anchor can be considered to be removed, since it will not appear in 2879 // locate searches, even though behind the scenes it still occupies a slot. 2880 // 2881 2882 assert(anchorID < _tableCount); 2883 assert(_table[anchorID].isAssigned); 2884 2885 // Mark the anchor as obsolete so that it can be removed from the table as 2886 // soon as all its references go away (minor table's responsibility). 2887 2888 _table[anchorID].isObsolete = true; 2889} 2890 2891UInt32 AnchorTable::locate(IOService * anchor) 2892{ 2893 // 2894 // This method searches for the specified anchor in the anchor table and 2895 // returns its ID (or kInvalidAnchorID on a failure). It would find the 2896 // first occurrence of the anchor in case multiple entries with the same 2897 // anchor object exist. It ignores slots marked as obsolete. 2898 // 2899 2900 for (UInt32 anchorID = 0; anchorID < _tableCount; anchorID++) 2901 { 2902 if ( _table[anchorID].isAssigned != false && 2903 _table[anchorID].isObsolete == false && 2904 _table[anchorID].anchor == anchor ) return anchorID; 2905 } 2906 2907 return kInvalidAnchorID; 2908} 2909 2910UInt32 AnchorTable::locate(IOService * anchor, void * key) 2911{ 2912 // 2913 // This method searches for the specified anchor and key pair in the anchor 2914 // table and returns its ID (or kInvalidAnchorID on a failure). It ignores 2915 // slots marked as obsolete. 2916 // 2917 2918 for (UInt32 anchorID = 0; anchorID < _tableCount; anchorID++) 2919 { 2920 if ( _table[anchorID].isAssigned != false && 2921 _table[anchorID].isObsolete == false && 2922 _table[anchorID].anchor == anchor && 2923 _table[anchorID].key == key ) return anchorID; 2924 } 2925 2926 return kInvalidAnchorID; 2927} 2928 2929UInt32 AnchorTable::update(IOService * anchor, void * key) 2930{ 2931 // 2932 // This method searches for the specified anchor in the anchor table and 2933 // updates its key value if no references to it exist in the minor table 2934 // or if the references in the minor table are all obsolete. It returns 2935 // the updated anchor ID (or kInvalidAnchorID on a failure). It ignores 2936 // slots marked as obsolete. 2937 // 2938 2939 MinorTable * minors = gIOMediaBSDClientGlobals.getMinors(); 2940 2941 for (UInt32 anchorID = 0; anchorID < _tableCount; anchorID++) 2942 { 2943 if ( _table[anchorID].isAssigned != false && 2944 _table[anchorID].isObsolete == false && 2945 _table[anchorID].anchor == anchor ) 2946 { 2947 if ( minors->hasReferencesToAnchorID(anchorID, true) == false ) 2948 { 2949 _table[anchorID].key = key; 2950 return anchorID; 2951 } 2952 } 2953 } 2954 2955 return kInvalidAnchorID; 2956} 2957 2958bool AnchorTable::isObsolete(UInt32 anchorID) 2959{ 2960 // 2961 // Determine whether the specified anchor ID is marked as obsolete. 2962 // 2963 2964 assert(anchorID < _tableCount); 2965 assert(_table[anchorID].isAssigned); 2966 2967 return _table[anchorID].isObsolete ? true : false; 2968} 2969 2970IOReturn AnchorTable::anchorWasNotified( void * /* target */, 2971 void * /* parameter */, 2972 UInt32 messageType, 2973 IOService * anchor, 2974 void * /* messageArgument */, 2975 vm_size_t /* messageArgumentSize */ ) 2976{ 2977 // 2978 // Notification handler for anchors. 2979 // 2980 2981 AnchorTable * anchors = gIOMediaBSDClientGlobals.getAnchors(); 2982 UInt32 anchorID; 2983 MinorTable * minors = gIOMediaBSDClientGlobals.getMinors(); 2984 2985 // Determine whether this is a termination notification (post-stop). 2986 2987 if ( messageType != kIOMessageServiceIsTerminated ) 2988 return kIOReturnSuccess; 2989 2990 // Disable access to tables. 2991 2992 gIOMediaBSDClientGlobals.lockState(); 2993 2994 // Determine whether this anchor is in the anchor table (obsolete occurences 2995 // are skipped in the search, as appropriate, since those anchor IDs will be 2996 // removed as it is). 2997 2998 while ( (anchorID = anchors->locate(anchor)) != kInvalidAnchorID ) 2999 { 3000 // Determine whether this anchor still has references from the minor 3001 // table. If it does, we mark the the anchor as obsolete so that it 3002 // will be removed later, once references to it go to zero (which is 3003 // handled by MinorTable::remove). 3004 3005 if ( minors->hasReferencesToAnchorID(anchorID, false) ) 3006 anchors->obsolete(anchorID); 3007 else 3008 anchors->remove(anchorID); 3009 } 3010 3011 // Enable access to tables. 3012 3013 gIOMediaBSDClientGlobals.unlockState(); 3014 3015 return kIOReturnSuccess; 3016} 3017 3018// ============================================================================= 3019// MinorTable Class 3020 3021MinorTable::MinorTable() 3022{ 3023 // 3024 // Initialize this object's minimal state. 3025 // 3026 3027 _table.buckets = IONew(MinorSlot *, kMinorsBucketCount); 3028 _tableCount = 0; 3029 3030 if ( _table.buckets ) 3031 bzero(_table.buckets, kMinorsBucketCount * sizeof(MinorSlot *)); 3032} 3033 3034MinorTable::~MinorTable() 3035{ 3036 // 3037 // Free all of this object's outstanding resources. 3038 // 3039 3040 for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ ) 3041 if ( _table[minorID].isAssigned ) remove(minorID); 3042 3043 if ( _table.buckets ) 3044 { 3045 for ( UInt32 bucketID = 0; _table.buckets[bucketID]; bucketID++ ) 3046 IODelete(_table.buckets[bucketID], MinorSlot, kMinorsAddCount); 3047 3048 IODelete(_table.buckets, MinorSlot *, kMinorsBucketCount); 3049 } 3050} 3051 3052UInt32 MinorTable::insert( IOMedia * media, 3053 UInt32 anchorID, 3054 IOMediaBSDClient * client, 3055 char * slicePath ) 3056{ 3057 // 3058 // This method inserts the specified media/anchorID pair into an unassigned 3059 // slot in the minor table and returns its ID (or kInvalidMinorID on error). 3060 // 3061 // Note that the bdev and cdev nodes are published as a result of this call, 3062 // with the name "[r]disk<anchorID><slicePath>". For instance, "disk2s3s1" 3063 // for an anchorID of 2 and slicePath of "s3s1". 3064 // 3065 3066 void * bdevNode; 3067 void * cdevNode; 3068 UInt32 majorID = gIOMediaBSDClientGlobals.getMajorID(); 3069 UInt32 minorID; 3070 char * minorName; 3071 UInt32 minorNameSize; 3072 3073 if ( _table.buckets == 0 ) return kInvalidMinorID; 3074 3075 // Search for an unassigned slot in the minor table. 3076 3077 for ( minorID = 0; minorID < _tableCount; minorID++ ) 3078 if ( _table[minorID].isAssigned == false ) break; 3079 3080 // Was an unassigned slot found? If not, grow the table. 3081 3082 if ( minorID == _tableCount ) 3083 { 3084 UInt32 bucketID = _tableCount / kMinorsAddCount; 3085 3086 // We must expand the minor table since no more slots are available. 3087 3088 if ( bucketID >= kMinorsBucketCount ) return kInvalidMinorID; 3089 3090 _table.buckets[bucketID] = IONew(MinorSlot, kMinorsAddCount); 3091 3092 if ( _table.buckets[bucketID] == 0 ) return kInvalidMinorID; 3093 3094 bzero(_table.buckets[bucketID], kMinorsAddCount * sizeof(MinorSlot)); 3095 3096 _tableCount += kMinorsAddCount; 3097 } 3098 3099 // Create a buffer large enough to hold the full name of the minor. 3100 3101 minorNameSize = strlen("disk#"); 3102 for (unsigned temp = anchorID; temp >= 10; temp /= 10) minorNameSize++; 3103 minorNameSize += strlen(slicePath); 3104 minorNameSize += 1; 3105 minorName = IONew(char, minorNameSize); 3106 3107 // Create a block and character device node in BSD for this media. 3108 3109 bdevNode = devfs_make_node( /* dev */ makedev(majorID, minorID), 3110 /* type */ DEVFS_BLOCK, 3111 /* owner */ UID_ROOT, 3112 /* group */ GID_OPERATOR, 3113 /* permission */ 0640, 3114 /* name (fmt) */ "disk%d%s", 3115 /* name (arg) */ anchorID, 3116 /* name (arg) */ slicePath ); 3117 3118 cdevNode = devfs_make_node( /* dev */ makedev(majorID, minorID), 3119 /* type */ DEVFS_CHAR, 3120 /* owner */ UID_ROOT, 3121 /* group */ GID_OPERATOR, 3122 /* permission */ 0640, 3123 /* name (fmt) */ "rdisk%d%s", 3124 /* name (arg) */ anchorID, 3125 /* name (arg) */ slicePath ); 3126 3127 if ( minorName == 0 || bdevNode == 0 || cdevNode == 0 ) 3128 { 3129 if ( cdevNode ) devfs_remove(cdevNode); 3130 if ( bdevNode ) devfs_remove(bdevNode); 3131 if ( minorName ) IODelete(minorName, char, minorNameSize); 3132 3133 return kInvalidMinorID; 3134 } 3135 3136 // Construct a name for the node. 3137 3138 snprintf(minorName, minorNameSize, "disk%d%s", (int) anchorID, slicePath); 3139 assert(strlen(minorName) + 1 == minorNameSize); 3140 3141 // Zero the new slot, fill it in, and retain the appropriate objects. 3142 3143 bzero(&_table[minorID], sizeof(MinorSlot)); // (zero slot) 3144 3145 _table[minorID].isAssigned = true; // (fill in slot) 3146 _table[minorID].isObsolete = false; 3147 _table[minorID].isOrphaned = false; 3148 _table[minorID].anchorID = anchorID; 3149 _table[minorID].client = client; 3150 _table[minorID].media = media; 3151 _table[minorID].name = minorName; 3152 _table[minorID].bdevBlockSize = media->getPreferredBlockSize(); 3153 _table[minorID].bdevNode = bdevNode; 3154 _table[minorID].bdevOpen = 0; 3155 _table[minorID].bdevOpenLevel = kIOStorageAccessNone; 3156 _table[minorID].cdevNode = cdevNode; 3157 _table[minorID].cdevOpen = 0; 3158 _table[minorID].cdevOpenLevel = kIOStorageAccessNone; 3159#if TARGET_OS_EMBEDDED 3160 _table[minorID].cdevOptions = 0; 3161#endif /* TARGET_OS_EMBEDDED */ 3162 3163 _table[minorID].client->retain(); // (retain client) 3164 _table[minorID].media->retain(); // (retain media) 3165 3166 return minorID; 3167} 3168 3169void MinorTable::remove(UInt32 minorID) 3170{ 3171 // 3172 // This method removes the specified minor from the minor table. 3173 // 3174 3175 UInt32 anchorID; 3176 3177 assert(minorID < _tableCount); 3178 assert(_table[minorID].isAssigned); 3179 3180 assert(_table[minorID].isOrphaned == false); 3181 assert(_table[minorID].bdevOpen == 0); 3182 assert(_table[minorID].cdevOpen == 0); 3183 3184 anchorID = _table[minorID].anchorID; 3185 3186 // Release the resources retained in the minor slot and zero it. 3187 3188 devfs_remove(_table[minorID].cdevNode); 3189 devfs_remove(_table[minorID].bdevNode); 3190 IODelete(_table[minorID].name, char, strlen(_table[minorID].name) + 1); 3191 _table[minorID].client->release(); // (release client) 3192 _table[minorID].media->release(); // (release media) 3193 3194 bzero(&_table[minorID], sizeof(MinorSlot)); // (zero slot) 3195 3196 // Determine whether the associated anchor ID is marked as obsolete. If it 3197 // is and there are no other references to the anchor ID in the minor table, 3198 // we remove the anchor ID from the anchor table. 3199 3200 if ( gIOMediaBSDClientGlobals.getAnchors()->isObsolete(anchorID) ) 3201 { 3202 if ( hasReferencesToAnchorID(anchorID, false) == false ) 3203 gIOMediaBSDClientGlobals.getAnchors()->remove(anchorID); 3204 } 3205} 3206 3207UInt32 MinorTable::update( IOMedia * media, 3208 UInt32 anchorID, 3209 IOMediaBSDClient * client, 3210 char * slicePath ) 3211{ 3212 // 3213 // This method searches for the specified anchor ID and slice path pair in 3214 // the minor table and updates it. An update would be an unusual occasion 3215 // as new anchors are assigned when two media trees are found to share the 3216 // same anchor. It would occur in one specific circumstance: on the minor 3217 // slot through which a DKIOCFORMAT was issued. The minor slot would have 3218 // been marked in "open flux", the format would have been issued, then the 3219 // media objects terminated, the minor slot marked obsolete, and the media 3220 // objects republished. The anchor ID would have one reference, the minor 3221 // slot with the DKIOCFORMAT still outstanding. AnchorTable::update would 3222 // notice the one reference is orphaned and accept the reuse of the anchor 3223 // ID. MinorTable::update would notice the orphaned minor slot and update 3224 // it with the new media object and media bsd client object, and clear its 3225 // obsolete state and "open flux" state, once the new media object arrives. 3226 // 3227 3228 UInt32 minorID; 3229 char * minorName; 3230 UInt32 minorNameSize; 3231 3232 // Create a buffer large enough to hold the full name of the minor. 3233 3234 minorNameSize = strlen("disk#"); 3235 for (unsigned temp = anchorID; temp >= 10; temp /= 10) minorNameSize++; 3236 minorNameSize += strlen(slicePath); 3237 minorNameSize += 1; 3238 minorName = IONew(char, minorNameSize); 3239 3240 if ( minorName == 0 ) return kInvalidMinorID; 3241 3242 // Construct a name for the node. 3243 3244 snprintf(minorName, minorNameSize, "disk%d%s", (int) anchorID, slicePath); 3245 assert(strlen(minorName) + 1 == minorNameSize); 3246 3247 // Search for an orphaned slot in the minor table with our minor name. 3248 3249 for ( minorID = 0; minorID < _tableCount; minorID++ ) 3250 { 3251 if ( _table[minorID].isAssigned != false && 3252 _table[minorID].isObsolete != false && 3253 _table[minorID].isOrphaned != false && 3254 _table[minorID].anchorID == anchorID && 3255 strcmp(_table[minorID].name, minorName) == 0 ) break; 3256 } 3257 3258 IODelete(minorName, char, minorNameSize); 3259 3260 if ( minorID == _tableCount ) return kInvalidMinorID; 3261 3262 // Update the slot and retain the appropriate objects. 3263 3264 _table[minorID].client->release(); // (release client) 3265 _table[minorID].media->release(); // (release media) 3266 3267 _table[minorID].isObsolete = false; // (update slot) 3268 _table[minorID].isOrphaned = false; 3269 _table[minorID].client = client; 3270 _table[minorID].media = media; 3271 3272 _table[minorID].client->retain(); // (retain client) 3273 _table[minorID].media->retain(); // (retain media) 3274 3275 return minorID; 3276} 3277 3278UInt32 MinorTable::locate(IOMedia * media) 3279{ 3280 // 3281 // This method searches for the specified media in the minor table and 3282 // returns its ID (or kInvalidMinorID on an error). It ignores slots 3283 // marked as obsolete. 3284 // 3285 3286 for (UInt32 minorID = 0; minorID < _tableCount; minorID++) 3287 { 3288 if ( _table[minorID].isAssigned != false && 3289 _table[minorID].isObsolete == false && 3290 _table[minorID].media == media ) return minorID; 3291 } 3292 3293 return kInvalidMinorID; 3294} 3295 3296UInt32 MinorTable::getOpenCountForAnchorID(UInt32 anchorID) 3297{ 3298 // 3299 // This method obtains a count of opens on the minors associated with the 3300 // specified anchor ID. A block device open is counted separately from a 3301 // character device open. 3302 // 3303 3304 UInt32 opens = 0; 3305 3306 for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ ) 3307 { 3308 if ( _table[minorID].isAssigned != false && 3309 _table[minorID].anchorID == anchorID ) 3310 { 3311 opens += _table[minorID].bdevOpen; 3312 opens += _table[minorID].cdevOpen; 3313 } 3314 } 3315 3316 return opens; 3317} 3318 3319bool MinorTable::hasReferencesToAnchorID(UInt32 anchorID, bool excludeOrphans) 3320{ 3321 // 3322 // This method determines whether there are assigned minors in the minor 3323 // table that refer to the specified anchor ID. It ignores slots marked 3324 // as obsolete and orphaned, unless excludeOrphans is false. 3325 // 3326 3327 for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ ) 3328 { 3329 if ( _table[minorID].isAssigned != false && 3330 _table[minorID].anchorID == anchorID ) 3331 { 3332 if ( excludeOrphans == false ) return true; 3333 if ( _table[minorID].isObsolete == false ) return true; 3334 if ( _table[minorID].isOrphaned == false ) return true; 3335 } 3336 } 3337 3338 return false; 3339} 3340 3341MinorSlot * MinorTable::getMinor(UInt32 minorID) 3342{ 3343 // 3344 // Obtain the structure describing the specified minor. 3345 // 3346 3347 if ( minorID < _tableCount && _table[minorID].isAssigned ) 3348 return &_table[minorID]; 3349 else 3350 return 0; 3351} 3352 3353void MinorTable::obsolete(UInt32 minorID) 3354{ 3355 // 3356 // This method obsoletes the specified minor, that is, the slot is marked 3357 // as obsolete and will be removed later via the dkclose function once it 3358 // detects the last close arrive. Once obsoleted, the minor can be cons- 3359 // idered to be removed, since it will not appear in locate searches. 3360 // 3361 3362 assert(minorID < _tableCount); 3363 assert(_table[minorID].isAssigned); 3364 3365 // Mark the minor as obsolete so that it can be removed from the table as 3366 // soon as the last close arrives (dkclose function's responsibility). 3367 3368 _table[minorID].isObsolete = true; 3369} 3370 3371bool MinorTable::isObsolete(UInt32 minorID) 3372{ 3373 // 3374 // Determine whether the specified minor ID is marked as obsolete. 3375 // 3376 3377 assert(minorID < _tableCount); 3378 assert(_table[minorID].isAssigned); 3379 3380 return _table[minorID].isObsolete ? true : false; 3381} 3382 3383// ============================================================================= 3384// IOMediaBSDClientGlobals Class 3385 3386static int devsw_add(int index, struct bdevsw * bsw, struct cdevsw * csw) 3387{ 3388 for ( index = bdevsw_isfree(index); index != -1; index++, index = bdevsw_isfree(-index) ) 3389 { 3390 int bdevsw_index; 3391 3392 bdevsw_index = bdevsw_add(index, bsw); 3393 3394 if (bdevsw_index == index) 3395 { 3396 int cdevsw_index; 3397 3398 cdevsw_index = cdevsw_add_with_bdev(index, csw, index); 3399 3400 if (cdevsw_index == index) 3401 { 3402 break; 3403 } 3404 3405 bdevsw_remove(bdevsw_index, bsw); 3406 } 3407 } 3408 3409 return index; 3410} 3411 3412static int devsw_remove(int index, struct bdevsw * bsw, struct cdevsw * csw) 3413{ 3414 index = bdevsw_remove(index, bsw); 3415 3416 if (index != -1) 3417 { 3418 index = cdevsw_remove(index, csw); 3419 } 3420 3421 return index; 3422} 3423 3424IOMediaBSDClientGlobals::IOMediaBSDClientGlobals() 3425{ 3426 // 3427 // Initialize the minimal global state. 3428 // 3429 3430 _anchors = new AnchorTable(); 3431 _minors = new MinorTable(); 3432 3433 _majorID = devsw_add(-1, &bdevswFunctions, &cdevswFunctions); 3434 3435 _openLock = IOLockAlloc(); 3436 _stateLock = IOLockAlloc(); 3437///w:start 3438#if !TARGET_OS_EMBEDDED 3439 _assertionCall = thread_call_allocate(dkreadwriteassertion, NULL); 3440 _assertionID = kIOPMUndefinedDriverAssertionID; 3441 _assertionLock = IOLockAlloc(); 3442#endif /* !TARGET_OS_EMBEDDED */ 3443///w:stop 3444} 3445 3446IOMediaBSDClientGlobals::~IOMediaBSDClientGlobals() 3447{ 3448 // 3449 // Free all of the outstanding global resources. 3450 // 3451 3452///w:start 3453#if !TARGET_OS_EMBEDDED 3454 if ( _assertionCall ) thread_call_free(_assertionCall); 3455 if ( _assertionLock ) IOLockFree(_assertionLock); 3456#endif /* !TARGET_OS_EMBEDDED */ 3457///w:stop 3458 if ( _openLock ) IOLockFree(_openLock); 3459 if ( _stateLock ) IOLockFree(_stateLock); 3460 3461 if ( _majorID != kInvalidMajorID ) devsw_remove(_majorID, &bdevswFunctions, &cdevswFunctions); 3462 3463 if ( _minors ) delete _minors; 3464 if ( _anchors ) delete _anchors; 3465} 3466 3467AnchorTable * IOMediaBSDClientGlobals::getAnchors() 3468{ 3469 // 3470 // Obtain the table of anchors. 3471 // 3472 3473 return _anchors; 3474} 3475 3476MinorTable * IOMediaBSDClientGlobals::getMinors() 3477{ 3478 // 3479 // Obtain the table of minors. 3480 // 3481 3482 return _minors; 3483} 3484 3485MinorSlot * IOMediaBSDClientGlobals::getMinor(UInt32 minorID) 3486{ 3487 // 3488 // Obtain information for the specified minor ID. 3489 // 3490 3491 return _minors->getMinor(minorID); 3492} 3493 3494UInt32 IOMediaBSDClientGlobals::getMajorID() 3495{ 3496 // 3497 // Obtain the major ID. 3498 // 3499 3500 return _majorID; 3501} 3502 3503bool IOMediaBSDClientGlobals::isValid() 3504{ 3505 // 3506 // Determine whether the minimal global state has been initialized. 3507 // 3508 3509 return ( _anchors ) && 3510 ( _minors ) && 3511 ( _majorID != kInvalidMajorID ) && 3512///w:start 3513#if !TARGET_OS_EMBEDDED 3514 ( _assertionCall ) && 3515 ( _assertionLock ) && 3516#endif /* !TARGET_OS_EMBEDDED */ 3517///w:stop 3518 ( _openLock ) && 3519 ( _stateLock ); 3520} 3521 3522void IOMediaBSDClientGlobals::lockOpen() 3523{ 3524 // 3525 // Disable access to the opens and closes. 3526 // 3527 3528 IOLockLock(_openLock); 3529} 3530 3531void IOMediaBSDClientGlobals::unlockOpen() 3532{ 3533 // 3534 // Enable access to the opens and closes. 3535 // 3536 3537 IOLockUnlock(_openLock); 3538} 3539 3540void IOMediaBSDClientGlobals::lockState() 3541{ 3542 // 3543 // Disable access to the global state. 3544 // 3545 3546 IOLockLock(_stateLock); 3547} 3548 3549void IOMediaBSDClientGlobals::unlockState() 3550{ 3551 // 3552 // Enable access to the global state. 3553 // 3554 3555 IOLockUnlock(_stateLock); 3556} 3557///w:start 3558#if !TARGET_OS_EMBEDDED 3559thread_call_t IOMediaBSDClientGlobals::getAssertionCall() 3560{ 3561 return _assertionCall; 3562} 3563 3564IOPMDriverAssertionID IOMediaBSDClientGlobals::getAssertionID() 3565{ 3566 return _assertionID; 3567} 3568 3569void IOMediaBSDClientGlobals::setAssertionID(IOPMDriverAssertionID assertionID) 3570{ 3571 _assertionID = assertionID; 3572} 3573 3574AbsoluteTime IOMediaBSDClientGlobals::getAssertionTime() 3575{ 3576 return _assertionTime; 3577} 3578 3579void IOMediaBSDClientGlobals::setAssertionTime(AbsoluteTime assertionTime) 3580{ 3581 _assertionTime = assertionTime; 3582} 3583 3584void IOMediaBSDClientGlobals::lockAssertion() 3585{ 3586 IOLockLock(_assertionLock); 3587} 3588 3589void IOMediaBSDClientGlobals::unlockAssertion() 3590{ 3591 IOLockUnlock(_assertionLock); 3592} 3593#endif /* !TARGET_OS_EMBEDDED */ 3594///w:stop 3595