]> git.saurik.com Git - apple/xnu.git/blame - iokit/Families/IOATAPIHDDrive/IOATAPIHDDrive.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Families / IOATAPIHDDrive / IOATAPIHDDrive.cpp
CommitLineData
1c79356b
A
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
36OSDefineMetaClassAndStructors( IOATAPIHDDrive, IOATAHDDrive )
37
38//---------------------------------------------------------------------------
39// Override the init() method in IOATAHDDrive.
40
41bool
42IOATAPIHDDrive::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
55IOService *
56IOATAPIHDDrive::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
105ATADeviceType
106IOATAPIHDDrive::reportATADeviceType() const
107{
108 return kATADeviceATAPI;
109}
110
111//---------------------------------------------------------------------------
112// Looks for an ATAPI device which is a direct-access device.
113
114bool
115IOATAPIHDDrive::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
126bool
127IOATAPIHDDrive::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
164IOReturn
165IOATAPIHDDrive::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
186IOReturn
187IOATAPIHDDrive::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
207IOReturn
208IOATAPIHDDrive::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
228IOReturn
229IOATAPIHDDrive::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
248IOReturn
249IOATAPIHDDrive::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
272IOReturn
273IOATAPIHDDrive::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
291IOReturn
292IOATAPIHDDrive::doStart()
293{
294 return doStartStop(true);
295}
296
297//---------------------------------------------------------------------------
298// Stop the drive.
299
300IOReturn
301IOATAPIHDDrive::doStop()
302{
303 return doStartStop(false);
304}
305
306//---------------------------------------------------------------------------
307// Issue a START/STOP Unit command.
308
309IOReturn
310IOATAPIHDDrive::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
331char * IOATAPIHDDrive::getVendorString()
332{
333 return _vendor;
334}
335
336char * IOATAPIHDDrive::getProductString()
337{
338 return _product;
339}
340
341char * IOATAPIHDDrive::getRevisionString()
342{
343 return _revision;
344}
345
346char * IOATAPIHDDrive::getAdditionalDeviceInfoString()
347{
348 return ("[ATAPI]");
349}
350
351//---------------------------------------------------------------------------
352// Report whether the media in the drive is ejectable.
353
354IOReturn
355IOATAPIHDDrive::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
365IOReturn
366IOATAPIHDDrive::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
375IOReturn
376IOATAPIHDDrive::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
387IOReturn
388IOATAPIHDDrive::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
485IOReturn
486IOATAPIHDDrive::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
506IOReturn
507IOATAPIHDDrive::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
516IOService *
517IOATAPIHDDrive::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
527void
528IOATAPIHDDrive::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}