1/* 2 * Copyright (c) 1998-2014 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 uint32_t options; 699 700 uint8_t reserved0096[4]; 701} dk_unmap_32_t; 702 703typedef struct 704{ 705 user64_addr_t extents; 706 uint32_t extentsCount; 707 708 uint32_t options; 709} dk_unmap_64_t; 710 711typedef struct 712{ 713 user32_addr_t extents; 714 uint32_t extentsCount; 715 716 uint8_t tier; 717 718 uint8_t reserved0072[7]; 719} dk_set_tier_32_t; 720 721typedef struct 722{ 723 user64_addr_t extents; 724 uint32_t extentsCount; 725 726 uint8_t tier; 727 728 uint8_t reserved0104[3]; 729} dk_set_tier_64_t; 730 731static IOStorageAccess DK_ADD_ACCESS(IOStorageAccess a1, IOStorageAccess a2) 732{ 733 static UInt8 table[4][4] = 734 { /* Rea, Wri, R|S, W|S */ 735 /* Rea */ { 000, 001, 002, 003 }, 736 /* Wri */ { 001, 001, 001, 001 }, 737 /* R|S */ { 002, 001, 002, 003 }, 738 /* W|S */ { 003, 001, 003, 003 } 739 }; 740 741 if ( a1 == kIOStorageAccessNone ) return a2; 742 if ( a2 == kIOStorageAccessNone ) return a1; 743 744 a1 = (a1 - 1) >> 1; 745 a2 = (a2 - 1) >> 1; 746 747 if ( a1 > 003 ) return kIOStorageAccessNone; 748 if ( a2 > 003 ) return kIOStorageAccessNone; 749 750 return (table[a1][a2] << 1) + 1; 751} 752 753static bool DKIOC_IS_RESERVED(caddr_t data, uint32_t reserved) 754{ 755 UInt32 index; 756 757 for ( index = 0; index < sizeof(reserved) * 8; index++, reserved >>= 1 ) 758 { 759 if ( (reserved & 1) ) 760 { 761 if ( data[index] ) return true; 762 } 763 } 764 765 return false; 766} 767 768UInt64 _IOMediaBSDClientGetThrottleMask(IOMedia * media) 769{ 770 UInt64 mask; 771 772 mask = 0; 773 774 if ( media ) 775 { 776 int error; 777 778 error = EAGAIN; 779 780 while ( error ) 781 { 782 // Iterate through IOBlockStorageDevice objects. 783 784 IORegistryIterator * devices; 785 786 error = 0; 787 788 mask = 0; 789 790 devices = IORegistryIterator::iterateOver( media, gIOServicePlane, kIORegistryIterateParents ); 791 792 if ( devices ) 793 { 794 IORegistryEntry * device; 795 796 device = devices->getNextObjectRecursive( ); 797 798 while ( device ) 799 { 800 if ( OSDynamicCast( IOBlockStorageDevice, device ) ) 801 { 802 // Iterate through IOMedia objects. 803 804 IORegistryIterator * services; 805 806 services = IORegistryIterator::iterateOver( device, gIOServicePlane ); 807 808 if ( services ) 809 { 810 IORegistryEntry * service; 811 812 service = services->getNextObjectRecursive( ); 813 814 while ( service ) 815 { 816 if ( OSDynamicCast( IOMedia, service ) ) 817 { 818 // Obtain the BSD Unit property. 819 820 OSNumber * unit; 821 822 unit = OSDynamicCast( OSNumber, service->getProperty( kIOBSDUnitKey ) ); 823 824 if ( unit ) 825 { 826 mask |= 1 << ( unit->unsigned32BitValue( ) % 64 ); 827 } 828 } 829 830 service = services->getNextObjectRecursive( ); 831 } 832 833 if ( services->isValid( ) == false ) 834 { 835 error = EAGAIN; 836 } 837 838 services->release( ); 839 } 840 841///w:start 842 OSNumber * number; 843 844 number = OSDynamicCast( OSNumber, device->getProperty( "throttle-unit" ) ); 845 846 if ( number ) 847 { 848 OSDictionary * dictionary; 849 850 dictionary = IOService::serviceMatching( kIOMediaClass ); 851 852 if ( dictionary ) 853 { 854 OSIterator * iterator; 855 856 dictionary->setObject( kIOBSDUnitKey, number ); 857 858 iterator = IOService::getMatchingServices( dictionary ); 859 860 if ( iterator ) 861 { 862 OSObject * object; 863 864 object = iterator->getNextObject( ); 865 866 if ( object ) 867 { 868 mask |= _IOMediaBSDClientGetThrottleMask( ( IOMedia * ) object ); 869 } 870 871 iterator->release( ); 872 } 873 874 dictionary->release( ); 875 } 876 } 877///w:stop 878 devices->exitEntry( ); 879 } 880 881 device = devices->getNextObjectRecursive( ); 882 } 883 884 if ( devices->isValid( ) == false ) 885 { 886 error = EAGAIN; 887 } 888 889 devices->release( ); 890 } 891 } 892 } 893 894 return mask; 895} 896 897int dkopen(dev_t dev, int flags, int devtype, proc_t /* proc */) 898{ 899 // 900 // dkopen opens the device (called on each open). 901 // 902 903 IOStorageAccess access; 904 int error; 905 IOStorageAccess level; 906 IOStorageAccess levelOut; 907 IOMedia * media; 908 MinorSlot * minor; 909 910 assert(S_ISBLK(devtype) || S_ISCHR(devtype)); 911 912 gIOMediaBSDClientGlobals.lockOpen(); // (disable access to opens, closes) 913 gIOMediaBSDClientGlobals.lockState(); // (disable access to state, tables) 914 915 access = kIOStorageAccessReader; 916 access |= (flags & FWRITE) ? kIOStorageAccessReaderWriter : 0; 917 access |= (flags & O_SHLOCK) ? kIOStorageAccessSharedLock : 0; 918 access |= (flags & O_EXLOCK) ? kIOStorageAccessExclusiveLock : 0; 919 920 error = 0; 921 media = 0; 922 minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 923 924 // 925 // Process the open. 926 // 927 928 if ( minor == 0 ) // (is minor valid?) 929 { 930 error = ENXIO; 931 } 932 else if ( minor->isOrphaned ) // (is minor in flux?) 933 { 934 error = EBUSY; 935 } 936 else 937 { 938///w:start 939#ifdef __LP64__ 940 static int root = 0; 941 942 if ( root == 0 ) 943 { 944 root = 1; 945 946 if ( minor->media->isWritable() ) 947 { 948 access |= kIOStorageAccessReaderWriter; 949 } 950 } 951#endif /* __LP64__ */ 952///w:stop 953 level = DK_ADD_ACCESS(minor->bdevOpenLevel, minor->cdevOpenLevel); 954 levelOut = DK_ADD_ACCESS(level, access); 955 956 if ( levelOut == kIOStorageAccessNone ) // (is access valid?) 957 { 958 error = EBUSY; 959 } 960 else if ( (flags & FWRITE) ) // (is client a writer?) 961 { 962 if ( minor->media->isWritable() == false ) 963 { 964 error = EACCES; 965 } 966 } 967 } 968 969 if ( error == 0 ) // (go?) 970 { 971 IOStorageAccess wasOpenLevel; 972 973 if ( S_ISBLK(devtype) ) // (update state) 974 { 975 minor->bdevOpen++; 976 wasOpenLevel = minor->bdevOpenLevel; 977 minor->bdevOpenLevel = DK_ADD_ACCESS(wasOpenLevel, access); 978 } 979 else 980 { 981 minor->cdevOpen++; 982 wasOpenLevel = minor->cdevOpenLevel; 983 minor->cdevOpenLevel = DK_ADD_ACCESS(wasOpenLevel, access); 984 } 985 986 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 987 988 if ( level != levelOut ) // (issue open/upgrade?) 989 { 990 bool success; 991 992 media = minor->media; 993 minor->media->retain(); 994 995 success = minor->media->open(minor->client, 0, levelOut); // (go) 996 997 if ( success == false ) 998 { 999 gIOMediaBSDClientGlobals.lockState(); // (disable access) 1000 1001 if ( S_ISBLK(devtype) ) // (undo state) 1002 { 1003 minor->bdevOpen--; 1004 minor->bdevOpenLevel = wasOpenLevel; 1005 } 1006 else 1007 { 1008 minor->cdevOpen--; 1009 minor->cdevOpenLevel = wasOpenLevel; 1010 } 1011 1012 assert(minor->isOrphaned == false); 1013 1014 if ( !minor->bdevOpen && !minor->cdevOpen && minor->isObsolete ) 1015 { 1016 gIOMediaBSDClientGlobals.getMinors()->remove(getminor(dev)); 1017 } 1018 1019 gIOMediaBSDClientGlobals.unlockState(); // (enable access) 1020 1021 error = EBUSY; 1022 } 1023 } 1024 } 1025 else 1026 { 1027 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1028 } 1029 1030 gIOMediaBSDClientGlobals.unlockOpen(); // (enable access to opens, closes) 1031 1032 // 1033 // Wait until I/O Kit has finished to attempt to match storage drivers 1034 // or terminate storage drivers, should the media object have been re- 1035 // registered or its storage driver been terminated as a result of the 1036 // open. 1037 // 1038 1039 if ( media ) 1040 { 1041 media->waitQuiet(); 1042 media->release(); 1043 } 1044 1045 return error; 1046} 1047 1048int dkclose(dev_t dev, int /* flags */, int devtype, proc_t /* proc */) 1049{ 1050 // 1051 // dkclose closes the device (called on last close). 1052 // 1053 1054 IOStorageAccess level; 1055 IOStorageAccess levelOut; 1056 IOMedia * media; 1057 MinorSlot * minor; 1058 1059 assert(S_ISBLK(devtype) || S_ISCHR(devtype)); 1060 1061 gIOMediaBSDClientGlobals.lockOpen(); // (disable access to opens, closes) 1062 gIOMediaBSDClientGlobals.lockState(); // (disable access to state, tables) 1063 1064 media = 0; 1065 minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 1066 1067 level = DK_ADD_ACCESS(minor->bdevOpenLevel, minor->cdevOpenLevel); 1068 1069 if ( S_ISBLK(devtype) ) // (update state) 1070 { 1071 minor->bdevBlockSize = minor->media->getPreferredBlockSize(); 1072 minor->bdevOpen = 0; 1073 minor->bdevOpenLevel = kIOStorageAccessNone; 1074 } 1075 else 1076 { 1077 minor->cdevOpen = 0; 1078 minor->cdevOpenLevel = kIOStorageAccessNone; 1079#if TARGET_OS_EMBEDDED 1080 minor->cdevOptions = 0; 1081#endif /* TARGET_OS_EMBEDDED */ 1082 } 1083 1084 levelOut = DK_ADD_ACCESS(minor->bdevOpenLevel, minor->cdevOpenLevel); 1085 1086 if ( minor->isOrphaned ) // (is minor in flux?) 1087 { 1088 // 1089 // We have determined that the specified minor is in "open flux". This 1090 // means we are in a state where the media object has been closed, only 1091 // the device node is still open. This happens to the minor subsequent 1092 // to a DKIOCEJECT ioctl -- this close resets the flux state to normal. 1093 // 1094 1095 minor->isOrphaned = false; 1096 1097 // If this minor is marked as obsolete, then we've already received the 1098 // media's termination notification, but the minor is yet to be removed 1099 // from the table -- remove it now. 1100 1101 assert(minor->bdevOpen == 0); 1102 assert(minor->cdevOpen == 0); 1103 1104 if ( minor->isObsolete ) 1105 { 1106 gIOMediaBSDClientGlobals.getMinors()->remove(getminor(dev)); 1107 } 1108 1109 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1110 } 1111 else if ( !minor->bdevOpen && !minor->cdevOpen ) 1112 { 1113 // 1114 // We communicate the close down to the media object once all opens are 1115 // gone, on both the block and character device nodes. 1116 // 1117 1118 IOMediaBSDClient * client; 1119 1120 client = minor->client; 1121 minor->client->retain(); 1122 1123 media = minor->media; 1124 minor->media->retain(); 1125 1126 // If this minor is marked as obsolete, then we've already received the 1127 // media's termination notification, but the minor is yet to be removed 1128 // from the table -- remove it now. 1129 1130 if ( minor->isObsolete ) 1131 { 1132 gIOMediaBSDClientGlobals.getMinors()->remove(getminor(dev)); 1133 } 1134 1135 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1136 1137 media->close(client); // (go) 1138 1139 client->release(); 1140 } 1141 else if ( level != levelOut ) 1142 { 1143 // 1144 // We communicate the downgrade down to the media object. 1145 // 1146 1147 media = minor->media; 1148 minor->media->retain(); 1149 1150 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1151 1152 minor->media->open(minor->client, 0, levelOut); // (go) 1153 } 1154 else 1155 { 1156 gIOMediaBSDClientGlobals.unlockState(); // (enable access to tables) 1157 } 1158 1159 gIOMediaBSDClientGlobals.unlockOpen(); // (enable access to opens, closes) 1160 1161 // 1162 // Wait until I/O Kit has finished to attempt to match storage drivers, 1163 // should the media object have been re-registered as a result of this 1164 // close. 1165 // 1166 1167 if ( media ) 1168 { 1169 media->waitQuiet(); 1170 media->release(); 1171 } 1172 1173 return 0; 1174} 1175 1176int dkread(dev_t dev, uio_t uio, int /* flags */) 1177{ 1178 // 1179 // dkread reads data from a device. 1180 // 1181 1182 struct dio dio = { dev, uio }; 1183 1184 return dkreadwrite(&dio, DKRTYPE_DIO); 1185} 1186 1187int dkwrite(dev_t dev, uio_t uio, int /* flags */) 1188{ 1189 // 1190 // dkwrite writes data to a device. 1191 // 1192 1193 struct dio dio = { dev, uio }; 1194 1195 return dkreadwrite(&dio, DKRTYPE_DIO); 1196} 1197 1198void dkstrategy(buf_t bp) 1199{ 1200 // 1201 // dkstrategy starts an asynchronous read or write operation. It returns 1202 // to the caller as soon as the operation is queued, and completes it via 1203 // the buf_biodone function. 1204 // 1205 1206 dkreadwrite(bp, DKRTYPE_BUF); 1207} 1208 1209int dkioctl(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc) 1210{ 1211 // 1212 // dkioctl performs operations other than a read or write. 1213 // 1214 1215 int error = 0; 1216 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 1217 1218 if ( minor->isOrphaned ) return EBADF; // (is minor in flux?) 1219 1220 // 1221 // Process the ioctl. 1222 // 1223 1224 switch ( cmd ) 1225 { 1226 case DKIOCGETBLOCKSIZE: // (uint32_t *) 1227 { 1228 // 1229 // This ioctl returns the preferred block size of the media object. 1230 // 1231 1232 *(uint32_t *)data = minor->media->getPreferredBlockSize(); 1233 1234 } break; 1235 1236#ifndef __LP64__ 1237 case DKIOCGETBLOCKCOUNT32: // (uint32_t *) 1238 { 1239 // 1240 // This ioctl returns the size of the media object in blocks. The 1241 // implied block size is returned by DKIOCGETBLOCKSIZE. 1242 // 1243 1244 if ( minor->media->getPreferredBlockSize() ) 1245 *(uint32_t *)data = ( minor->media->getSize() / 1246 minor->media->getPreferredBlockSize() ); 1247 else 1248 *(uint32_t *)data = 0; 1249 1250 } break; 1251#endif /* !__LP64__ */ 1252 1253 case DKIOCGETBLOCKCOUNT: // (uint64_t *) 1254 { 1255 // 1256 // This ioctl returns the size of the media object in blocks. The 1257 // implied block size is returned by DKIOCGETBLOCKSIZE. 1258 // 1259 1260 if ( minor->media->getPreferredBlockSize() ) 1261 *(uint64_t *)data = ( minor->media->getSize() / 1262 minor->media->getPreferredBlockSize() ); 1263 else 1264 *(uint64_t *)data = 0; 1265 1266 } break; 1267 1268 case DKIOCGETMAXBLOCKCOUNTREAD: // (uint64_t *) 1269 { 1270 // 1271 // This ioctl returns the maximum block count for reads. 1272 // 1273 1274 OSNumber * number = OSDynamicCast( 1275 /* class */ OSNumber, 1276 /* object */ minor->media->getProperty( 1277 /* key */ kIOMaximumBlockCountReadKey, 1278 /* plane */ gIOServicePlane ) ); 1279 if ( number ) 1280 *(uint64_t *)data = number->unsigned64BitValue(); 1281 else 1282 *(uint64_t *)data = 0; 1283 1284 } break; 1285 1286 case DKIOCGETMAXBLOCKCOUNTWRITE: // (uint64_t *) 1287 { 1288 // 1289 // This ioctl returns the maximum block count for writes. 1290 // 1291 1292 OSNumber * number = OSDynamicCast( 1293 /* class */ OSNumber, 1294 /* object */ minor->media->getProperty( 1295 /* key */ kIOMaximumBlockCountWriteKey, 1296 /* plane */ gIOServicePlane ) ); 1297 if ( number ) 1298 *(uint64_t *)data = number->unsigned64BitValue(); 1299 else 1300 *(uint64_t *)data = 0; 1301 1302 } break; 1303 1304 case DKIOCGETMAXBYTECOUNTREAD: // (uint64_t *) 1305 { 1306 // 1307 // This ioctl returns the maximum byte count for reads. 1308 // 1309 1310 OSNumber * number = OSDynamicCast( 1311 /* class */ OSNumber, 1312 /* object */ minor->media->getProperty( 1313 /* key */ kIOMaximumByteCountReadKey, 1314 /* plane */ gIOServicePlane ) ); 1315 if ( number ) 1316 *(uint64_t *)data = number->unsigned64BitValue(); 1317 else 1318 *(uint64_t *)data = 0; 1319 1320 } break; 1321 1322 case DKIOCGETMAXBYTECOUNTWRITE: // (uint64_t *) 1323 { 1324 // 1325 // This ioctl returns the maximum byte count for writes. 1326 // 1327 1328 OSNumber * number = OSDynamicCast( 1329 /* class */ OSNumber, 1330 /* object */ minor->media->getProperty( 1331 /* key */ kIOMaximumByteCountWriteKey, 1332 /* plane */ gIOServicePlane ) ); 1333 if ( number ) 1334 *(uint64_t *)data = number->unsigned64BitValue(); 1335 else 1336 *(uint64_t *)data = 0; 1337 1338 } break; 1339 1340 case DKIOCGETMAXSEGMENTCOUNTREAD: // (uint64_t *) 1341 { 1342 // 1343 // This ioctl returns the maximum segment count for reads. 1344 // 1345 1346 OSNumber * number = OSDynamicCast( 1347 /* class */ OSNumber, 1348 /* object */ minor->media->getProperty( 1349 /* key */ kIOMaximumSegmentCountReadKey, 1350 /* plane */ gIOServicePlane ) ); 1351 if ( number ) 1352 *(uint64_t *)data = number->unsigned64BitValue(); 1353 else 1354 *(uint64_t *)data = 0; 1355 1356 } break; 1357 1358 case DKIOCGETMAXSEGMENTCOUNTWRITE: // (uint64_t *) 1359 { 1360 // 1361 // This ioctl returns the maximum segment count for writes. 1362 // 1363 1364 OSNumber * number = OSDynamicCast( 1365 /* class */ OSNumber, 1366 /* object */ minor->media->getProperty( 1367 /* key */ kIOMaximumSegmentCountWriteKey, 1368 /* plane */ gIOServicePlane ) ); 1369 if ( number ) 1370 *(uint64_t *)data = number->unsigned64BitValue(); 1371 else 1372 *(uint64_t *)data = 0; 1373 1374 } break; 1375 1376 case DKIOCGETMAXSEGMENTBYTECOUNTREAD: // (uint64_t *) 1377 { 1378 // 1379 // This ioctl returns the maximum segment byte count for reads. 1380 // 1381 1382 OSNumber * number = OSDynamicCast( 1383 /* class */ OSNumber, 1384 /* object */ minor->media->getProperty( 1385 /* key */ kIOMaximumSegmentByteCountReadKey, 1386 /* plane */ gIOServicePlane ) ); 1387 if ( number ) 1388 *(uint64_t *)data = number->unsigned64BitValue(); 1389 else 1390 *(uint64_t *)data = 0; 1391 1392 } break; 1393 1394 case DKIOCGETMAXSEGMENTBYTECOUNTWRITE: // (uint64_t *) 1395 { 1396 // 1397 // This ioctl returns the maximum segment byte count for writes. 1398 // 1399 1400 OSNumber * number = OSDynamicCast( 1401 /* class */ OSNumber, 1402 /* object */ minor->media->getProperty( 1403 /* key */ kIOMaximumSegmentByteCountWriteKey, 1404 /* plane */ gIOServicePlane ) ); 1405 if ( number ) 1406 *(uint64_t *)data = number->unsigned64BitValue(); 1407 else 1408 *(uint64_t *)data = 0; 1409 1410 } break; 1411 1412 case DKIOCGETMINSEGMENTALIGNMENTBYTECOUNT: // (uint64_t *) 1413 { 1414 // 1415 // This ioctl returns the minimum segment alignment in bytes. 1416 // 1417 1418 OSNumber * number = OSDynamicCast( 1419 /* class */ OSNumber, 1420 /* object */ minor->media->getProperty( 1421 /* key */ kIOMinimumSegmentAlignmentByteCountKey, 1422 /* plane */ gIOServicePlane ) ); 1423 if ( number ) 1424 *(uint64_t *)data = number->unsigned64BitValue(); 1425 else 1426 *(uint64_t *)data = 0; 1427 1428 } break; 1429 1430 case DKIOCGETMAXSEGMENTADDRESSABLEBITCOUNT: // (uint64_t *) 1431 { 1432 // 1433 // This ioctl returns the maximum segment width in bits. 1434 // 1435 1436 OSNumber * number = OSDynamicCast( 1437 /* class */ OSNumber, 1438 /* object */ minor->media->getProperty( 1439 /* key */ kIOMaximumSegmentAddressableBitCountKey, 1440 /* plane */ gIOServicePlane ) ); 1441 if ( number ) 1442 *(uint64_t *)data = number->unsigned64BitValue(); 1443 else 1444 *(uint64_t *)data = 0; 1445 1446 } break; 1447 1448 case DKIOCGETPHYSICALBLOCKSIZE: // (uint32_t *) 1449 { 1450 // 1451 // This ioctl returns the preferred block size of the device. 1452 // 1453 1454 OSNumber * number = OSDynamicCast( 1455 /* class */ OSNumber, 1456 /* object */ minor->media->getProperty( 1457 /* key */ kIOPropertyPhysicalBlockSizeKey, 1458 /* plane */ gIOServicePlane ) ); 1459 if ( number ) 1460 *(uint32_t *)data = number->unsigned32BitValue(); 1461 else 1462 *(uint32_t *)data = minor->media->getPreferredBlockSize(); 1463 1464 } break; 1465 1466 case DKIOCGETCOMMANDPOOLSIZE: // (uint32_t *) 1467 { 1468 // 1469 // This ioctl returns the maximum queue depth of the device. 1470 // 1471 1472 OSNumber * number = OSDynamicCast( 1473 /* class */ OSNumber, 1474 /* object */ minor->media->getProperty( 1475 /* key */ kIOCommandPoolSizeKey, 1476 /* plane */ gIOServicePlane ) ); 1477 if ( number ) 1478 *(uint32_t *)data = number->unsigned32BitValue(); 1479 else 1480 *(uint32_t *)data = 0; 1481 1482 } break; 1483 1484 case DKIOCISFORMATTED: // (uint32_t *) 1485 { 1486 // 1487 // This ioctl returns truth if the media object is formatted. 1488 // 1489 1490 *(uint32_t *)data = minor->media->isFormatted(); 1491 1492 } break; 1493 1494 case DKIOCISWRITABLE: // (uint32_t *) 1495 { 1496 // 1497 // This ioctl returns truth if the media object is writable. 1498 // 1499 1500 *(uint32_t *)data = minor->media->isWritable(); 1501 1502 } break; 1503 1504 case DKIOCEJECT: // (void) 1505 { 1506 // 1507 // This ioctl asks that the media object be ejected from the device. 1508 // 1509 1510 IOMediaBSDClient * client; 1511 IOBlockStorageDriver * driver; 1512 MinorTable * minors; 1513 IOReturn status; 1514 1515 client = minor->client; 1516 driver = (IOBlockStorageDriver *) minor->media->getProvider(); 1517 driver = OSDynamicCast(IOBlockStorageDriver, driver); 1518 minors = gIOMediaBSDClientGlobals.getMinors(); 1519 1520 // Determine whether this media has an IOBlockStorageDriver parent. 1521 1522 if ( driver == 0 ) { error = ENOTTY; break; } 1523 1524 // Disable access to opens, closes, tables. 1525 1526 gIOMediaBSDClientGlobals.lockOpen(); 1527 gIOMediaBSDClientGlobals.lockState(); 1528 1529 // Determine whether there are other opens on the device nodes that 1530 // are associated with this anchor -- the one valid open is the one 1531 // that issued this eject. If all is well, we then attempt to open 1532 // the block storage driver to make the ejection request. 1533 1534 if ( minors->getOpenCountForAnchorID(minor->anchorID) == 1 && 1535 driver->open(client, 0, kIOStorageAccessReaderWriter) ) 1536 { 1537 // Mark the minor as being in "open flux". This means we are in 1538 // a state where the media object has been closed but the device 1539 // node is still open; we must reject all future accesses to the 1540 // device node until it is closed. Note that we do this both on 1541 // success and failure of the ejection call. 1542 1543 minor->isOrphaned = true; 1544 1545 // Enable access to opens, closes, tables. 1546 1547 gIOMediaBSDClientGlobals.unlockState(); 1548 gIOMediaBSDClientGlobals.unlockOpen(); 1549 1550 // Close the media object before the ejection request is made. 1551 1552 minor->media->close(client); 1553 1554 // Retain the media's BSD client object, as it is about 1555 // to be terminated, and we still need it for the close. 1556 1557 client->retain(); 1558 1559 // Eject the media from the drive. 1560 1561 status = driver->ejectMedia(); 1562 error = driver->errnoFromReturn(status); 1563 1564 // Close the block storage driver. 1565 1566 driver->close(client); 1567 1568 // Release the media's BSD client object. 1569 1570 client->release(); 1571 } 1572 else 1573 { 1574 error = EBUSY; 1575 1576 // Enable access to opens, closes, tables. 1577 1578 gIOMediaBSDClientGlobals.unlockState(); 1579 gIOMediaBSDClientGlobals.unlockOpen(); 1580 } 1581 1582 } break; 1583 1584 case DKIOCFORMAT: // (dk_format_capacity_t *) 1585 { 1586 // 1587 // This ioctl asks that the media object be formatted. 1588 // 1589 1590 IOMediaBSDClient * client; 1591 IOBlockStorageDriver * driver; 1592 MinorTable * minors; 1593 dk_format_capacity_t * request; 1594 IOReturn status; 1595 1596 client = minor->client; 1597 driver = (IOBlockStorageDriver *) minor->media->getProvider(); 1598 driver = OSDynamicCast(IOBlockStorageDriver, driver); 1599 minors = gIOMediaBSDClientGlobals.getMinors(); 1600 request = (dk_format_capacity_t *) data; 1601 1602 if ( DKIOC_IS_RESERVED(data, 0xF000) ) { error = EINVAL; break; } 1603 1604 // Determine whether this media has an IOBlockStorageDriver parent. 1605 1606 if ( driver == 0 ) { error = ENOTTY; break; } 1607 1608 // Disable access to opens, closes, tables. 1609 1610 gIOMediaBSDClientGlobals.lockOpen(); 1611 gIOMediaBSDClientGlobals.lockState(); 1612 1613 // Determine whether there are other opens on the device nodes that 1614 // are associated with this anchor -- the one valid open is the one 1615 // that issued the format. If all is well, we then attempt to open 1616 // the block storage driver to make the formatting request. 1617 1618 if ( minors->getOpenCountForAnchorID(minor->anchorID) == 1 && 1619 driver->open(client, 0, kIOStorageAccessReaderWriter) ) 1620 { 1621 UInt64 capacity = request->blockCount * request->blockSize; 1622 1623 // Mark the minor as being in "open flux". This means we are in 1624 // a state where the media object has been closed but the device 1625 // node is still open; we must reject all future accesses to the 1626 // device node until it is closed. Note that we do this both on 1627 // success and failure of the formatting call. 1628 1629 minor->isOrphaned = true; 1630 1631 // Enable access to opens, closes, tables. 1632 1633 gIOMediaBSDClientGlobals.unlockState(); 1634 gIOMediaBSDClientGlobals.unlockOpen(); 1635 1636 // Close the media object before the formatting request is made. 1637 1638 minor->media->close(client); 1639 1640 // Retain the media's BSD client object, as it is about 1641 // to be terminated, and we still need it for the close. 1642 1643 client->retain(); 1644 1645 // Format the media in the drive. 1646 1647 status = driver->formatMedia(capacity); 1648 error = driver->errnoFromReturn(status); 1649 1650 // Wait until I/O Kit has finished to attempt to match storage 1651 // drivers, since the media object will have been re-published. 1652 // This shall ensure the new IOMediaBSDClient reconnects prior 1653 // to our return from DKIOCFORMAT. Note that we still recover 1654 // correctly in case the media object doesn't get re-published, 1655 // as though an ejection had taken place. 1656 1657 driver->waitQuiet(); 1658 1659 // Close the block storage driver. 1660 1661 driver->close(client); 1662 1663 // Release the media's BSD client object. 1664 1665 client->release(); 1666 } 1667 else 1668 { 1669 error = EBUSY; 1670 1671 // Enable access to opens, closes, tables. 1672 1673 gIOMediaBSDClientGlobals.unlockState(); 1674 gIOMediaBSDClientGlobals.unlockOpen(); 1675 } 1676 1677 } break; 1678 1679 case DKIOCGETFORMATCAPACITIES: // (dk_format_capacities_t *) 1680 { 1681 // 1682 // This ioctl returns the feasible format capacities for this media 1683 // object. 1684 // 1685 1686 UInt64 blockSize; 1687 UInt64 * capacities; 1688 UInt32 capacitiesCount; 1689 UInt32 capacitiesMaxCount; 1690 IOBlockStorageDriver * driver; 1691 dk_format_capacities_64_t request; 1692 dk_format_capacities_32_t * request32; 1693 dk_format_capacities_64_t * request64; 1694 1695 driver = (IOBlockStorageDriver *) minor->media->getProvider(); 1696 driver = OSDynamicCast(IOBlockStorageDriver, driver); 1697 request32 = (dk_format_capacities_32_t *) data; 1698 request64 = (dk_format_capacities_64_t *) data; 1699 1700 if ( proc_is64bit(proc) ) 1701 { 1702 if ( DKIOC_IS_RESERVED(data, 0xF000) ) { error = EINVAL; break; } 1703 1704 request.capacities = request64->capacities; 1705 request.capacitiesCount = request64->capacitiesCount; 1706 } 1707 else 1708 { 1709 if ( DKIOC_IS_RESERVED(data, 0xFF00) ) { error = EINVAL; break; } 1710 1711 request.capacities = request32->capacities; 1712 request.capacitiesCount = request32->capacitiesCount; 1713 } 1714 1715 // Determine whether this media has an IOBlockStorageDriver parent. 1716 1717 if ( driver == 0 ) { error = ENOTTY; break; } 1718 1719 // Obtain the format capacities list from the block storage driver. 1720 1721 capacitiesCount = request.capacitiesCount; 1722 capacitiesMaxCount = driver->getFormatCapacities(0, 0); 1723 1724 if ( capacitiesCount ) 1725 { 1726 if ( request.capacities == 0 ) { error = EINVAL; break; } 1727 1728 capacitiesCount = min(capacitiesCount, capacitiesMaxCount); 1729 capacities = IONew(UInt64, capacitiesCount); 1730 1731 if ( capacities == 0 ) { error = ENOMEM; break; } 1732 1733 driver->getFormatCapacities(capacities, capacitiesCount); 1734 1735 blockSize = minor->media->getPreferredBlockSize(); 1736 if ( blockSize == 0 ) blockSize = DEV_BSIZE; 1737 1738 // Construct the format capacities list for client consumption. 1739 1740 for ( UInt32 index = 0; index < capacitiesCount; index++ ) 1741 { 1742 dk_format_capacity_t capacity = { 0 }; 1743 1744 capacity.blockCount = capacities[index] / blockSize; 1745 capacity.blockSize = blockSize; 1746 1747 if ( proc == kernproc ) 1748 { 1749 bcopy( /* src */ &capacity, 1750 /* dst */ (void *) (request.capacities + index * sizeof(dk_format_capacity_t)), 1751 /* n */ sizeof(dk_format_capacity_t) ); 1752 } 1753 else 1754 { 1755 error = copyout( /* kaddr */ &capacity, 1756 /* uaddr */ request.capacities + index * sizeof(dk_format_capacity_t), 1757 /* len */ sizeof(dk_format_capacity_t) ); 1758 } 1759 1760 if ( error ) break; 1761 } 1762 1763 IODelete(capacities, UInt64, capacitiesCount); 1764 1765 if ( capacitiesCount < capacitiesMaxCount ) { error = E2BIG; } 1766 } 1767 1768 if ( proc_is64bit(proc) ) 1769 { 1770 request64->capacitiesCount = request.capacitiesCount; 1771 } 1772 else 1773 { 1774 request32->capacitiesCount = request.capacitiesCount; 1775 } 1776 1777 } break; 1778 1779 case DKIOCSYNCHRONIZECACHE: // (void) 1780 { 1781 // 1782 // This ioctl asks that the media object be flushed onto the device. 1783 // 1784 1785 IOReturn status; 1786 1787 // Flush the media onto the drive. 1788 1789 status = minor->media->synchronizeCache(minor->client); 1790 error = minor->media->errnoFromReturn(status); 1791 1792 } break; 1793 1794 case DKIOCUNMAP: // (dk_unmap_t) 1795 { 1796 // 1797 // This ioctl asks that the media object delete unused data. 1798 // 1799 1800 IOStorageExtent * extents; 1801 dk_unmap_64_t request; 1802 dk_unmap_32_t * request32; 1803 dk_unmap_64_t * request64; 1804 IOReturn status; 1805 1806 assert(sizeof(dk_extent_t) == sizeof(IOStorageExtent)); 1807 1808 request32 = (dk_unmap_32_t *) data; 1809 request64 = (dk_unmap_64_t *) data; 1810 1811 if ( proc_is64bit(proc) ) 1812 { 1813 request.extents = request64->extents; 1814 request.extentsCount = request64->extentsCount; 1815 request.options = request64->options; 1816 } 1817 else 1818 { 1819 if ( DKIOC_IS_RESERVED(data, 0xF000) ) { error = EINVAL; break; } 1820 1821 request.extents = request32->extents; 1822 request.extentsCount = request32->extentsCount; 1823 request.options = request32->options; 1824 } 1825 1826 // Delete unused data from the media. 1827 1828 if ( request.extents == 0 ) { error = EINVAL; break; } 1829 1830 extents = IONew(IOStorageExtent, request.extentsCount); 1831 1832 if ( extents == 0 ) { error = ENOMEM; break; } 1833 1834 if ( proc == kernproc ) 1835 { 1836 bcopy( /* src */ (void *) request.extents, 1837 /* dst */ extents, 1838 /* n */ request.extentsCount * sizeof(IOStorageExtent) ); 1839 } 1840 else 1841 { 1842 error = copyin( /* uaddr */ request.extents, 1843 /* kaddr */ extents, 1844 /* len */ request.extentsCount * sizeof(IOStorageExtent) ); 1845 } 1846 1847 if ( error == 0 ) 1848 { 1849 status = minor->media->unmap( /* client */ minor->client, 1850 /* extents */ extents, 1851 /* extentsCount */ request.extentsCount, 1852 /* options */ request.options ); 1853 1854 error = minor->media->errnoFromReturn(status); 1855 } 1856 1857 IODelete(extents, IOStorageExtent, request.extentsCount); 1858 1859 } break; 1860 1861 case DKIOCREQUESTIDLE: // (void) 1862 { 1863 // 1864 // This ioctl asks that the device enter an idle state. 1865 // 1866 1867 IOBlockStorageDriver * driver; 1868 IOReturn status; 1869 1870 driver = (IOBlockStorageDriver *) minor->media->getProvider(); 1871 driver = OSDynamicCast(IOBlockStorageDriver, driver); 1872 1873 // Determine whether this media has an IOBlockStorageDriver parent. 1874 1875 if ( driver == 0 ) { error = ENOTTY; break; } 1876 1877 // Request that the drive enter an idle state. 1878 1879 status = driver->requestIdle(); 1880 error = minor->media->errnoFromReturn(status); 1881 1882 } break; 1883 1884 case DKIOCGETBSDUNIT: // (uint32_t *) 1885 { 1886 // 1887 // This ioctl returns the BSD unit of the media object. 1888 // 1889 1890 OSNumber * number = OSDynamicCast( 1891 /* class */ OSNumber, 1892 /* object */ minor->media->getProperty( 1893 /* key */ kIOBSDUnitKey ) ); 1894 if ( number ) 1895 *(uint32_t *)data = number->unsigned32BitValue(); 1896 else 1897 *(uint32_t *)data = 0; 1898 1899 } break; 1900 1901 case DKIOCGETFIRMWAREPATH: // (dk_firmware_path_t *) 1902 { 1903 // 1904 // This ioctl returns the open firmware path for this media object. 1905 // 1906 1907 int l = sizeof(((dk_firmware_path_t *)data)->path); 1908 char * p = ((dk_firmware_path_t *)data)->path; 1909 1910 if ( minor->media->getPath(p, &l, gIODTPlane) && strchr(p, ':') ) 1911 strlcpy(p, strchr(p, ':') + 1, l); // (strip the plane name) 1912 else 1913 error = EINVAL; 1914 1915 } break; 1916 1917 case DKIOCISSOLIDSTATE: // (uint32_t *) 1918 { 1919 // 1920 // This ioctl returns truth if the device is solid state. 1921 // 1922 1923 OSDictionary * dictionary = OSDynamicCast( 1924 /* class */ OSDictionary, 1925 /* object */ minor->media->getProperty( 1926 /* key */ kIOPropertyDeviceCharacteristicsKey, 1927 /* plane */ gIOServicePlane ) ); 1928 1929 *(uint32_t *)data = false; 1930 1931 if ( dictionary ) 1932 { 1933 OSString * string = OSDynamicCast( 1934 /* class */ OSString, 1935 /* object */ dictionary->getObject( 1936 /* key */ kIOPropertyMediumTypeKey ) ); 1937 1938 if ( string && string->isEqualTo(kIOPropertyMediumTypeSolidStateKey) ) 1939 *(uint32_t *)data = true; 1940 } 1941 1942 } break; 1943 1944 case DKIOCISVIRTUAL: // (uint32_t *) 1945 { 1946 // 1947 // This ioctl returns truth if the device is virtual. 1948 // 1949 1950 OSDictionary * dictionary = OSDynamicCast( 1951 /* class */ OSDictionary, 1952 /* object */ minor->media->getProperty( 1953 /* key */ kIOPropertyProtocolCharacteristicsKey, 1954 /* plane */ gIOServicePlane ) ); 1955 1956 *(uint32_t *)data = false; 1957 1958 if ( dictionary ) 1959 { 1960 OSString * string = OSDynamicCast( 1961 /* class */ OSString, 1962 /* object */ dictionary->getObject( 1963 /* key */ kIOPropertyPhysicalInterconnectTypeKey ) ); 1964 1965 if ( string && string->isEqualTo(kIOPropertyPhysicalInterconnectTypeVirtual) ) 1966 *(uint32_t *)data = true; 1967 } 1968 1969 } break; 1970 1971 case DKIOCGETBASE: // (uint64_t *) 1972 { 1973 // 1974 // This ioctl returns the base of the media object. 1975 // 1976 1977 *(uint64_t *)data = minor->media->getBase(); 1978 1979 } break; 1980 1981 case DKIOCGETFEATURES: // (uint32_t *) 1982 { 1983 // 1984 // This ioctl returns the features of the media object. 1985 // 1986 1987 OSDictionary * dictionary = OSDynamicCast( 1988 /* class */ OSDictionary, 1989 /* object */ minor->media->getProperty( 1990 /* key */ kIOStorageFeaturesKey, 1991 /* plane */ gIOServicePlane ) ); 1992 1993 *(uint32_t *)data = 0; 1994 1995 if ( dictionary ) 1996 { 1997 OSBoolean * boolean; 1998 1999 boolean = OSDynamicCast( 2000 /* class */ OSBoolean, 2001 /* object */ dictionary->getObject( 2002 /* key */ kIOStorageFeatureForceUnitAccess ) ); 2003 2004 if ( boolean == kOSBooleanTrue ) 2005 *(uint32_t *)data |= DK_FEATURE_FORCE_UNIT_ACCESS; 2006 2007 boolean = OSDynamicCast( 2008 /* class */ OSBoolean, 2009 /* object */ dictionary->getObject( 2010 /* key */ kIOStorageFeaturePriority ) ); 2011 2012 if ( boolean == kOSBooleanTrue ) 2013 *(uint32_t *)data |= DK_FEATURE_PRIORITY; 2014 2015 boolean = OSDynamicCast( 2016 /* class */ OSBoolean, 2017 /* object */ dictionary->getObject( 2018 /* key */ kIOStorageFeatureUnmap ) ); 2019 2020 if ( boolean == kOSBooleanTrue ) 2021 *(uint32_t *)data |= DK_FEATURE_UNMAP; 2022 } 2023 2024 } break; 2025 2026 case DKIOCGETTHROTTLEMASK: // (uint64_t *) 2027 { 2028 // 2029 // This ioctl returns the throttle mask for the media object. 2030 // 2031 2032 *( ( uint64_t * ) data ) = _IOMediaBSDClientGetThrottleMask( minor->media ); 2033 2034 } break; 2035 2036 case DKIOCGETENCRYPTIONTYPE: // (uint32_t *) 2037 { 2038 // 2039 // This ioctl returns the encryption type of the device. 2040 // 2041 2042 OSDictionary * dictionary = OSDynamicCast( 2043 /* class */ OSDictionary, 2044 /* object */ minor->media->getProperty( 2045 /* key */ kIOPropertyControllerCharacteristicsKey, 2046 /* plane */ gIOServicePlane ) ); 2047 2048 *(uint32_t *)data = 0; 2049 2050 if ( dictionary ) 2051 { 2052 OSString * string = OSDynamicCast( 2053 /* class */ OSString, 2054 /* object */ dictionary->getObject( 2055 /* key */ kIOPropertyEncryptionTypeKey ) ); 2056 2057 if ( string ) 2058 { 2059 if ( string->isEqualTo(kIOPropertyAESCBCKey) ) 2060 *(uint32_t *)data = DK_ENCRYPTION_TYPE_AES_CBC; 2061 else if ( string->isEqualTo(kIOPropertyAESXEXKey) ) 2062 *(uint32_t *)data = DK_ENCRYPTION_TYPE_AES_XEX; 2063 else if ( string->isEqualTo(kIOPropertyAESXTSKey) ) 2064 *(uint32_t *)data = DK_ENCRYPTION_TYPE_AES_XTS; 2065 } 2066 } 2067 2068 } break; 2069 2070 case DKIOCISLOWPOWERMODE: // (uint32_t *) 2071 { 2072 // 2073 // This ioctl returns truth if the device is low power. 2074 // 2075 2076 OSDictionary * dictionary = OSDynamicCast( 2077 /* class */ OSDictionary, 2078 /* object */ minor->media->getProperty( 2079 /* key */ kIOPropertyControllerCharacteristicsKey, 2080 /* plane */ gIOServicePlane ) ); 2081 2082 *(uint32_t *)data = false; 2083 2084 if ( dictionary ) 2085 { 2086 OSBoolean * boolean = OSDynamicCast( 2087 /* class */ OSBoolean, 2088 /* object */ dictionary->getObject( 2089 /* key */ kIOPropertyLowPowerModeKey ) ); 2090 2091 if ( boolean == kOSBooleanTrue ) 2092 *(uint32_t *)data = true; 2093 } 2094 2095 } break; 2096 2097 default: 2098 { 2099 // 2100 // Call the foreign ioctl handler for all other ioctls. 2101 // 2102 2103 error = minor->client->ioctl(dev, cmd, data, flags, proc); 2104 2105 } break; 2106 } 2107 2108 return error; // (return error status) 2109} 2110 2111int dkioctl_bdev(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc) 2112{ 2113 // 2114 // dkioctl_bdev performs operations other than a read or write, specific to 2115 // the block device. 2116 // 2117 2118 int error = 0; 2119 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2120 2121 if ( minor->isOrphaned ) return EBADF; // (is minor in flux?) 2122 2123 // 2124 // Process the ioctl. 2125 // 2126 2127 switch ( cmd ) 2128 { 2129 case DKIOCGETBLOCKSIZE: // (uint32_t *) 2130 { 2131 // 2132 // This ioctl returns the preferred (or overrided) block size of the 2133 // media object. 2134 // 2135 2136 *(uint32_t *)data = minor->bdevBlockSize; 2137 2138 } break; 2139 2140 case DKIOCSETBLOCKSIZE: // (uint32_t *) 2141 { 2142 // 2143 // This ioctl overrides the block size for the media object, for the 2144 // duration of all block device opens at this minor. 2145 // 2146 2147 if ( *(uint32_t *)data > 0 ) 2148 minor->bdevBlockSize = (UInt64) (*(uint32_t *)data); 2149 else 2150 error = EINVAL; 2151 2152 } break; 2153 2154#ifndef __LP64__ 2155 case DKIOCGETBLOCKCOUNT32: // (uint32_t *) 2156 { 2157 // 2158 // This ioctl returns the size of the media object in blocks. The 2159 // implied block size is returned by DKIOCGETBLOCKSIZE. 2160 // 2161 2162 if ( minor->bdevBlockSize ) 2163 *(uint32_t *)data = ( minor->media->getSize() / 2164 minor->bdevBlockSize ); 2165 else 2166 *(uint32_t *)data = 0; 2167 2168 } break; 2169#endif /* !__LP64__ */ 2170 2171 case DKIOCGETBLOCKCOUNT: // (uint64_t *) 2172 { 2173 // 2174 // This ioctl returns the size of the media object in blocks. The 2175 // implied block size is returned by DKIOCGETBLOCKSIZE. 2176 // 2177 2178 if ( minor->bdevBlockSize ) 2179 *(uint64_t *)data = ( minor->media->getSize() / 2180 minor->bdevBlockSize ); 2181 else 2182 *(uint64_t *)data = 0; 2183 2184 } break; 2185 2186 case DKIOCLOCKPHYSICALEXTENTS: // (void) 2187 { 2188 bool success; 2189 2190 success = minor->media->lockPhysicalExtents( minor->client ); 2191 2192 if ( success == false ) 2193 { 2194 error = ENOTSUP; 2195 } 2196 2197 } break; 2198 2199 case DKIOCGETPHYSICALEXTENT: // (dk_physical_extent_t) 2200 { 2201 dk_physical_extent_t * request; 2202 2203 request = ( dk_physical_extent_t * ) data; 2204 2205 if ( DKIOC_IS_RESERVED( data, 0xFFFF0000 ) == false ) 2206 { 2207 IOStorage * media; 2208 2209 media = minor->media->copyPhysicalExtent( minor->client, &request->offset, &request->length ); 2210 2211 if ( media ) 2212 { 2213 OSNumber * majorID; 2214 2215 majorID = OSDynamicCast( OSNumber, media->getProperty( kIOBSDMajorKey ) ); 2216 2217 if ( majorID ) 2218 { 2219 OSNumber * minorID; 2220 2221 minorID = OSDynamicCast( OSNumber, media->getProperty( kIOBSDMinorKey ) ); 2222 2223 if ( minorID ) 2224 { 2225 request->dev = makedev( majorID->unsigned32BitValue( ), minorID->unsigned32BitValue( ) ); 2226 } 2227 else 2228 { 2229 error = ENODEV; 2230 } 2231 } 2232 else 2233 { 2234 error = ENODEV; 2235 } 2236 2237 media->release( ); 2238 } 2239 else 2240 { 2241 error = ENOTSUP; 2242 } 2243 } 2244 else 2245 { 2246 error = EINVAL; 2247 } 2248 2249 } break; 2250 2251 case DKIOCUNLOCKPHYSICALEXTENTS: // (void) 2252 { 2253 minor->media->unlockPhysicalExtents( minor->client ); 2254 2255 } break; 2256 2257 case DKIOCSETTIER: // (dk_set_tier_t) 2258 { 2259 // 2260 // This ioctl asks that the media object reprioritize a read or 2261 // write request. 2262 // 2263 2264 IOStorageExtent * extents; 2265 dk_set_tier_64_t request; 2266 dk_set_tier_32_t * request32; 2267 dk_set_tier_64_t * request64; 2268 IOReturn status; 2269 2270 assert(sizeof(dk_extent_t) == sizeof(IOStorageExtent)); 2271 2272 request32 = (dk_set_tier_32_t *) data; 2273 request64 = (dk_set_tier_64_t *) data; 2274 2275 if ( proc_is64bit(proc) ) 2276 { 2277 if ( DKIOC_IS_RESERVED(data, 0xE000) ) { error = EINVAL; break; } 2278 2279 request.extents = request64->extents; 2280 request.extentsCount = request64->extentsCount; 2281 request.tier = request64->tier; 2282 } 2283 else 2284 { 2285 if ( DKIOC_IS_RESERVED(data, 0xFE00) ) { error = EINVAL; break; } 2286 2287 request.extents = request32->extents; 2288 request.extentsCount = request32->extentsCount; 2289 request.tier = request32->tier; 2290 } 2291 2292 // Reprioritize a read or write request. 2293 2294 if ( request.extents == 0 ) { error = EINVAL; break; } 2295 2296 extents = IONew(IOStorageExtent, request.extentsCount); 2297 2298 if ( extents == 0 ) { error = ENOMEM; break; } 2299 2300 if ( proc == kernproc ) 2301 { 2302 bcopy( /* src */ (void *) request.extents, 2303 /* dst */ extents, 2304 /* n */ request.extentsCount * sizeof(IOStorageExtent) ); 2305 } 2306 else 2307 { 2308 error = copyin( /* uaddr */ request.extents, 2309 /* kaddr */ extents, 2310 /* len */ request.extentsCount * sizeof(IOStorageExtent) ); 2311 } 2312 2313 if ( error == 0 ) 2314 { 2315 status = minor->media->setPriority( /* client */ minor->client, 2316 /* extents */ extents, 2317 /* extentsCount */ request.extentsCount, 2318 /* priority */ DK_TIER_TO_PRIORITY(request.tier) ); 2319 2320 error = minor->media->errnoFromReturn(status); 2321 } 2322 2323 IODelete(extents, IOStorageExtent, request.extentsCount); 2324 2325 } break; 2326 2327 default: 2328 { 2329 // 2330 // Call the common ioctl handler for all other ioctls. 2331 // 2332 2333 error = dkioctl(dev, cmd, data, flags, proc); 2334 2335 } break; 2336 } 2337 2338 return error; // (return error status) 2339} 2340 2341int dkioctl_cdev(dev_t dev, u_long cmd, caddr_t data, int flags, proc_t proc) 2342{ 2343 // 2344 // dkioctl_cdev performs operations other than a read or write, specific to 2345 // the character device. 2346 // 2347 2348 int error = 0; 2349 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2350 2351 if ( minor->isOrphaned ) return EBADF; // (is minor in flux?) 2352 2353 // 2354 // Process the ioctl. 2355 // 2356 2357 switch ( cmd ) 2358 { 2359#if TARGET_OS_EMBEDDED 2360 case _DKIOCSETSTATIC: // (void) 2361 { 2362 minor->cdevOptions |= kIOStorageOptionIsStatic; 2363 2364 } break; 2365#endif /* TARGET_OS_EMBEDDED */ 2366 2367 default: 2368 { 2369 // 2370 // Call the common ioctl handler for all other ioctls. 2371 // 2372 2373 error = dkioctl(dev, cmd, data, flags, proc); 2374 2375 } break; 2376 } 2377 2378 return error; // (return error status) 2379} 2380 2381int dksize(dev_t dev) 2382{ 2383 // 2384 // dksize returns the block size of the media. 2385 // 2386 // This is a departure from BSD 4.4's definition of this function, that is, 2387 // it will not return the size of the disk partition, as would be expected 2388 // in a BSD 4.4 implementation. 2389 // 2390 2391 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2392 2393 if ( minor->isOrphaned ) return 0; // (is minor in flux?) 2394 2395 return (int) minor->bdevBlockSize; // (return block size) 2396} 2397 2398// ============================================================================= 2399// Support For BSD Functions 2400 2401extern "C" task_t get_aiotask(); 2402 2403inline task_t get_kernel_task() 2404{ 2405 return kernel_task; 2406} 2407 2408inline task_t get_user_task() 2409{ 2410 task_t task; 2411 2412 task = get_aiotask(); 2413 2414 if ( task == 0 ) task = current_task(); 2415 2416 return task; 2417} 2418 2419inline dev_t DKR_GET_DEV(dkr_t dkr, dkrtype_t dkrtype) 2420{ 2421 return (dkrtype == DKRTYPE_BUF) 2422 ? buf_device((buf_t)dkr) 2423 : ((dio_t)dkr)->dev; 2424} 2425 2426inline UInt64 DKR_GET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype) 2427{ 2428 return (dkrtype == DKRTYPE_BUF) 2429 ? buf_count((buf_t)dkr) 2430 : uio_resid(((dio_t)dkr)->uio); 2431} 2432 2433inline UInt64 DKR_GET_BYTE_START(dkr_t dkr, dkrtype_t dkrtype) 2434{ 2435 if (dkrtype == DKRTYPE_BUF) 2436 { 2437 buf_t bp = (buf_t)dkr; 2438 MinorSlot * minor; 2439 2440 minor = gIOMediaBSDClientGlobals.getMinor(getminor(buf_device(bp))); 2441 2442 return (UInt64)buf_blkno(bp) * minor->bdevBlockSize; 2443 } 2444 2445 return uio_offset(((dio_t)dkr)->uio); 2446} 2447 2448inline bool DKR_IS_READ(dkr_t dkr, dkrtype_t dkrtype) 2449{ 2450 return (dkrtype == DKRTYPE_BUF) 2451 ? ((buf_flags((buf_t)dkr) & B_READ) == B_READ) 2452 : ((uio_rw(((dio_t)dkr)->uio)) == UIO_READ); 2453} 2454 2455inline bool DKR_IS_ASYNCHRONOUS(dkr_t dkr, dkrtype_t dkrtype) 2456{ 2457 return (dkrtype == DKRTYPE_BUF) 2458 ? true 2459 : false; 2460} 2461 2462inline bool DKR_IS_RAW(dkr_t dkr, dkrtype_t dkrtype) 2463{ 2464 return (dkrtype == DKRTYPE_BUF) 2465 ? false 2466 : true; 2467} 2468 2469inline void DKR_SET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype, UInt64 bcount) 2470{ 2471 if (dkrtype == DKRTYPE_BUF) 2472 buf_setresid((buf_t)dkr, buf_count((buf_t)dkr) - bcount); 2473 else 2474 uio_setresid(((dio_t)dkr)->uio, uio_resid(((dio_t)dkr)->uio) - bcount); 2475} 2476 2477inline void DKR_RUN_COMPLETION(dkr_t dkr, dkrtype_t dkrtype, IOReturn status) 2478{ 2479 if (dkrtype == DKRTYPE_BUF) 2480 { 2481 buf_t bp = (buf_t)dkr; 2482 MinorSlot * minor; 2483 2484 minor = gIOMediaBSDClientGlobals.getMinor(getminor(buf_device(bp))); 2485 2486 buf_seterror(bp, minor->media->errnoFromReturn(status)); // (error?) 2487 buf_biodone(bp); // (complete request) 2488 } 2489} 2490 2491inline IOMemoryDescriptor * DKR_GET_BUFFER(dkr_t dkr, dkrtype_t dkrtype) 2492{ 2493 if (dkrtype == DKRTYPE_BUF) 2494 { 2495 buf_t bp = (buf_t)dkr; 2496 int flags; 2497 2498 flags = buf_flags(bp); 2499 2500 if ( (flags & B_CLUSTER) ) 2501 { 2502 IOOptionBits options = kIOMemoryTypeUPL | kIOMemoryAsReference; 2503 2504 options |= (flags & B_READ) ? kIODirectionIn : kIODirectionOut; 2505 2506 return IOMemoryDescriptor::withOptions( // (multiple-range) 2507 buf_upl(bp), 2508 buf_count(bp), 2509 buf_uploffset(bp), 2510 0, 2511 options ); 2512 } 2513 else 2514 { 2515 return IOMemoryDescriptor::withAddressRange( // (single-range) 2516 buf_dataptr(bp), 2517 buf_count(bp), 2518 (flags & B_READ) ? kIODirectionIn : kIODirectionOut, 2519 (flags & B_PHYS) ? get_user_task() : get_kernel_task() ); 2520 } 2521 } 2522 else 2523 { 2524 IOOptionBits options = kIOMemoryTypeUIO | kIOMemoryAsReference; 2525 uio_t uio = ((dio_t)dkr)->uio; 2526 2527 options |= (uio_rw(uio) == UIO_READ) ? kIODirectionIn : kIODirectionOut; 2528 2529 return IOMemoryDescriptor::withOptions( // (multiple-range) 2530 uio, 2531 uio_iovcnt(uio), 2532 0, 2533 (uio_isuserspace(uio)) ? get_user_task() : get_kernel_task(), 2534 options ); 2535 } 2536} 2537 2538inline void * DKR_GET_DRIVER_DATA(dkr_t dkr, dkrtype_t dkrtype) 2539{ 2540 return (dkrtype == DKRTYPE_BUF) 2541 ? buf_drvdata((buf_t)dkr) 2542 : ((dio_t)dkr)->drvdata; 2543} 2544 2545inline void DKR_SET_DRIVER_DATA(dkr_t dkr, dkrtype_t dkrtype, void * drvdata) 2546{ 2547 if (dkrtype == DKRTYPE_BUF) 2548 buf_setdrvdata((buf_t)dkr, drvdata); 2549 else 2550 ((dio_t)dkr)->drvdata = drvdata; 2551} 2552 2553inline IOStorageAttributes DKR_GET_ATTRIBUTES(dkr_t dkr, dkrtype_t dkrtype) 2554{ 2555 IOStorageAttributes attributes = { 0 }; 2556 2557 if (dkrtype == DKRTYPE_BUF) 2558 { 2559 buf_t bp = (buf_t)dkr; 2560 int flags; 2561 2562 flags = buf_flags(bp); 2563 2564 attributes.bufattr = buf_attr(bp); 2565 2566 attributes.options |= (flags & B_FUA ) ? kIOStorageOptionForceUnitAccess : 0; 2567 attributes.options |= (flags & B_ENCRYPTED_IO ) ? kIOStorageOptionIsEncrypted : 0; 2568 attributes.options |= (flags & B_STATICCONTENT) ? kIOStorageOptionIsStatic : 0; 2569 2570 attributes.priority = DK_TIER_TO_PRIORITY(bufattr_throttled(attributes.bufattr)); 2571 } 2572#if TARGET_OS_EMBEDDED 2573 else 2574 { 2575 dev_t dev = ((dio_t)dkr)->dev; 2576 MinorSlot * minor; 2577 2578 minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2579 2580 attributes.options |= minor->cdevOptions; 2581 } 2582#endif /* TARGET_OS_EMBEDDED */ 2583 2584 return attributes; 2585} 2586///w:start 2587#if !TARGET_OS_EMBEDDED 2588inline bool DKR_DELAY_IDLE_SLEEP(dkr_t dkr, dkrtype_t dkrtype) 2589{ 2590 return (dkrtype == DKRTYPE_BUF) 2591 ? bufattr_delayidlesleep(buf_attr((buf_t)dkr)) 2592 : false; 2593} 2594#endif /* !TARGET_OS_EMBEDDED */ 2595///w:stop 2596 2597int dkreadwrite(dkr_t dkr, dkrtype_t dkrtype) 2598{ 2599 // 2600 // dkreadwrite performs a read or write operation. 2601 // 2602 2603 IOStorageAttributes attributes; 2604 IOMemoryDescriptor * buffer; 2605 register UInt64 byteCount; 2606 register UInt64 byteStart; 2607 UInt64 mediaSize; 2608 MinorSlot * minor; 2609 IOReturn status; 2610 2611 DKR_SET_DRIVER_DATA(dkr, dkrtype, 0); 2612 2613 minor = gIOMediaBSDClientGlobals.getMinor(getminor(DKR_GET_DEV(dkr, dkrtype))); 2614 2615 if ( minor->isOrphaned ) // (is minor in flux?) 2616 { 2617 status = kIOReturnNoMedia; 2618 goto dkreadwriteErr; 2619 } 2620 2621 if ( minor->media->isFormatted() == false ) // (is media unformatted?) 2622 { 2623 status = kIOReturnUnformattedMedia; 2624 goto dkreadwriteErr; 2625 } 2626 2627 byteCount = DKR_GET_BYTE_COUNT(dkr, dkrtype); // (get byte count) 2628 byteStart = DKR_GET_BYTE_START(dkr, dkrtype); // (get byte start) 2629 mediaSize = minor->media->getSize(); // (get media size) 2630 2631 // 2632 // Reads that start at (or perhaps past) the end-of-media are not considered 2633 // errors, even though no data is transferred, while writes at (or past) the 2634 // end-of-media do indeed return errors under BSD semantics. 2635 // 2636 2637 if ( byteStart >= mediaSize ) // (is start at or past the end-of-media?) 2638 { 2639 status = DKR_IS_READ(dkr,dkrtype) ? kIOReturnSuccess : kIOReturnIOError; 2640 goto dkreadwriteErr; 2641 } 2642 2643 // 2644 // Reads and writes, via the character device, that do not start or end on a 2645 // media block boundary are considered errors under BSD semantics. 2646 // 2647 2648 if ( DKR_IS_RAW(dkr, dkrtype) ) 2649 { 2650 UInt64 mediaBlockSize = minor->media->getPreferredBlockSize(); 2651 2652 if ( (byteStart % mediaBlockSize) || (byteCount % mediaBlockSize) ) 2653 { 2654 status = kIOReturnNotAligned; 2655 goto dkreadwriteErr; 2656 } 2657 } 2658 2659 // 2660 // Build a descriptor which describes the buffer involved in the transfer. 2661 // 2662 2663 buffer = DKR_GET_BUFFER(dkr, dkrtype); 2664 2665 if ( buffer == 0 ) // (no buffer?) 2666 { 2667 status = kIOReturnNoMemory; 2668 goto dkreadwriteErr; 2669 } 2670 2671 // 2672 // Reads and writes that extend beyond the end-of-media are not considered 2673 // errors under BSD semantics. We are to transfer as many bytes as can be 2674 // read or written from the medium and return no error. This differs from 2675 // IOMedia semantics which is to fail the entire request without copying a 2676 // single byte should it include something past the end-of-media. We must 2677 // adapt the IOMedia semantics to look like BSD semantics here. 2678 // 2679 // Clip the transfer buffer should this be a short read or write request. 2680 // 2681 2682 if ( byteCount > mediaSize - byteStart ) // (clip at end-of-media) 2683 { 2684 IOMemoryDescriptor * originalBuffer = buffer; 2685 2686 buffer = IOSubMemoryDescriptor::withSubRange( 2687 /* descriptor */ originalBuffer, 2688 /* withOffset */ 0, 2689 /* withLength */ mediaSize - byteStart, 2690 /* withDirection */ originalBuffer->getDirection() ); 2691 2692 originalBuffer->release(); // (either retained above or about to fail) 2693 2694 if ( buffer == 0 ) // (no buffer?) 2695 { 2696 status = kIOReturnNoMemory; 2697 goto dkreadwriteErr; 2698 } 2699 } 2700 2701 // 2702 // Prepare the transfer. 2703 // 2704 2705 if ( buffer->prepare() != kIOReturnSuccess ) // (prepare the buffer) 2706 { 2707 buffer->release(); 2708 status = kIOReturnVMError; // (wiring or permissions failure) 2709 goto dkreadwriteErr; 2710 } 2711 2712 // 2713 // Execute the transfer. 2714 // 2715 2716 attributes = DKR_GET_ATTRIBUTES(dkr, dkrtype); 2717 2718 DKR_SET_DRIVER_DATA(dkr, dkrtype, buffer); 2719 2720///w:start 2721#if !TARGET_OS_EMBEDDED 2722 if ( DKR_DELAY_IDLE_SLEEP(dkr, dkrtype) ) 2723 { 2724 IOPMDriverAssertionID assertionID; 2725 AbsoluteTime assertionTime; 2726 2727 gIOMediaBSDClientGlobals.lockAssertion(); 2728 2729 clock_interval_to_deadline(60, NSEC_PER_SEC, &assertionTime); 2730 2731 gIOMediaBSDClientGlobals.setAssertionTime(assertionTime); 2732 2733 assertionID = gIOMediaBSDClientGlobals.getAssertionID(); 2734 2735 if ( assertionID == kIOPMUndefinedDriverAssertionID ) 2736 { 2737 assertionID = IOService::getPMRootDomain()->createPMAssertion( 2738 /* type */ kIOPMDriverAssertionReservedBit7, 2739 /* level */ kIOPMDriverAssertionLevelOn, 2740 /* service */ minor->client, 2741 /* description */ "com.apple.iokit.IOStorageFamily" ); 2742 2743 if ( assertionID != kIOPMUndefinedDriverAssertionID ) 2744 { 2745 gIOMediaBSDClientGlobals.setAssertionID(assertionID); 2746 2747 thread_call_enter_delayed( 2748 /* call */ gIOMediaBSDClientGlobals.getAssertionCall(), 2749 /* deadline */ assertionTime ); 2750 } 2751 } 2752 2753 gIOMediaBSDClientGlobals.unlockAssertion(); 2754 } 2755#endif /* !TARGET_OS_EMBEDDED */ 2756///w:stop 2757 if ( DKR_IS_ASYNCHRONOUS(dkr, dkrtype) ) // (an asynchronous request?) 2758 { 2759 IOStorageCompletion completion; 2760 2761 completion.target = dkr; 2762 completion.action = dkreadwritecompletion; 2763 completion.parameter = (void *) dkrtype; 2764 2765 if ( DKR_IS_READ(dkr, dkrtype) ) // (a read?) 2766 { 2767 minor->media->read( /* client */ minor->client, 2768 /* byteStart */ byteStart, 2769 /* buffer */ buffer, 2770 /* attributes */ &attributes, 2771 /* completion */ &completion ); // (go) 2772 } 2773 else // (a write?) 2774 { 2775 minor->media->write( /* client */ minor->client, 2776 /* byteStart */ byteStart, 2777 /* buffer */ buffer, 2778 /* attributes */ &attributes, 2779 /* completion */ &completion ); // (go) 2780 } 2781 2782 status = kIOReturnSuccess; 2783 } 2784 else // (a synchronous request?) 2785 { 2786 if ( DKR_IS_READ(dkr, dkrtype) ) // (a read?) 2787 { 2788 status = minor->media->read( 2789 /* client */ minor->client, 2790 /* byteStart */ byteStart, 2791 /* buffer */ buffer, 2792 /* attributes */ &attributes, 2793 /* actualByteCount */ &byteCount ); // (go) 2794 } 2795 else // (a write?) 2796 { 2797 status = minor->media->write( 2798 /* client */ minor->client, 2799 /* byteStart */ byteStart, 2800 /* buffer */ buffer, 2801 /* attributes */ &attributes, 2802 /* actualByteCount */ &byteCount ); // (go) 2803 } 2804 2805 dkreadwritecompletion(dkr, (void *)dkrtype, status, byteCount); 2806 } 2807 2808 return minor->media->errnoFromReturn(status); // (return error status) 2809 2810dkreadwriteErr: 2811 2812 dkreadwritecompletion(dkr, (void *)dkrtype, status, 0); 2813 2814 return minor->media->errnoFromReturn(status); // (return error status) 2815} 2816 2817void dkreadwritecompletion( void * target, 2818 void * parameter, 2819 IOReturn status, 2820 UInt64 actualByteCount ) 2821{ 2822 // 2823 // dkreadwritecompletion cleans up after a read or write operation. 2824 // 2825 2826 dkr_t dkr = (dkr_t) target; 2827 dkrtype_t dkrtype = (dkrtype_t) (uintptr_t) parameter; 2828 dev_t dev = DKR_GET_DEV(dkr, dkrtype); 2829 void * drvdata = DKR_GET_DRIVER_DATA(dkr, dkrtype); 2830 MinorSlot * minor = gIOMediaBSDClientGlobals.getMinor(getminor(dev)); 2831 2832 if ( drvdata ) // (has a buffer?) 2833 { 2834 IOMemoryDescriptor * buffer = (IOMemoryDescriptor *) drvdata; 2835 2836 buffer->complete(); // (complete the buffer) 2837 buffer->release(); // (release our retain on the buffer) 2838 } 2839 2840 if ( status != kIOReturnSuccess ) // (has an error?) 2841 { 2842 if ( status != kIOReturnNotPermitted ) 2843 { 2844 IOLog("%s: %s.\n", minor->name, minor->media->stringFromReturn(status)); 2845 } 2846 } 2847 2848 if ( DKR_IS_ASYNCHRONOUS(dkr, dkrtype) ) // (an asynchronous request?) 2849 { 2850 DKR_SET_BYTE_COUNT(dkr, dkrtype, actualByteCount); // (set byte count) 2851 DKR_RUN_COMPLETION(dkr, dkrtype, status); // (run completion) 2852 } 2853 else 2854 { 2855 DKR_SET_BYTE_COUNT(dkr, dkrtype, actualByteCount); // (set byte count) 2856 } 2857} 2858///w:start 2859#if !TARGET_OS_EMBEDDED 2860void dkreadwriteassertion(thread_call_param_t param0, thread_call_param_t param1) 2861{ 2862 AbsoluteTime assertionTime; 2863 2864 gIOMediaBSDClientGlobals.lockAssertion(); 2865 2866 assertionTime = gIOMediaBSDClientGlobals.getAssertionTime(); 2867 2868 if ( __OSAbsoluteTime(assertionTime) < mach_absolute_time() ) 2869 { 2870 IOPMDriverAssertionID assertionID; 2871 2872 assertionID = gIOMediaBSDClientGlobals.getAssertionID(); 2873 2874 IOService::getPMRootDomain()->releasePMAssertion(assertionID); 2875 2876 gIOMediaBSDClientGlobals.setAssertionID(kIOPMUndefinedDriverAssertionID); 2877 } 2878 else 2879 { 2880 thread_call_enter_delayed( 2881 /* call */ gIOMediaBSDClientGlobals.getAssertionCall(), 2882 /* deadline */ assertionTime ); 2883 } 2884 2885 gIOMediaBSDClientGlobals.unlockAssertion(); 2886} 2887#endif /* !TARGET_OS_EMBEDDED */ 2888///w:stop 2889 2890// ============================================================================= 2891// AnchorTable Class 2892 2893AnchorTable::AnchorTable() 2894{ 2895 // 2896 // Initialize this object's minimal state. 2897 // 2898 2899 _table = 0; 2900 _tableCount = 0; 2901} 2902 2903AnchorTable::~AnchorTable() 2904{ 2905 // 2906 // Free all of this object's outstanding resources. 2907 // 2908 2909 for ( UInt32 anchorID = 0; anchorID < _tableCount; anchorID++ ) 2910 if ( _table[anchorID].isAssigned ) remove(anchorID); 2911 2912 if ( _table ) IODelete(_table, AnchorSlot, _tableCount); 2913} 2914 2915UInt32 AnchorTable::insert(IOService * anchor, void * key) 2916{ 2917 // 2918 // This method inserts the specified anchor into an unassigned slot in the 2919 // anchor table and returns its ID (or kInvalidAnchorID on a failure). 2920 // 2921 // Note that the anchor is transparently removed from the table should the 2922 // anchor terminate (or it is at least marked obsolete, should references 2923 // to the anchor still exist in the minor table). 2924 // 2925 2926 UInt32 anchorID; 2927 IONotifier * notifier; 2928 2929 // Search for an unassigned slot in the anchor table. 2930 2931 for ( anchorID = 0; anchorID < _tableCount; anchorID++ ) 2932 if ( _table[anchorID].isAssigned == false ) break; 2933 2934 // Was an unassigned slot found? If not, grow the table. 2935 2936 if ( anchorID == _tableCount ) 2937 { 2938 AnchorSlot * newTable; 2939 UInt32 newTableCount; 2940 2941 // We must expand the anchor table since no more slots are available. 2942 2943 if ( _tableCount >= kAnchorsMaxCount ) return kInvalidAnchorID; 2944 2945 newTableCount = min(kAnchorsAddCount + _tableCount, kAnchorsMaxCount); 2946 newTable = IONew(AnchorSlot, newTableCount); 2947 2948 if ( newTable == 0 ) return kInvalidAnchorID; 2949 2950 bzero(newTable, newTableCount * sizeof(AnchorSlot)); 2951 2952 // Copy over the old table's entries, then free the old table. 2953 2954 if ( _table ) 2955 { 2956 bcopy(_table, newTable, _tableCount * sizeof(AnchorSlot)); 2957 IODelete(_table, AnchorSlot, _tableCount); 2958 } 2959 2960 // Obtain the next unassigned index (simple since we know the size of 2961 // the old table), then update our instance variables to reflect the 2962 // new tables. 2963 2964 anchorID = _tableCount; 2965 _table = newTable; 2966 _tableCount = newTableCount; 2967 } 2968 2969 // Create a notification handler for the anchor's termination (post-stop); 2970 // the handler will remove the anchor transparently from the table if the 2971 // anchor terminates (or at least marks it obsolete, if references to the 2972 // anchor still exist in the minor table). 2973 2974 notifier = anchor->registerInterest( 2975 /* type */ gIOGeneralInterest, 2976 /* action */ anchorWasNotified, 2977 /* target */ this, 2978 /* parameter */ 0 ); 2979 2980 if ( notifier == 0 ) return kInvalidAnchorID; 2981 2982 // Zero the new slot, fill it in, and retain the anchor object. 2983 2984 bzero(&_table[anchorID], sizeof(AnchorSlot)); // (zero slot) 2985 2986 _table[anchorID].isAssigned = true; // (fill in slot) 2987 _table[anchorID].isObsolete = false; 2988 _table[anchorID].anchor = anchor; 2989 _table[anchorID].key = key; 2990 _table[anchorID].notifier = notifier; 2991 2992 _table[anchorID].anchor->retain(); // (retain anchor) 2993 2994 return anchorID; 2995} 2996 2997void AnchorTable::remove(UInt32 anchorID) 2998{ 2999 // 3000 // This method removes the specified anchor from the anchor table. 3001 // 3002 3003 assert(anchorID < _tableCount); 3004 assert(_table[anchorID].isAssigned); 3005 3006 // Release the resources retained in the anchor slot and zero it. 3007 3008 _table[anchorID].notifier->remove(); 3009 _table[anchorID].anchor->release(); // (release anchor) 3010 3011 bzero(&_table[anchorID], sizeof(AnchorSlot)); // (zero slot) 3012} 3013 3014void AnchorTable::obsolete(UInt32 anchorID) 3015{ 3016 // 3017 // This method obsoletes the specified anchor, that is, the slot is marked 3018 // as obsolete and will be removed later via the minor table remove method 3019 // once it detects references to the anchor ID drop to 0. Once obsoleted, 3020 // the anchor can be considered to be removed, since it will not appear in 3021 // locate searches, even though behind the scenes it still occupies a slot. 3022 // 3023 3024 assert(anchorID < _tableCount); 3025 assert(_table[anchorID].isAssigned); 3026 3027 // Mark the anchor as obsolete so that it can be removed from the table as 3028 // soon as all its references go away (minor table's responsibility). 3029 3030 _table[anchorID].isObsolete = true; 3031} 3032 3033UInt32 AnchorTable::locate(IOService * anchor) 3034{ 3035 // 3036 // This method searches for the specified anchor in the anchor table and 3037 // returns its ID (or kInvalidAnchorID on a failure). It would find the 3038 // first occurrence of the anchor in case multiple entries with the same 3039 // anchor object exist. It ignores slots marked as obsolete. 3040 // 3041 3042 for (UInt32 anchorID = 0; anchorID < _tableCount; anchorID++) 3043 { 3044 if ( _table[anchorID].isAssigned != false && 3045 _table[anchorID].isObsolete == false && 3046 _table[anchorID].anchor == anchor ) return anchorID; 3047 } 3048 3049 return kInvalidAnchorID; 3050} 3051 3052UInt32 AnchorTable::locate(IOService * anchor, void * key) 3053{ 3054 // 3055 // This method searches for the specified anchor and key pair in the anchor 3056 // table and returns its ID (or kInvalidAnchorID on a failure). It ignores 3057 // slots marked as obsolete. 3058 // 3059 3060 for (UInt32 anchorID = 0; anchorID < _tableCount; anchorID++) 3061 { 3062 if ( _table[anchorID].isAssigned != false && 3063 _table[anchorID].isObsolete == false && 3064 _table[anchorID].anchor == anchor && 3065 _table[anchorID].key == key ) return anchorID; 3066 } 3067 3068 return kInvalidAnchorID; 3069} 3070 3071UInt32 AnchorTable::update(IOService * anchor, void * key) 3072{ 3073 // 3074 // This method searches for the specified anchor in the anchor table and 3075 // updates its key value if no references to it exist in the minor table 3076 // or if the references in the minor table are all obsolete. It returns 3077 // the updated anchor ID (or kInvalidAnchorID on a failure). It ignores 3078 // slots marked as obsolete. 3079 // 3080 3081 MinorTable * minors = gIOMediaBSDClientGlobals.getMinors(); 3082 3083 for (UInt32 anchorID = 0; anchorID < _tableCount; anchorID++) 3084 { 3085 if ( _table[anchorID].isAssigned != false && 3086 _table[anchorID].isObsolete == false && 3087 _table[anchorID].anchor == anchor ) 3088 { 3089 if ( minors->hasReferencesToAnchorID(anchorID, true) == false ) 3090 { 3091 _table[anchorID].key = key; 3092 return anchorID; 3093 } 3094 } 3095 } 3096 3097 return kInvalidAnchorID; 3098} 3099 3100bool AnchorTable::isObsolete(UInt32 anchorID) 3101{ 3102 // 3103 // Determine whether the specified anchor ID is marked as obsolete. 3104 // 3105 3106 assert(anchorID < _tableCount); 3107 assert(_table[anchorID].isAssigned); 3108 3109 return _table[anchorID].isObsolete ? true : false; 3110} 3111 3112IOReturn AnchorTable::anchorWasNotified( void * /* target */, 3113 void * /* parameter */, 3114 UInt32 messageType, 3115 IOService * anchor, 3116 void * /* messageArgument */, 3117 vm_size_t /* messageArgumentSize */ ) 3118{ 3119 // 3120 // Notification handler for anchors. 3121 // 3122 3123 AnchorTable * anchors = gIOMediaBSDClientGlobals.getAnchors(); 3124 UInt32 anchorID; 3125 MinorTable * minors = gIOMediaBSDClientGlobals.getMinors(); 3126 3127 // Determine whether this is a termination notification (post-stop). 3128 3129 if ( messageType != kIOMessageServiceIsTerminated ) 3130 return kIOReturnSuccess; 3131 3132 // Disable access to tables. 3133 3134 gIOMediaBSDClientGlobals.lockState(); 3135 3136 // Determine whether this anchor is in the anchor table (obsolete occurences 3137 // are skipped in the search, as appropriate, since those anchor IDs will be 3138 // removed as it is). 3139 3140 while ( (anchorID = anchors->locate(anchor)) != kInvalidAnchorID ) 3141 { 3142 // Determine whether this anchor still has references from the minor 3143 // table. If it does, we mark the the anchor as obsolete so that it 3144 // will be removed later, once references to it go to zero (which is 3145 // handled by MinorTable::remove). 3146 3147 if ( minors->hasReferencesToAnchorID(anchorID, false) ) 3148 anchors->obsolete(anchorID); 3149 else 3150 anchors->remove(anchorID); 3151 } 3152 3153 // Enable access to tables. 3154 3155 gIOMediaBSDClientGlobals.unlockState(); 3156 3157 return kIOReturnSuccess; 3158} 3159 3160// ============================================================================= 3161// MinorTable Class 3162 3163MinorTable::MinorTable() 3164{ 3165 // 3166 // Initialize this object's minimal state. 3167 // 3168 3169 _table.buckets = IONew(MinorSlot *, kMinorsBucketCount); 3170 _tableCount = 0; 3171 3172 if ( _table.buckets ) 3173 bzero(_table.buckets, kMinorsBucketCount * sizeof(MinorSlot *)); 3174} 3175 3176MinorTable::~MinorTable() 3177{ 3178 // 3179 // Free all of this object's outstanding resources. 3180 // 3181 3182 for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ ) 3183 if ( _table[minorID].isAssigned ) remove(minorID); 3184 3185 if ( _table.buckets ) 3186 { 3187 for ( UInt32 bucketID = 0; _table.buckets[bucketID]; bucketID++ ) 3188 IODelete(_table.buckets[bucketID], MinorSlot, kMinorsAddCount); 3189 3190 IODelete(_table.buckets, MinorSlot *, kMinorsBucketCount); 3191 } 3192} 3193 3194UInt32 MinorTable::insert( IOMedia * media, 3195 UInt32 anchorID, 3196 IOMediaBSDClient * client, 3197 char * slicePath ) 3198{ 3199 // 3200 // This method inserts the specified media/anchorID pair into an unassigned 3201 // slot in the minor table and returns its ID (or kInvalidMinorID on error). 3202 // 3203 // Note that the bdev and cdev nodes are published as a result of this call, 3204 // with the name "[r]disk<anchorID><slicePath>". For instance, "disk2s3s1" 3205 // for an anchorID of 2 and slicePath of "s3s1". 3206 // 3207 3208 void * bdevNode; 3209 void * cdevNode; 3210 UInt32 majorID = gIOMediaBSDClientGlobals.getMajorID(); 3211 UInt32 minorID; 3212 char * minorName; 3213 UInt32 minorNameSize; 3214 3215 if ( _table.buckets == 0 ) return kInvalidMinorID; 3216 3217 // Search for an unassigned slot in the minor table. 3218 3219 for ( minorID = 0; minorID < _tableCount; minorID++ ) 3220 if ( _table[minorID].isAssigned == false ) break; 3221 3222 // Was an unassigned slot found? If not, grow the table. 3223 3224 if ( minorID == _tableCount ) 3225 { 3226 UInt32 bucketID = _tableCount / kMinorsAddCount; 3227 3228 // We must expand the minor table since no more slots are available. 3229 3230 if ( bucketID >= kMinorsBucketCount ) return kInvalidMinorID; 3231 3232 _table.buckets[bucketID] = IONew(MinorSlot, kMinorsAddCount); 3233 3234 if ( _table.buckets[bucketID] == 0 ) return kInvalidMinorID; 3235 3236 bzero(_table.buckets[bucketID], kMinorsAddCount * sizeof(MinorSlot)); 3237 3238 _tableCount += kMinorsAddCount; 3239 } 3240 3241 // Create a buffer large enough to hold the full name of the minor. 3242 3243 minorNameSize = strlen("disk#"); 3244 for (unsigned temp = anchorID; temp >= 10; temp /= 10) minorNameSize++; 3245 minorNameSize += strlen(slicePath); 3246 minorNameSize += 1; 3247 minorName = IONew(char, minorNameSize); 3248 3249 // Create a block and character device node in BSD for this media. 3250 3251 bdevNode = devfs_make_node( /* dev */ makedev(majorID, minorID), 3252 /* type */ DEVFS_BLOCK, 3253 /* owner */ UID_ROOT, 3254 /* group */ GID_OPERATOR, 3255 /* permission */ 0640, 3256 /* name (fmt) */ "disk%d%s", 3257 /* name (arg) */ anchorID, 3258 /* name (arg) */ slicePath ); 3259 3260 cdevNode = devfs_make_node( /* dev */ makedev(majorID, minorID), 3261 /* type */ DEVFS_CHAR, 3262 /* owner */ UID_ROOT, 3263 /* group */ GID_OPERATOR, 3264 /* permission */ 0640, 3265 /* name (fmt) */ "rdisk%d%s", 3266 /* name (arg) */ anchorID, 3267 /* name (arg) */ slicePath ); 3268 3269 if ( minorName == 0 || bdevNode == 0 || cdevNode == 0 ) 3270 { 3271 if ( cdevNode ) devfs_remove(cdevNode); 3272 if ( bdevNode ) devfs_remove(bdevNode); 3273 if ( minorName ) IODelete(minorName, char, minorNameSize); 3274 3275 return kInvalidMinorID; 3276 } 3277 3278 // Construct a name for the node. 3279 3280 snprintf(minorName, minorNameSize, "disk%d%s", (int) anchorID, slicePath); 3281 assert(strlen(minorName) + 1 == minorNameSize); 3282 3283 // Zero the new slot, fill it in, and retain the appropriate objects. 3284 3285 bzero(&_table[minorID], sizeof(MinorSlot)); // (zero slot) 3286 3287 _table[minorID].isAssigned = true; // (fill in slot) 3288 _table[minorID].isObsolete = false; 3289 _table[minorID].isOrphaned = false; 3290 _table[minorID].anchorID = anchorID; 3291 _table[minorID].client = client; 3292 _table[minorID].media = media; 3293 _table[minorID].name = minorName; 3294 _table[minorID].bdevBlockSize = media->getPreferredBlockSize(); 3295 _table[minorID].bdevNode = bdevNode; 3296 _table[minorID].bdevOpen = 0; 3297 _table[minorID].bdevOpenLevel = kIOStorageAccessNone; 3298 _table[minorID].cdevNode = cdevNode; 3299 _table[minorID].cdevOpen = 0; 3300 _table[minorID].cdevOpenLevel = kIOStorageAccessNone; 3301#if TARGET_OS_EMBEDDED 3302 _table[minorID].cdevOptions = 0; 3303#endif /* TARGET_OS_EMBEDDED */ 3304 3305 _table[minorID].client->retain(); // (retain client) 3306 _table[minorID].media->retain(); // (retain media) 3307 3308 return minorID; 3309} 3310 3311void MinorTable::remove(UInt32 minorID) 3312{ 3313 // 3314 // This method removes the specified minor from the minor table. 3315 // 3316 3317 UInt32 anchorID; 3318 3319 assert(minorID < _tableCount); 3320 assert(_table[minorID].isAssigned); 3321 3322 assert(_table[minorID].isOrphaned == false); 3323 assert(_table[minorID].bdevOpen == 0); 3324 assert(_table[minorID].cdevOpen == 0); 3325 3326 anchorID = _table[minorID].anchorID; 3327 3328 // Release the resources retained in the minor slot and zero it. 3329 3330 devfs_remove(_table[minorID].cdevNode); 3331 devfs_remove(_table[minorID].bdevNode); 3332 IODelete(_table[minorID].name, char, strlen(_table[minorID].name) + 1); 3333 _table[minorID].client->release(); // (release client) 3334 _table[minorID].media->release(); // (release media) 3335 3336 bzero(&_table[minorID], sizeof(MinorSlot)); // (zero slot) 3337 3338 // Determine whether the associated anchor ID is marked as obsolete. If it 3339 // is and there are no other references to the anchor ID in the minor table, 3340 // we remove the anchor ID from the anchor table. 3341 3342 if ( gIOMediaBSDClientGlobals.getAnchors()->isObsolete(anchorID) ) 3343 { 3344 if ( hasReferencesToAnchorID(anchorID, false) == false ) 3345 gIOMediaBSDClientGlobals.getAnchors()->remove(anchorID); 3346 } 3347} 3348 3349UInt32 MinorTable::update( IOMedia * media, 3350 UInt32 anchorID, 3351 IOMediaBSDClient * client, 3352 char * slicePath ) 3353{ 3354 // 3355 // This method searches for the specified anchor ID and slice path pair in 3356 // the minor table and updates it. An update would be an unusual occasion 3357 // as new anchors are assigned when two media trees are found to share the 3358 // same anchor. It would occur in one specific circumstance: on the minor 3359 // slot through which a DKIOCFORMAT was issued. The minor slot would have 3360 // been marked in "open flux", the format would have been issued, then the 3361 // media objects terminated, the minor slot marked obsolete, and the media 3362 // objects republished. The anchor ID would have one reference, the minor 3363 // slot with the DKIOCFORMAT still outstanding. AnchorTable::update would 3364 // notice the one reference is orphaned and accept the reuse of the anchor 3365 // ID. MinorTable::update would notice the orphaned minor slot and update 3366 // it with the new media object and media bsd client object, and clear its 3367 // obsolete state and "open flux" state, once the new media object arrives. 3368 // 3369 3370 UInt32 minorID; 3371 char * minorName; 3372 UInt32 minorNameSize; 3373 3374 // Create a buffer large enough to hold the full name of the minor. 3375 3376 minorNameSize = strlen("disk#"); 3377 for (unsigned temp = anchorID; temp >= 10; temp /= 10) minorNameSize++; 3378 minorNameSize += strlen(slicePath); 3379 minorNameSize += 1; 3380 minorName = IONew(char, minorNameSize); 3381 3382 if ( minorName == 0 ) return kInvalidMinorID; 3383 3384 // Construct a name for the node. 3385 3386 snprintf(minorName, minorNameSize, "disk%d%s", (int) anchorID, slicePath); 3387 assert(strlen(minorName) + 1 == minorNameSize); 3388 3389 // Search for an orphaned slot in the minor table with our minor name. 3390 3391 for ( minorID = 0; minorID < _tableCount; minorID++ ) 3392 { 3393 if ( _table[minorID].isAssigned != false && 3394 _table[minorID].isObsolete != false && 3395 _table[minorID].isOrphaned != false && 3396 _table[minorID].anchorID == anchorID && 3397 strcmp(_table[minorID].name, minorName) == 0 ) break; 3398 } 3399 3400 IODelete(minorName, char, minorNameSize); 3401 3402 if ( minorID == _tableCount ) return kInvalidMinorID; 3403 3404 // Update the slot and retain the appropriate objects. 3405 3406 _table[minorID].client->release(); // (release client) 3407 _table[minorID].media->release(); // (release media) 3408 3409 _table[minorID].isObsolete = false; // (update slot) 3410 _table[minorID].isOrphaned = false; 3411 _table[minorID].client = client; 3412 _table[minorID].media = media; 3413 3414 _table[minorID].client->retain(); // (retain client) 3415 _table[minorID].media->retain(); // (retain media) 3416 3417 return minorID; 3418} 3419 3420UInt32 MinorTable::locate(IOMedia * media) 3421{ 3422 // 3423 // This method searches for the specified media in the minor table and 3424 // returns its ID (or kInvalidMinorID on an error). It ignores slots 3425 // marked as obsolete. 3426 // 3427 3428 for (UInt32 minorID = 0; minorID < _tableCount; minorID++) 3429 { 3430 if ( _table[minorID].isAssigned != false && 3431 _table[minorID].isObsolete == false && 3432 _table[minorID].media == media ) return minorID; 3433 } 3434 3435 return kInvalidMinorID; 3436} 3437 3438UInt32 MinorTable::getOpenCountForAnchorID(UInt32 anchorID) 3439{ 3440 // 3441 // This method obtains a count of opens on the minors associated with the 3442 // specified anchor ID. A block device open is counted separately from a 3443 // character device open. 3444 // 3445 3446 UInt32 opens = 0; 3447 3448 for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ ) 3449 { 3450 if ( _table[minorID].isAssigned != false && 3451 _table[minorID].anchorID == anchorID ) 3452 { 3453 opens += _table[minorID].bdevOpen; 3454 opens += _table[minorID].cdevOpen; 3455 } 3456 } 3457 3458 return opens; 3459} 3460 3461bool MinorTable::hasReferencesToAnchorID(UInt32 anchorID, bool excludeOrphans) 3462{ 3463 // 3464 // This method determines whether there are assigned minors in the minor 3465 // table that refer to the specified anchor ID. It ignores slots marked 3466 // as obsolete and orphaned, unless excludeOrphans is false. 3467 // 3468 3469 for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ ) 3470 { 3471 if ( _table[minorID].isAssigned != false && 3472 _table[minorID].anchorID == anchorID ) 3473 { 3474 if ( excludeOrphans == false ) return true; 3475 if ( _table[minorID].isObsolete == false ) return true; 3476 if ( _table[minorID].isOrphaned == false ) return true; 3477 } 3478 } 3479 3480 return false; 3481} 3482 3483MinorSlot * MinorTable::getMinor(UInt32 minorID) 3484{ 3485 // 3486 // Obtain the structure describing the specified minor. 3487 // 3488 3489 if ( minorID < _tableCount && _table[minorID].isAssigned ) 3490 return &_table[minorID]; 3491 else 3492 return 0; 3493} 3494 3495void MinorTable::obsolete(UInt32 minorID) 3496{ 3497 // 3498 // This method obsoletes the specified minor, that is, the slot is marked 3499 // as obsolete and will be removed later via the dkclose function once it 3500 // detects the last close arrive. Once obsoleted, the minor can be cons- 3501 // idered to be removed, since it will not appear in locate searches. 3502 // 3503 3504 assert(minorID < _tableCount); 3505 assert(_table[minorID].isAssigned); 3506 3507 // Mark the minor as obsolete so that it can be removed from the table as 3508 // soon as the last close arrives (dkclose function's responsibility). 3509 3510 _table[minorID].isObsolete = true; 3511} 3512 3513bool MinorTable::isObsolete(UInt32 minorID) 3514{ 3515 // 3516 // Determine whether the specified minor ID is marked as obsolete. 3517 // 3518 3519 assert(minorID < _tableCount); 3520 assert(_table[minorID].isAssigned); 3521 3522 return _table[minorID].isObsolete ? true : false; 3523} 3524 3525// ============================================================================= 3526// IOMediaBSDClientGlobals Class 3527 3528static int devsw_add(int index, struct bdevsw * bsw, struct cdevsw * csw) 3529{ 3530 for ( index = bdevsw_isfree(index); index != -1; index++, index = bdevsw_isfree(-index) ) 3531 { 3532 int bdevsw_index; 3533 3534 bdevsw_index = bdevsw_add(index, bsw); 3535 3536 if (bdevsw_index == index) 3537 { 3538 int cdevsw_index; 3539 3540 cdevsw_index = cdevsw_add_with_bdev(index, csw, index); 3541 3542 if (cdevsw_index == index) 3543 { 3544 break; 3545 } 3546 3547 bdevsw_remove(bdevsw_index, bsw); 3548 } 3549 } 3550 3551 return index; 3552} 3553 3554static int devsw_remove(int index, struct bdevsw * bsw, struct cdevsw * csw) 3555{ 3556 index = bdevsw_remove(index, bsw); 3557 3558 if (index != -1) 3559 { 3560 index = cdevsw_remove(index, csw); 3561 } 3562 3563 return index; 3564} 3565 3566IOMediaBSDClientGlobals::IOMediaBSDClientGlobals() 3567{ 3568 // 3569 // Initialize the minimal global state. 3570 // 3571 3572 _anchors = new AnchorTable(); 3573 _minors = new MinorTable(); 3574 3575 _majorID = devsw_add(-1, &bdevswFunctions, &cdevswFunctions); 3576 3577 _openLock = IOLockAlloc(); 3578 _stateLock = IOLockAlloc(); 3579///w:start 3580#if !TARGET_OS_EMBEDDED 3581 _assertionCall = thread_call_allocate(dkreadwriteassertion, NULL); 3582 _assertionID = kIOPMUndefinedDriverAssertionID; 3583 _assertionLock = IOLockAlloc(); 3584#endif /* !TARGET_OS_EMBEDDED */ 3585///w:stop 3586} 3587 3588IOMediaBSDClientGlobals::~IOMediaBSDClientGlobals() 3589{ 3590 // 3591 // Free all of the outstanding global resources. 3592 // 3593 3594///w:start 3595#if !TARGET_OS_EMBEDDED 3596 if ( _assertionCall ) thread_call_free(_assertionCall); 3597 if ( _assertionLock ) IOLockFree(_assertionLock); 3598#endif /* !TARGET_OS_EMBEDDED */ 3599///w:stop 3600 if ( _openLock ) IOLockFree(_openLock); 3601 if ( _stateLock ) IOLockFree(_stateLock); 3602 3603 if ( _majorID != kInvalidMajorID ) devsw_remove(_majorID, &bdevswFunctions, &cdevswFunctions); 3604 3605 if ( _minors ) delete _minors; 3606 if ( _anchors ) delete _anchors; 3607} 3608 3609AnchorTable * IOMediaBSDClientGlobals::getAnchors() 3610{ 3611 // 3612 // Obtain the table of anchors. 3613 // 3614 3615 return _anchors; 3616} 3617 3618MinorTable * IOMediaBSDClientGlobals::getMinors() 3619{ 3620 // 3621 // Obtain the table of minors. 3622 // 3623 3624 return _minors; 3625} 3626 3627MinorSlot * IOMediaBSDClientGlobals::getMinor(UInt32 minorID) 3628{ 3629 // 3630 // Obtain information for the specified minor ID. 3631 // 3632 3633 return _minors->getMinor(minorID); 3634} 3635 3636UInt32 IOMediaBSDClientGlobals::getMajorID() 3637{ 3638 // 3639 // Obtain the major ID. 3640 // 3641 3642 return _majorID; 3643} 3644 3645bool IOMediaBSDClientGlobals::isValid() 3646{ 3647 // 3648 // Determine whether the minimal global state has been initialized. 3649 // 3650 3651 return ( _anchors ) && 3652 ( _minors ) && 3653 ( _majorID != kInvalidMajorID ) && 3654///w:start 3655#if !TARGET_OS_EMBEDDED 3656 ( _assertionCall ) && 3657 ( _assertionLock ) && 3658#endif /* !TARGET_OS_EMBEDDED */ 3659///w:stop 3660 ( _openLock ) && 3661 ( _stateLock ); 3662} 3663 3664void IOMediaBSDClientGlobals::lockOpen() 3665{ 3666 // 3667 // Disable access to the opens and closes. 3668 // 3669 3670 IOLockLock(_openLock); 3671} 3672 3673void IOMediaBSDClientGlobals::unlockOpen() 3674{ 3675 // 3676 // Enable access to the opens and closes. 3677 // 3678 3679 IOLockUnlock(_openLock); 3680} 3681 3682void IOMediaBSDClientGlobals::lockState() 3683{ 3684 // 3685 // Disable access to the global state. 3686 // 3687 3688 IOLockLock(_stateLock); 3689} 3690 3691void IOMediaBSDClientGlobals::unlockState() 3692{ 3693 // 3694 // Enable access to the global state. 3695 // 3696 3697 IOLockUnlock(_stateLock); 3698} 3699///w:start 3700#if !TARGET_OS_EMBEDDED 3701thread_call_t IOMediaBSDClientGlobals::getAssertionCall() 3702{ 3703 return _assertionCall; 3704} 3705 3706IOPMDriverAssertionID IOMediaBSDClientGlobals::getAssertionID() 3707{ 3708 return _assertionID; 3709} 3710 3711void IOMediaBSDClientGlobals::setAssertionID(IOPMDriverAssertionID assertionID) 3712{ 3713 _assertionID = assertionID; 3714} 3715 3716AbsoluteTime IOMediaBSDClientGlobals::getAssertionTime() 3717{ 3718 return _assertionTime; 3719} 3720 3721void IOMediaBSDClientGlobals::setAssertionTime(AbsoluteTime assertionTime) 3722{ 3723 _assertionTime = assertionTime; 3724} 3725 3726void IOMediaBSDClientGlobals::lockAssertion() 3727{ 3728 IOLockLock(_assertionLock); 3729} 3730 3731void IOMediaBSDClientGlobals::unlockAssertion() 3732{ 3733 IOLockUnlock(_assertionLock); 3734} 3735#endif /* !TARGET_OS_EMBEDDED */ 3736///w:stop 3737