]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOATAPIHDDrive/IOATAPIHDDrive.cpp
7016edd1dc17e1ee2e5309c093e214fa4a47c90a
[apple/xnu.git] / iokit / Families / IOATAPIHDDrive / IOATAPIHDDrive.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
24 *
25 * IOATAPIHDDrive.h - Generic ATAPI Direct-Access driver.
26 *
27 * HISTORY
28 * Sep 2, 1999 jliu - Ported from AppleATAPIDrive.
29 */
30
31 #include <IOKit/assert.h>
32 #include <IOKit/storage/ata/IOATAPIHDDrive.h>
33 #include <IOKit/storage/ata/IOATAPIHDDriveNub.h>
34
35 #define super IOATAHDDrive
36 OSDefineMetaClassAndStructors( IOATAPIHDDrive, IOATAHDDrive )
37
38 //---------------------------------------------------------------------------
39 // Override the init() method in IOATAHDDrive.
40
41 bool
42 IOATAPIHDDrive::init(OSDictionary * properties)
43 {
44 _mediaPresent = false;
45 _isRemovable = false;
46
47 return super::init(properties);
48 }
49
50 //---------------------------------------------------------------------------
51 // Override probe() method inherited from IOATAHDDrive. We need to
52 // perform additional matching on ATAPI device type based on the
53 // Inquiry data revealed by an ATA(PI) device nub.
54
55 IOService *
56 IOATAPIHDDrive::probe(IOService * provider, SInt32 * score)
57 {
58 UInt8 deviceType;
59 IOService * ret = 0;
60 bool wasOpened = false;
61
62 // Let superclass have a go at probe first.
63 //
64 if (!super::probe(provider, score))
65 return 0;
66
67 // Our provider must be a IOATADevice nub, most likely created
68 // by an IOATAController instance.
69 //
70 _ataDevice = OSDynamicCast(IOATADevice, provider);
71 if (_ataDevice == 0)
72 return 0; // IOATADevice nub not found.
73
74 do {
75 // Since we may issue command to the IOATADevice to perform
76 // device matching, we express interest in using the device by
77 // performing an open.
78 //
79 if (_ataDevice->open(this) == false)
80 break;
81
82 wasOpened = true;
83
84 // Perform ATAPI type matching, CD-ROM, Direct-Access, Tape, etc.
85 //
86 if (!_ataDevice->getInquiryData(1, (ATAPIInquiry *) &deviceType) ||
87 !matchATAPIDeviceType(deviceType & 0x1f, score))
88 break;
89
90 ret = this;
91 }
92 while (false);
93
94 if (wasOpened)
95 _ataDevice->close(this);
96
97 _ataDevice = 0;
98
99 return ret;
100 }
101
102 //---------------------------------------------------------------------------
103 // Report as an ATAPI device.
104
105 ATADeviceType
106 IOATAPIHDDrive::reportATADeviceType() const
107 {
108 return kATADeviceATAPI;
109 }
110
111 //---------------------------------------------------------------------------
112 // Looks for an ATAPI device which is a direct-access device.
113
114 bool
115 IOATAPIHDDrive::matchATAPIDeviceType(UInt8 type, SInt32 * score)
116 {
117 if (type == kIOATAPIDeviceTypeDirectAccess)
118 return true;
119
120 return false;
121 }
122
123 //---------------------------------------------------------------------------
124 // Gather information about the ATAPI device nub.
125
126 bool
127 IOATAPIHDDrive::inspectDevice(IOATADevice * device)
128 {
129 OSString * string;
130
131 // Fetch ATAPI device information from the nub.
132 //
133 string = OSDynamicCast(OSString,
134 device->getProperty(kATAPropertyVendorName));
135 if (string) {
136 strncpy(_vendor, string->getCStringNoCopy(), 8);
137 _vendor[8] = '\0';
138 }
139
140 string = OSDynamicCast(OSString,
141 device->getProperty(kATAPropertyProductName));
142 if (string) {
143 strncpy(_product, string->getCStringNoCopy(), 16);
144 _product[16] = '\0';
145 }
146
147 string = OSDynamicCast(OSString,
148 device->getProperty(kATAPropertyProductRevision));
149 if (string) {
150 strncpy(_revision, string->getCStringNoCopy(), 4);
151 _revision[4] = '\0';
152 }
153
154 // Device wants to be power-managed.
155 //
156 _supportedFeatures |= kIOATAFeaturePowerManagement;
157
158 return true;
159 }
160
161 //---------------------------------------------------------------------------
162 // Async read/write requests.
163
164 IOReturn
165 IOATAPIHDDrive::doAsyncReadWrite(IOMemoryDescriptor * buffer,
166 UInt32 block,
167 UInt32 nblks,
168 IOStorageCompletion completion)
169 {
170 IOReturn ret;
171 IOATACommand * cmd = atapiCommandReadWrite(buffer, block, nblks);
172
173 if (!cmd)
174 return kIOReturnNoMemory;
175
176 ret = asyncExecute(cmd, completion);
177
178 cmd->release();
179
180 return ret;
181 }
182
183 //---------------------------------------------------------------------------
184 // Sync read/write requests.
185
186 IOReturn
187 IOATAPIHDDrive::doSyncReadWrite(IOMemoryDescriptor * buffer,
188 UInt32 block,
189 UInt32 nblks)
190 {
191 IOReturn ret;
192 IOATACommand * cmd = atapiCommandReadWrite(buffer, block, nblks);
193
194 if (!cmd)
195 return kIOReturnNoMemory;
196
197 ret = syncExecute(cmd);
198
199 cmd->release();
200
201 return ret;
202 }
203
204 //---------------------------------------------------------------------------
205 // Eject the media in the removable drive.
206
207 IOReturn
208 IOATAPIHDDrive::doEjectMedia()
209 {
210 IOReturn ret;
211 IOATACommand * cmd = atapiCommandStartStopUnit(false, /* start unit */
212 true, /* Load/Eject */
213 false); /* Immediate */
214
215 if (!cmd)
216 return kIOReturnNoMemory;
217
218 ret = syncExecute(cmd);
219
220 cmd->release();
221
222 return ret;
223 }
224
225 //---------------------------------------------------------------------------
226 // Format the media in the drive.
227
228 IOReturn
229 IOATAPIHDDrive::doFormatMedia(UInt64 byteCapacity,
230 IOMemoryDescriptor * formatData = 0)
231 {
232 IOReturn ret;
233 IOATACommand * cmd = atapiCommandFormatUnit(0, 0, 0, formatData);
234
235 if (!cmd)
236 return kIOReturnNoMemory;
237
238 ret = syncExecute(cmd, 15 * 60 * 1000); // 15 min timeout
239
240 cmd->release();
241
242 return ret;
243 }
244
245 //---------------------------------------------------------------------------
246 // Lock/unlock the media in the removable drive.
247
248 IOReturn
249 IOATAPIHDDrive::doLockUnlockMedia(bool doLock)
250 {
251 IOReturn ret;
252 IOATACommand * cmd = atapiCommandPreventAllowRemoval(doLock);
253
254 if (!cmd)
255 return kIOReturnNoMemory;
256
257 ret = syncExecute(cmd);
258
259 cmd->release();
260
261 // Cache the state on the media lock, and restore it when
262 // the driver wakes up from sleep.
263
264 _isLocked = doLock;
265
266 return ret;
267 }
268
269 //---------------------------------------------------------------------------
270 // Sync the write cache.
271
272 IOReturn
273 IOATAPIHDDrive::doSynchronizeCache()
274 {
275 IOReturn ret;
276 IOATACommand * cmd = atapiCommandSynchronizeCache();
277
278 if (!cmd)
279 return kIOReturnNoMemory;
280
281 ret = syncExecute(cmd);
282
283 cmd->release();
284
285 return ret;
286 }
287
288 //---------------------------------------------------------------------------
289 // Start up the drive.
290
291 IOReturn
292 IOATAPIHDDrive::doStart()
293 {
294 return doStartStop(true);
295 }
296
297 //---------------------------------------------------------------------------
298 // Stop the drive.
299
300 IOReturn
301 IOATAPIHDDrive::doStop()
302 {
303 return doStartStop(false);
304 }
305
306 //---------------------------------------------------------------------------
307 // Issue a START/STOP Unit command.
308
309 IOReturn
310 IOATAPIHDDrive::doStartStop(bool doStart)
311 {
312 IOReturn ret;
313 IOATACommand * cmd;
314
315 cmd = atapiCommandStartStopUnit(doStart, /* start unit */
316 false, /* Load/Eject */
317 false); /* Immediate operation */
318
319 if (!cmd) return kIOReturnNoMemory;
320
321 ret = syncExecute(cmd);
322
323 cmd->release();
324
325 return ret;
326 }
327
328 //---------------------------------------------------------------------------
329 // Return device identification strings
330
331 char * IOATAPIHDDrive::getVendorString()
332 {
333 return _vendor;
334 }
335
336 char * IOATAPIHDDrive::getProductString()
337 {
338 return _product;
339 }
340
341 char * IOATAPIHDDrive::getRevisionString()
342 {
343 return _revision;
344 }
345
346 char * IOATAPIHDDrive::getAdditionalDeviceInfoString()
347 {
348 return ("[ATAPI]");
349 }
350
351 //---------------------------------------------------------------------------
352 // Report whether the media in the drive is ejectable.
353
354 IOReturn
355 IOATAPIHDDrive::reportEjectability(bool * isEjectable)
356 {
357 *isEjectable = true; /* default: if it's removable, it's ejectable */
358 return kIOReturnSuccess;
359 }
360
361 //---------------------------------------------------------------------------
362 // Report whether the drive can prevent user-initiated ejects by locking
363 // the media in the drive.
364
365 IOReturn
366 IOATAPIHDDrive::reportLockability(bool * isLockable)
367 {
368 *isLockable = true; /* default: if it's removable, it's lockable */
369 return kIOReturnSuccess;
370 }
371
372 //---------------------------------------------------------------------------
373 // Report our polling requirments.
374
375 IOReturn
376 IOATAPIHDDrive::reportPollRequirements(bool * pollRequired,
377 bool * pollIsExpensive)
378 {
379 *pollIsExpensive = false;
380 *pollRequired = _isRemovable;
381 return kIOReturnSuccess;
382 }
383
384 //---------------------------------------------------------------------------
385 // Report the current state of the media.
386
387 IOReturn
388 IOATAPIHDDrive::reportMediaState(bool * mediaPresent,
389 bool * changed)
390 {
391 IOATACommand * cmd = 0;
392 IOMemoryDescriptor * senseData = 0;
393 UInt8 senseBuf[18];
394 ATAResults results;
395 IOReturn ret;
396
397 assert(mediaPresent && changed);
398
399 do {
400 ret = kIOReturnNoMemory;
401
402 bzero((void *) senseBuf, sizeof(senseBuf));
403 senseData = IOMemoryDescriptor::withAddress(senseBuf,
404 sizeof(senseBuf),
405 kIODirectionIn);
406 if (!senseData)
407 break;
408
409 cmd = atapiCommandTestUnitReady();
410 if (!cmd)
411 break;
412
413 // Execute the Test Unit Ready command with no retries.
414 //
415 syncExecute(cmd, kATADefaultTimeout, kATAZeroRetry, senseData);
416
417 ret = kIOReturnSuccess;
418
419 if (cmd->getResults(&results) == kIOReturnSuccess)
420 {
421 *mediaPresent = true;
422 *changed = (*mediaPresent != _mediaPresent);
423 _mediaPresent = true;
424 }
425 else
426 {
427 UInt8 errorCode = senseBuf[0];
428 UInt8 senseKey = senseBuf[2];
429
430 #ifdef DEBUG_LOG
431 UInt8 senseCode = senseBuf[12];
432 UInt8 senseQualifier = senseBuf[13];
433
434 IOLog("-- IOATAPIHDDrive::reportMediaState --\n");
435 IOLog("Error code: %02x\n", errorCode);
436 IOLog("Sense Key : %02x\n", senseKey);
437 IOLog("ASC : %02x\n", senseCode);
438 IOLog("ASCQ : %02x\n", senseQualifier);
439 #endif
440
441 *mediaPresent = false;
442 *changed = (*mediaPresent != _mediaPresent);
443 _mediaPresent = false;
444
445 // The error code field for ATAPI request sense should always
446 // be 0x70 or 0x71. Otherwise ignore the sense data.
447 //
448 if ((errorCode == 0x70) || (errorCode == 0x71))
449 {
450 switch (senseKey) {
451 case 5: /* Invalid ATAPI command */
452 ret = kIOReturnIOError;
453 break;
454
455 case 2: /* Not ready */
456 break;
457
458 default:
459 break;
460 }
461 }
462 }
463 }
464 while (false);
465
466 if (cmd)
467 cmd->release();
468
469 if (senseData)
470 senseData->release();
471
472 #if 0
473 IOLog("%s: media present %s, changed %s\n", getName(),
474 *mediaPresent ? "Y" : "N",
475 *changed ? "Y" : "N"
476 );
477 #endif
478
479 return ret;
480 }
481
482 //---------------------------------------------------------------------------
483 // Report media removability.
484
485 IOReturn
486 IOATAPIHDDrive::reportRemovability(bool * isRemovable)
487 {
488 UInt8 inqBuf[2];
489
490 *isRemovable = false;
491
492 if (_ataDevice->getInquiryData(sizeof(inqBuf), (ATAPIInquiry *) inqBuf))
493 {
494 if (inqBuf[1] & 0x80)
495 *isRemovable = _isRemovable = true;
496 else
497 *isRemovable = _isRemovable = false;
498 }
499
500 return kIOReturnSuccess;
501 }
502
503 //---------------------------------------------------------------------------
504 // Report whether media is write-protected.
505
506 IOReturn
507 IOATAPIHDDrive::reportWriteProtection(bool * isWriteProtected)
508 {
509 *isWriteProtected = false; // defaults to read-write
510 return kIOReturnSuccess;
511 }
512
513 //---------------------------------------------------------------------------
514 // Instantiate an ATAPI specific subclass of IOBlockStorageDevice.
515
516 IOService *
517 IOATAPIHDDrive::instantiateNub()
518 {
519 IOService * nub = new IOATAPIHDDriveNub;
520 return nub;
521 }
522
523 //---------------------------------------------------------------------------
524 // Override the handleActiveStateTransition() method in IOATAHDDrive and
525 // perform ATAPI specific handling.
526
527 void
528 IOATAPIHDDrive::handleActiveStateTransition( UInt32 stage, IOReturn status )
529 {
530 // Restore the lock on the media after the ATAPI device wakes up from
531 // sleep. Assume that the drive will always power up in the unlocked state.
532 // Technically, some drives may have a jumper to set the default state
533 // at power up.
534
535 if ( ( stage == kIOATAActiveStage0 ) && _isLocked )
536 {
537 IOStorageCompletion completion;
538 IOReturn ret;
539 IOATACommand * cmd = atapiCommandPreventAllowRemoval( true );
540
541 completion.target = this;
542 completion.action = sHandleActiveStateTransition;
543 completion.parameter = (void *) kIOATAActiveStage1;
544
545 if ( cmd )
546 {
547 cmd->setQueueInfo( kATAQTypeBypassQ );
548 ret = asyncExecute( cmd, completion );
549 cmd->release();
550 }
551 }
552 else
553 {
554 super::handleActiveStateTransition( stage, status );
555 }
556 }