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 25//------------------------------------------------------------------------------------------------- 26// Includes 27//------------------------------------------------------------------------------------------------- 28 29#include <IOKit/IOLib.h> 30#include <IOKit/IOKitKeys.h> 31#include <IOKit/storage/IOBlockStorageDriver.h> 32#include "IOUFIStorageServices.h" 33 34 35//------------------------------------------------------------------------------------------------- 36// Macros 37//------------------------------------------------------------------------------------------------- 38 39#if ( USB_MASS_STORAGE_DEBUG == 1 ) 40#define PANIC_NOW(x) panic x 41// Override the debug level for USBLog to make sure our logs make it out and then import 42// the logging header. 43#define DEBUG_LEVEL 1 44#include <IOKit/usb/IOUSBLog.h> 45#define STATUS_LOG(x) USBLog x 46#else 47#define PANIC_NOW(x) 48#define STATUS_LOG(x) 49#endif 50 51// The command should be tried 5 times. The original attempt 52// plus 4 retries. 53#define kNumberRetries 4 54 55// Default I/O size values. 56enum 57{ 58 kMaximumBlockCountRead = 128, 59 kMaximumBlockCountWrite = 128, 60 kMaximumByteCountRead = 65536, 61 kMaximumByteCountWrite = 65536 62}; 63 64// Structure for the asynch client data 65struct BlockServicesClientData 66{ 67 68 // The object that owns the copy of this structure. 69 IOUFIStorageServices * owner; 70 71 // The request parameters provided by the client. 72 IOStorageCompletion completionData; 73 IOMemoryDescriptor * clientBuffer; 74 UInt32 clientStartingBlock; 75 UInt32 clientRequestedBlockCount; 76 UInt32 clientRequestedBlockSize; 77 78 // The internally needed parameters. 79 UInt32 retriesLeft; 80 81}; 82 83typedef struct BlockServicesClientData BlockServicesClientData; 84 85#define super IOBlockStorageDevice 86OSDefineMetaClassAndStructors ( IOUFIStorageServices, IOBlockStorageDevice ); 87 88 89//------------------------------------------------------------------------------------------------- 90// attach - attach to provider. [PROTECTED] 91//------------------------------------------------------------------------------------------------- 92 93bool 94IOUFIStorageServices::attach ( IOService * provider ) 95{ 96 97 OSDictionary * scsiCharacterDict = NULL; 98 99 100 STATUS_LOG ( ( 6, "%s[%p]:: attach called", getName(), this ) ); 101 102 if ( !super::attach ( provider ) ) 103 { 104 return false; 105 } 106 107 fProvider = OSDynamicCast ( IOUSBMassStorageUFIDevice, provider ); 108 if ( fProvider == NULL ) 109 { 110 111 STATUS_LOG ( ( 1, "%s[%p]:: attach; wrong provider type!", getName(), this ) ); 112 return false; 113 114 } 115 116 setProperty ( kIOPropertyProtocolCharacteristicsKey, fProvider->GetProtocolCharacteristicsDictionary ( ) ); 117 setProperty ( kIOPropertyDeviceCharacteristicsKey, fProvider->GetDeviceCharacteristicsDictionary ( ) ); 118 119 // Check for a SCSI Device Characteristics dictionary, if not present, set default values. 120 scsiCharacterDict = OSDynamicCast ( OSDictionary, fProvider->getProperty( kIOPropertySCSIDeviceCharacteristicsKey ) ); 121 if ( scsiCharacterDict == NULL ) 122 { 123 124 setProperty ( kIOMaximumBlockCountReadKey, kMaximumBlockCountRead ); 125 setProperty ( kIOMaximumBlockCountWriteKey, kMaximumBlockCountWrite ); 126 setProperty ( kIOMaximumByteCountReadKey, kMaximumByteCountRead ); 127 setProperty ( kIOMaximumByteCountWriteKey, kMaximumByteCountWrite ); 128 129 } 130 else 131 { 132 133 OSNumber * number = NULL; 134 UInt32 maxBlockCount = 0; 135 UInt64 maxByteCount = 0; 136 137 138 // Set a max block read count, favor SCSI Characteristics property if present. 139 maxBlockCount = kMaximumBlockCountRead; 140 number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumBlockCountReadKey ) ); 141 if ( number != NULL ) 142 { 143 144 maxBlockCount = number->unsigned32BitValue ( ); 145 if ( maxBlockCount == 0 ) 146 { 147 maxBlockCount = kMaximumBlockCountRead; 148 } 149 150 } 151 152 setProperty ( kIOMaximumBlockCountReadKey, maxBlockCount ); 153 154 // Set a max block write count, favor SCSI Characteristics property if present. 155 maxBlockCount = kMaximumBlockCountWrite; 156 number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumBlockCountWriteKey ) ); 157 if ( number != NULL ) 158 { 159 160 maxBlockCount = number->unsigned32BitValue ( ); 161 if ( maxBlockCount == 0 ) 162 { 163 maxBlockCount = kMaximumBlockCountWrite; 164 } 165 166 } 167 168 setProperty ( kIOMaximumBlockCountWriteKey, maxBlockCount ); 169 170 // Set a max byte read count, favor SCSI Characteristics property if present. 171 maxByteCount = kMaximumByteCountRead; 172 number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumByteCountReadKey ) ); 173 if ( number != NULL ) 174 { 175 176 maxByteCount = number->unsigned32BitValue ( ); 177 if ( maxByteCount == 0 ) 178 { 179 maxByteCount = kMaximumByteCountRead; 180 } 181 182 } 183 184 setProperty ( kIOMaximumByteCountReadKey, maxByteCount ); 185 186 // Set a max byte write count, favor SCSI Characteristics property if present. 187 maxByteCount = kMaximumByteCountWrite; 188 number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumByteCountWriteKey ) ); 189 if ( number != NULL ) 190 { 191 192 maxByteCount = number->unsigned32BitValue ( ); 193 if ( maxByteCount == 0 ) 194 { 195 maxByteCount = kMaximumByteCountWrite; 196 } 197 198 } 199 200 setProperty ( kIOMaximumByteCountWriteKey, maxByteCount ); 201 202 } 203 204 fMediaChanged = false; 205 fMediaPresent = false; 206 207 STATUS_LOG ( ( 6, "%s[%p]:: attach exiting", getName(), this ) ); 208 209 return true; 210 211} 212 213 214//------------------------------------------------------------------------------------------------- 215// detach - detach from provider. [PROTECTED] 216//------------------------------------------------------------------------------------------------- 217 218void 219IOUFIStorageServices::detach( IOService * provider ) 220{ 221 222 STATUS_LOG ( ( 6, "%s[%p]: detach called", getName(), this ) ); 223 224 super::detach( provider ); 225 226 STATUS_LOG ( ( 6, "%s[%p]: detach exiting", getName(), this ) ); 227 228} 229 230 231//------------------------------------------------------------------------------------------------- 232// message - handles messages. [PUBLIC] 233//------------------------------------------------------------------------------------------------- 234 235IOReturn 236IOUFIStorageServices::message( UInt32 type, 237 IOService * nub, 238 void * arg ) 239{ 240 241 IOReturn status = kIOReturnSuccess; 242 243 244 STATUS_LOG ( ( 6, "%s[%p]::message called", getName(), this ) ); 245 246 switch ( type ) 247 { 248 249 case kIOMessageMediaStateHasChanged: 250 { 251 252 STATUS_LOG ( ( 5, "%s[%p]:: type = kIOMessageMediaStateHasChanged, nub = %p", getName(), this, nub ) ); 253 254 fMediaChanged = true; 255 fMediaPresent = true; 256 status = messageClients ( type, arg, sizeof ( IOMediaState ) ); 257 STATUS_LOG ( ( 5, "%s[%p]:: status = %ld", getName(), this, ( UInt32 ) status ) ); 258 259 } 260 break; 261 262 default: 263 { 264 status = super::message ( type, nub, arg ); 265 } 266 break; 267 268 } 269 270 return status; 271 272} 273 274 275//------------------------------------------------------------------------------------------------- 276// AsyncReadWriteComplete - Completion routine for I/O [STATIC][PRIVATE] 277//------------------------------------------------------------------------------------------------- 278 279void 280IOUFIStorageServices::AsyncReadWriteComplete ( void * clientData, 281 IOReturn status, 282 UInt64 actualByteCount ) 283{ 284 285 IOUFIStorageServices * owner; 286 BlockServicesClientData * servicesData; 287 IOStorageCompletion returnData; 288 bool commandComplete = true; 289 290 291 // Save the IOCompletion information so that it may be returned 292 // to the client. 293 servicesData = ( BlockServicesClientData * ) clientData; 294 returnData = servicesData->completionData; 295 owner = servicesData->owner; 296 297 STATUS_LOG ( ( 5, "%s[%p]:: AsyncReadWriteComplete; command status %x", owner->getName(), owner, status ) ); 298 // Check to see if an error occurred that on which the request should be retried. 299 if ( ( ( status != kIOReturnNotAttached ) && ( status != kIOReturnOffline ) && 300 ( status != kIOReturnSuccess ) ) && ( servicesData->retriesLeft > 0 ) ) 301 { 302 303 IOReturn requestStatus; 304 305 STATUS_LOG ( (5, "%s[%p]:: AsyncReadWriteComplete; retry command", owner->getName(), owner ) ); 306 // An error occurred, but it is one on which the command should be retried. Decrement 307 // the retry counter and try again. 308 servicesData->retriesLeft--; 309 requestStatus = owner->fProvider->AsyncReadWrite ( 310 servicesData->clientBuffer, 311 servicesData->clientStartingBlock, 312 servicesData->clientRequestedBlockCount, 313 servicesData->clientRequestedBlockSize, 314 clientData ); 315 if ( requestStatus != kIOReturnSuccess ) 316 { 317 commandComplete = true; 318 } 319 else 320 { 321 commandComplete = false; 322 } 323 324 } 325 326 if ( commandComplete == true ) 327 { 328 329 IOFree ( clientData, sizeof ( BlockServicesClientData ) ); 330 331 // Release the retains for this command. 332 owner->fProvider->release(); 333 owner->release(); 334 335 IOStorage::complete ( &returnData, status, actualByteCount ); 336 337 } 338} 339 340 341// Deprecated !!! 342//-------------------------------------------------------------------------------------------------- 343// doAsyncReadWrite [PUBLIC] 344//-------------------------------------------------------------------------------------------------- 345 346IOReturn 347IOUFIStorageServices::doAsyncReadWrite ( IOMemoryDescriptor * buffer, 348 UInt32 block, 349 UInt32 nblks, 350 IOStorageCompletion completion ) 351{ 352 353 UNUSED ( buffer ); 354 UNUSED ( block ); 355 UNUSED ( nblks ); 356 UNUSED ( completion ); 357 358 359 return kIOReturnUnsupported; 360 361} 362 363 364//-------------------------------------------------------------------------------------------------- 365// doAsyncReadWrite [PUBLIC] 366//-------------------------------------------------------------------------------------------------- 367 368 369IOReturn 370IOUFIStorageServices::doAsyncReadWrite ( IOMemoryDescriptor * buffer, 371 UInt64 block, 372 UInt64 nblks, 373 IOStorageAttributes * attributes, 374 IOStorageCompletion * completion ) 375{ 376 BlockServicesClientData * clientData; 377 IODirection direction; 378 IOReturn requestStatus; 379 UInt32 requestBlockSize; 380 381 382 UNUSED ( attributes ); 383 384 // Return errors for incoming I/O if we have been terminated. 385 if ( isInactive() != false ) 386 { 387 return kIOReturnNotAttached; 388 } 389 390 direction = buffer->getDirection(); 391 if ( ( direction != kIODirectionIn ) && ( direction != kIODirectionOut ) ) 392 { 393 // This is neither a read nor write request (since this is a read/write method, 394 // what kind of request is it?) return an error to the client. 395 return kIOReturnBadArgument; 396 } 397 398 clientData = ( BlockServicesClientData * ) IOMalloc ( sizeof( BlockServicesClientData ) ); 399 if ( clientData == NULL ) 400 { 401 STATUS_LOG ( ( 1, "%s[%p]:: doAsyncReadWrite; clientData malloc failed!", getName(), this ) ); 402 return kIOReturnNoResources; 403 } 404 405 // Make sure we don't go away while the command is being executed. 406 retain(); 407 fProvider->retain(); 408 409 requestBlockSize = fProvider->ReportMediumBlockSize(); 410 411 STATUS_LOG ( ( 5, "%s[%p]:: doAsyncReadWrite; save completion data!", getName(), this ) ); 412 413 // Set the owner of this request. 414 clientData->owner = this; 415 416 // Save the client's request parameters. 417 clientData->completionData = *completion; 418 clientData->clientBuffer = buffer; 419 clientData->clientStartingBlock = block; 420 clientData->clientRequestedBlockCount = nblks; 421 clientData->clientRequestedBlockSize = requestBlockSize; 422 423 // Set the retry limit to the maximum 424 clientData->retriesLeft = kNumberRetries; 425 426 requestStatus = fProvider->AsyncReadWrite ( buffer, block, nblks, ( UInt64 ) requestBlockSize, ( void * ) clientData ); 427 if ( requestStatus != kIOReturnSuccess ) 428 { 429 if ( clientData != NULL ) 430 { 431 IOFree ( clientData, sizeof ( BlockServicesClientData ) ); 432 } 433 } 434 435 return requestStatus; 436} 437 438 439//------------------------------------------------------------------------------------------------- 440// doSyncReadWrite [PUBLIC] 441//------------------------------------------------------------------------------------------------- 442 443IOReturn 444IOUFIStorageServices::doSyncReadWrite ( IOMemoryDescriptor * buffer, 445 UInt32 block, 446 UInt32 nblks ) 447{ 448 449 IOReturn result; 450 451 // Return errors for incoming I/O if we have been terminated 452 if ( isInactive() != false ) 453 { 454 return kIOReturnNotAttached; 455 } 456 457 // Make sure we don't go away while the command in being executed. 458 retain(); 459 fProvider->retain(); 460 461 // Execute the command 462 result = fProvider->SyncReadWrite( buffer, block, nblks, fProvider->ReportMediumBlockSize() ); 463 464 // Release the retains for this command. 465 fProvider->release(); 466 release(); 467 468 return result; 469 470} 471 472 473//-------------------------------------------------------------------------------------------------- 474// doEjectMedia [PUBLIC] 475//-------------------------------------------------------------------------------------------------- 476 477IOReturn 478IOUFIStorageServices::doEjectMedia ( void ) 479{ 480 481 IOReturn result; 482 483 484 fMediaPresent = false; 485 486 // Return errors for incoming activity if we have been terminated 487 if ( isInactive() != false ) 488 { 489 return kIOReturnNotAttached; 490 } 491 492 // Make sure we don't go away while the command in being executed. 493 retain(); 494 fProvider->retain(); 495 496 // Execute the command 497 result = fProvider->EjectTheMedium(); 498 499 // Release the retains for this command. 500 fProvider->release(); 501 release(); 502 503 return result; 504 505} 506 507 508//-------------------------------------------------------------------------------------------------- 509// doFormatMedia [PUBLIC] 510//-------------------------------------------------------------------------------------------------- 511 512IOReturn 513IOUFIStorageServices::doFormatMedia ( UInt64 byteCapacity ) 514{ 515 516 IOReturn result; 517 518 519 // Return errors for incoming activity if we have been terminated 520 if ( isInactive() != false ) 521 { 522 return kIOReturnNotAttached; 523 } 524 525 // Make sure we don't go away while the command in being executed. 526 retain(); 527 fProvider->retain(); 528 529 // Execute the command 530 result = fProvider->FormatMedium( byteCapacity / ( fProvider->ReportMediumBlockSize() ), 531 fProvider->ReportMediumBlockSize() ); 532 533 // Release the retains for this command. 534 fProvider->release(); 535 release(); 536 537 return result; 538 539} 540 541 542//-------------------------------------------------------------------------------------------------- 543// doGetFormatCapacities [PUBLIC] 544//-------------------------------------------------------------------------------------------------- 545 546UInt32 547IOUFIStorageServices::doGetFormatCapacities ( UInt64 * capacities, 548 UInt32 capacitiesMaxCount ) const 549{ 550 551 IOReturn result; 552 553 // Return errors for incoming activity if we have been terminated 554 if ( isInactive() != false ) 555 { 556 return kIOReturnNotAttached; 557 } 558 559 // Make sure we don't go away while the command in being executed. 560 retain(); 561 fProvider->retain(); 562 563 // Execute the command 564 result = fProvider->GetFormatCapacities ( capacities, capacitiesMaxCount ); 565 566 // Release the retains for this command. 567 fProvider->release(); 568 release(); 569 570 return result; 571 572} 573 574 575//-------------------------------------------------------------------------------------------------- 576// doSynchronizeCache [PUBLIC] 577//-------------------------------------------------------------------------------------------------- 578 579IOReturn 580IOUFIStorageServices::doSynchronizeCache ( void ) 581{ 582 583 // Return errors for incoming activity if we have been terminated 584 if ( isInactive() != false ) 585 { 586 return kIOReturnNotAttached; 587 } 588 589 return kIOReturnSuccess; 590 591} 592 593 594//-------------------------------------------------------------------------------------------------- 595// getVendorString [PUBLIC] 596//-------------------------------------------------------------------------------------------------- 597 598char * 599IOUFIStorageServices::getVendorString ( void ) 600{ 601 return fProvider->GetVendorString ( ); 602} 603 604 605//-------------------------------------------------------------------------------------------------- 606// getProductString [PUBLIC] 607//-------------------------------------------------------------------------------------------------- 608 609char * 610IOUFIStorageServices::getProductString ( void ) 611{ 612 return fProvider->GetProductString ( ); 613} 614 615 616//-------------------------------------------------------------------------------------------------- 617// getRevisionString [PUBLIC] 618//-------------------------------------------------------------------------------------------------- 619 620char * 621IOUFIStorageServices::getRevisionString ( void ) 622{ 623 return fProvider->GetRevisionString ( ); 624} 625 626 627//-------------------------------------------------------------------------------------------------- 628// getAdditionalDeviceInfoString [PUBLIC] 629//-------------------------------------------------------------------------------------------------- 630 631char * 632IOUFIStorageServices::getAdditionalDeviceInfoString ( void ) 633{ 634 635 STATUS_LOG ( (6, "%s::%s called", getName ( ), __FUNCTION__ ) ); 636 return ( ( char * ) "No Additional Device Info" ); 637 638} 639 640 641//-------------------------------------------------------------------------------------------------- 642// reportBlockSize [PUBLIC] 643//-------------------------------------------------------------------------------------------------- 644 645IOReturn 646IOUFIStorageServices::reportBlockSize ( UInt64 * blockSize ) 647{ 648 649 *blockSize = fProvider->ReportMediumBlockSize ( ); 650 return kIOReturnSuccess; 651 652} 653 654 655//-------------------------------------------------------------------------------------------------- 656// reportEjectability [PUBLIC] 657//-------------------------------------------------------------------------------------------------- 658 659IOReturn 660IOUFIStorageServices::reportEjectability ( bool * isEjectable ) 661{ 662 663 *isEjectable = true; 664 return kIOReturnSuccess; 665 666} 667 668 669//-------------------------------------------------------------------------------------------------- 670// reportMaxValidBlock [PUBLIC] 671//-------------------------------------------------------------------------------------------------- 672 673IOReturn 674IOUFIStorageServices::reportMaxValidBlock ( UInt64 * maxBlock ) 675{ 676 677 *maxBlock = ( fProvider->ReportMediumTotalBlockCount ( ) - 1 ); 678 return kIOReturnSuccess; 679 680} 681 682 683//-------------------------------------------------------------------------------------------------- 684// reportMediaState [PUBLIC] 685//-------------------------------------------------------------------------------------------------- 686 687IOReturn 688IOUFIStorageServices::reportMediaState ( bool * mediaPresent, 689 bool * changed ) 690{ 691 692 STATUS_LOG ( ( 6, "%s[%p]::reportMediaState.", getName(), this ) ); 693 694 *mediaPresent = fMediaPresent; 695 *changed = fMediaChanged; 696 697 if ( fMediaChanged ) 698 { 699 fMediaChanged = !fMediaChanged; 700 } 701 702 return kIOReturnSuccess; 703 704} 705 706 707//-------------------------------------------------------------------------------------------------- 708// reportRemovability [PUBLIC] 709//-------------------------------------------------------------------------------------------------- 710 711IOReturn 712IOUFIStorageServices::reportRemovability ( bool * isRemovable ) 713{ 714 715 *isRemovable = true; 716 return kIOReturnSuccess; 717 718} 719 720 721//-------------------------------------------------------------------------------------------------- 722// reportWriteProtection [PUBLIC] 723//-------------------------------------------------------------------------------------------------- 724 725IOReturn 726IOUFIStorageServices::reportWriteProtection ( bool * isWriteProtected ) 727{ 728 729 *isWriteProtected = fProvider->ReportMediumWriteProtection(); 730 return kIOReturnSuccess; 731 732} 733 734 735//-------------------------------------------------------------------------------------------------- 736// getWriteCacheState [PUBLIC] 737//-------------------------------------------------------------------------------------------------- 738 739IOReturn 740IOUFIStorageServices::getWriteCacheState ( bool * enabled ) 741{ 742 743 UNUSED ( enabled ); 744 745 return ( kIOReturnUnsupported ); 746 747} 748 749 750//-------------------------------------------------------------------------------------------------- 751// setWriteCacheState [PUBLIC] 752//-------------------------------------------------------------------------------------------------- 753 754IOReturn 755IOUFIStorageServices::setWriteCacheState ( bool enabled ) 756{ 757 758 UNUSED ( enabled ); 759 760 return ( kIOReturnUnsupported ); 761 762} 763 764 765// Space reserved for future expansion. 766OSMetaClassDefineReservedUnused( IOUFIStorageServices, 1 ); 767OSMetaClassDefineReservedUnused( IOUFIStorageServices, 2 ); 768OSMetaClassDefineReservedUnused( IOUFIStorageServices, 3 ); 769OSMetaClassDefineReservedUnused( IOUFIStorageServices, 4 ); 770OSMetaClassDefineReservedUnused( IOUFIStorageServices, 5 ); 771OSMetaClassDefineReservedUnused( IOUFIStorageServices, 6 ); 772OSMetaClassDefineReservedUnused( IOUFIStorageServices, 7 ); 773OSMetaClassDefineReservedUnused( IOUFIStorageServices, 8 ); 774 775//-------------------------------------------------------------------------------------------------- 776// End Of File 777//-------------------------------------------------------------------------------------------------- 778