]>
Commit | Line | Data |
---|---|---|
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 | * IOATAHDCommand.cpp - Performs ATA command processing. | |
26 | * | |
27 | * HISTORY | |
28 | * Aug 27, 1999 jliu - Ported from AppleATADrive. | |
29 | */ | |
30 | ||
31 | #include <IOKit/assert.h> | |
32 | #include <IOKit/IOSyncer.h> | |
33 | #include <IOKit/storage/ata/IOATAHDDrive.h> | |
34 | ||
35 | // Enable this define to generate debugging messages. | |
36 | // #define DEBUG_LOG 1 | |
37 | ||
38 | //--------------------------------------------------------------------------- | |
39 | // Select the device timing protocol. | |
40 | ||
41 | bool | |
42 | IOATAHDDrive::selectTimingProtocol() | |
43 | { | |
44 | bool ret; | |
45 | UInt8 ataReadCmd; | |
46 | UInt8 ataWriteCmd; | |
47 | ATATimingProtocol timing; | |
48 | char * protocolName; | |
49 | ||
50 | ret = _ataDevice->getTimingsSupported(&timing); | |
51 | if (ret == false) | |
52 | { | |
53 | IOLog("%s: getTimingsSupported() error\n", getName()); | |
54 | timing = kATATimingPIO; | |
55 | } | |
56 | ||
57 | // IOLog("%s: device supported timings: %08x\n", getName(), timing); | |
58 | ||
59 | if (timing & (kATATimingUltraDMA66 | kATATimingUltraDMA33 | kATATimingDMA)) | |
60 | { | |
61 | if (timing & kATATimingUltraDMA66) | |
62 | { | |
63 | protocolName = "U-DMA/66"; | |
64 | timing = kATATimingUltraDMA66; | |
65 | } | |
66 | else if (timing & kATATimingUltraDMA33) | |
67 | { | |
68 | protocolName = "U-DMA/33"; | |
69 | timing = kATATimingUltraDMA33; | |
70 | } | |
71 | else | |
72 | { | |
73 | protocolName = "DMA"; | |
74 | timing = kATATimingDMA; | |
75 | } | |
76 | ||
77 | selectCommandProtocol(true); | |
78 | ||
79 | switch ( _ataProtocol ) | |
80 | { | |
81 | case kATAProtocolDMAQueued: | |
82 | ataReadCmd = kIOATACommandReadDMAQueued; | |
83 | ataWriteCmd = kIOATACommandWriteDMAQueued; | |
84 | break; | |
85 | ||
86 | case kATAProtocolDMA: | |
87 | default: | |
88 | ataReadCmd = kIOATACommandReadDMA; | |
89 | ataWriteCmd = kIOATACommandWriteDMA; | |
90 | } | |
91 | } | |
92 | else | |
93 | { | |
94 | protocolName = "PIO"; | |
95 | timing = kATATimingPIO; | |
96 | ataReadCmd = kIOATACommandReadPIO; | |
97 | ataWriteCmd = kIOATACommandWritePIO; | |
98 | selectCommandProtocol(false); | |
99 | } | |
100 | ||
101 | _timingProtocol = timing; | |
102 | _ataReadCmd = ataReadCmd; | |
103 | _ataWriteCmd = ataWriteCmd; | |
104 | ret = true; | |
105 | ||
106 | // Select device timing. | |
107 | // | |
108 | ret = _ataDevice->selectTiming( _timingProtocol, false ); | |
109 | ||
110 | if (ret == false) | |
111 | { | |
112 | IOLog("%s: %s selectTiming() failed\n", getName(), protocolName); | |
113 | ||
114 | if (_timingProtocol != kATATimingPIO) | |
115 | { | |
116 | // Non PIO mode selection failed, defaulting to PIO mode and | |
117 | // try one more time. | |
118 | ||
119 | protocolName = "PIO"; | |
120 | _timingProtocol = kATATimingPIO; | |
121 | _ataReadCmd = kIOATACommandReadPIO; | |
122 | _ataWriteCmd = kIOATACommandWritePIO; | |
123 | selectCommandProtocol(false); | |
124 | ||
125 | ret = _ataDevice->selectTiming( _timingProtocol, false ); | |
126 | if (ret == false) | |
127 | IOLog("%s: %s selectTiming() retry failed\n", | |
128 | getName(), protocolName); | |
129 | } | |
130 | } | |
131 | ||
132 | if (ret && _logSelectedTimingProtocol) | |
133 | IOLog("%s: Using %s transfers\n", getName(), protocolName); | |
134 | ||
135 | return ret; | |
136 | } | |
137 | ||
138 | //--------------------------------------------------------------------------- | |
139 | // Select the command protocol to use (e.g. ataProtocolPIO, ataProtocolDMA). | |
140 | ||
141 | bool | |
142 | IOATAHDDrive::selectCommandProtocol(bool isDMA) | |
143 | { | |
144 | ATAProtocol protocolsSupported; | |
145 | ||
146 | if ( _ataDevice->getProtocolsSupported( &protocolsSupported ) == false ) | |
147 | { | |
148 | IOLog("%s: getProtocolsSupported() failed\n", getName()); | |
149 | return false; | |
150 | } | |
151 | ||
152 | if ( (protocolsSupported & kATAProtocolDMAQueued) != 0 ) | |
153 | { | |
154 | #if 0 | |
155 | _ataProtocol = kATAProtocolDMAQueued; | |
156 | #else | |
157 | _ataProtocol = kATAProtocolDMA; | |
158 | #endif | |
159 | } | |
160 | else if ( (protocolsSupported & kATAProtocolDMA) != 0 ) | |
161 | { | |
162 | _ataProtocol = kATAProtocolDMA; | |
163 | } | |
164 | else | |
165 | { | |
166 | _ataProtocol = kATAProtocolPIO; | |
167 | } | |
168 | ||
169 | return true; | |
170 | } | |
171 | ||
172 | //--------------------------------------------------------------------------- | |
173 | // Configure the ATA/ATAPI device when the driver is initialized, and | |
174 | // after every device reset. | |
175 | ||
176 | bool | |
177 | IOATAHDDrive::configureDevice(IOATADevice * device) | |
178 | { | |
179 | bool ret; | |
180 | ||
181 | // Select device timing. | |
182 | // | |
183 | ret = device->selectTiming( _timingProtocol, true ); | |
184 | if (ret == false) { | |
185 | IOLog("%s: selectTiming() failed\n", getName()); | |
186 | return false; | |
187 | } | |
188 | ||
189 | return true; | |
190 | } | |
191 | ||
192 | //--------------------------------------------------------------------------- | |
193 | // Setup an ATATaskFile from the parameters given, and write the taskfile | |
194 | // to the ATATaskfile structure pointer provided. | |
195 | // | |
196 | // taskfile - pointer to a taskfile structure. | |
197 | // protocol - An ATA transfer protocol (ataProtocolPIO, ataProtocolDMA, etc) | |
198 | // command - ATA command byte. | |
199 | // block - Initial transfer block. | |
200 | // nblks - Number of blocks to transfer. | |
201 | ||
202 | void | |
203 | IOATAHDDrive::setupReadWriteTaskFile(ATATaskfile * taskfile, | |
204 | ATAProtocol protocol, | |
205 | UInt8 command, | |
206 | UInt32 block, | |
207 | UInt32 nblks) | |
208 | { | |
209 | bzero( taskfile, sizeof(ATATaskfile) ); | |
210 | ||
211 | taskfile->protocol = protocol; | |
212 | ||
213 | // Mask of all taskfile registers that shall contain valid | |
214 | // data and should be written to the hardware registers. | |
215 | // | |
216 | taskfile->regmask = ATARegtoMask(kATARegSectorNumber) | | |
217 | ATARegtoMask(kATARegCylinderLow) | | |
218 | ATARegtoMask(kATARegCylinderHigh) | | |
219 | ATARegtoMask(kATARegDriveHead) | | |
220 | ATARegtoMask(kATARegSectorCount) | | |
221 | ATARegtoMask(kATARegFeatures) | | |
222 | ATARegtoMask(kATARegCommand); | |
223 | ||
224 | taskfile->resultmask = 0; | |
225 | ||
226 | taskfile->ataRegs[kATARegSectorNumber] = block & 0x0ff; | |
227 | taskfile->ataRegs[kATARegCylinderLow] = (block >> 8) & 0xff; | |
228 | taskfile->ataRegs[kATARegCylinderHigh] = (block >> 16) & 0xff; | |
229 | taskfile->ataRegs[kATARegDriveHead] = ((block >> 24) & 0x0f) | | |
230 | kATAModeLBA | (_unit << 4); | |
231 | ||
232 | if ( protocol == kATAProtocolDMAQueued ) | |
233 | { | |
234 | taskfile->ataRegs[kATARegFeatures] = | |
235 | (nblks == kIOATAMaxBlocksPerXfer) ? 0 : nblks; | |
236 | taskfile->ataRegs[kATARegSectorCount] = 0; | |
237 | } | |
238 | else | |
239 | { | |
240 | taskfile->ataRegs[kATARegFeatures] = 0; | |
241 | taskfile->ataRegs[kATARegSectorCount] = | |
242 | (nblks == kIOATAMaxBlocksPerXfer) ? 0 : nblks; | |
243 | } | |
244 | ||
245 | taskfile->ataRegs[kATARegCommand] = command; | |
246 | } | |
247 | ||
248 | //--------------------------------------------------------------------------- | |
249 | // Allocate and return an IOATACommand that is initialized to perform | |
250 | // a read/write operation. | |
251 | // | |
252 | // buffer - IOMemoryDescriptor object describing this transfer. | |
253 | // block - Initial transfer block. | |
254 | // nblks - Number of blocks to transfer. | |
255 | ||
256 | IOATACommand * | |
257 | IOATAHDDrive::ataCommandReadWrite(IOMemoryDescriptor * buffer, | |
258 | UInt32 block, | |
259 | UInt32 nblks) | |
260 | { | |
261 | ATATaskfile taskfile; | |
262 | bool isWrite; | |
263 | IOATACommand * cmd = allocateCommand(); | |
264 | ||
265 | assert(buffer); | |
266 | ||
267 | if (!cmd) return 0; // error, command allocation failed. | |
268 | ||
269 | isWrite = (buffer->getDirection() == kIODirectionOut) ? | |
270 | true : false; | |
271 | ||
272 | #ifdef DEBUG_LOG | |
273 | IOLog("%s::ataCommandReadWrite %08x (%d) %s %d %d\n", | |
274 | getName(), | |
275 | buffer, | |
276 | buffer->getLength(), | |
277 | isWrite ? "WR" : "RD", | |
278 | block, | |
279 | nblks); | |
280 | #endif | |
281 | ||
282 | #if 0 // used for testing - force PIO mode | |
283 | setupReadWriteTaskFile(&taskfile, | |
284 | kATAProtocolPIO, | |
285 | isWrite ? kIOATACommandWritePIO : | |
286 | kIOATACommandReadPIO, | |
287 | block, | |
288 | nblks); | |
289 | #else | |
290 | ||
291 | // Setup the taskfile structure with the size and direction of the | |
292 | // transfer. This structure will be written to the actual taskfile | |
293 | // registers when this command is processed. | |
294 | // | |
295 | setupReadWriteTaskFile(&taskfile, | |
296 | _ataProtocol, | |
297 | isWrite ? _ataWriteCmd : _ataReadCmd, | |
298 | block, | |
299 | nblks); | |
300 | #endif | |
301 | ||
302 | // Get a pointer to the client data buffer, and record parameters | |
303 | // which shall be later used by the completion routine. | |
304 | // | |
305 | ATA_CLIENT_DATA(cmd)->buffer = buffer; | |
306 | ||
307 | cmd->setTaskfile(&taskfile); | |
308 | ||
309 | cmd->setPointers(buffer, /* (IOMemoryDescriptor *) */ | |
310 | buffer->getLength(), /* transferCount (bytes) */ | |
311 | isWrite); /* isWrite */ | |
312 | ||
313 | return cmd; | |
314 | } | |
315 | ||
316 | //--------------------------------------------------------------------------- | |
317 | // Allocate and return a ATA SetFeatures command. | |
318 | ||
319 | IOATACommand * | |
320 | IOATAHDDrive::ataCommandSetFeatures(UInt8 features, | |
321 | UInt8 SectorCount, | |
322 | UInt8 SectorNumber, | |
323 | UInt8 CylinderLow, | |
324 | UInt8 CyclinderHigh) | |
325 | { | |
326 | ATATaskfile taskfile; | |
327 | IOATACommand * cmd = allocateCommand(); | |
328 | ||
329 | if (!cmd) return 0; // error, command allocation failed. | |
330 | ||
331 | taskfile.protocol = kATAProtocolPIO; | |
332 | ||
333 | taskfile.regmask = ATARegtoMask(kATARegSectorNumber) | | |
334 | ATARegtoMask(kATARegCylinderLow) | | |
335 | ATARegtoMask(kATARegCylinderHigh) | | |
336 | ATARegtoMask(kATARegDriveHead) | | |
337 | ATARegtoMask(kATARegSectorCount) | | |
338 | ATARegtoMask(kATARegCommand); | |
339 | ||
340 | taskfile.resultmask = ATARegtoMask(kATARegError) | | |
341 | ATARegtoMask(kATARegStatus); | |
342 | ||
343 | taskfile.ataRegs[kATARegFeatures] = features; | |
344 | taskfile.ataRegs[kATARegSectorNumber] = SectorNumber; | |
345 | taskfile.ataRegs[kATARegCylinderLow] = CylinderLow; | |
346 | taskfile.ataRegs[kATARegCylinderHigh] = CyclinderHigh; | |
347 | taskfile.ataRegs[kATARegDriveHead] = kATAModeLBA | (_unit << 4); | |
348 | taskfile.ataRegs[kATARegSectorCount] = SectorCount; | |
349 | taskfile.ataRegs[kATARegCommand] = kIOATACommandSetFeatures; | |
350 | ||
351 | cmd->setTaskfile(&taskfile); | |
352 | ||
353 | // This is a way to issue a command which will wait | |
354 | // for an interrupt, but does no data transfer. | |
355 | ||
356 | cmd->setPointers(0, 0, false); | |
357 | ||
358 | return cmd; | |
359 | } | |
360 | ||
361 | //--------------------------------------------------------------------------- | |
362 | // Return a Flush Cache command. | |
363 | ||
364 | IOATACommand * | |
365 | IOATAHDDrive::ataCommandFlushCache() | |
366 | { | |
367 | ATATaskfile taskfile; | |
368 | IOATACommand * cmd = allocateCommand(); | |
369 | ||
370 | if (!cmd) return 0; // error, command allocation failed. | |
371 | ||
372 | // kATAProtocolSetRegs does not wait for an interrupt from the drive. | |
373 | ||
374 | taskfile.protocol = kATAProtocolPIO; | |
375 | ||
376 | taskfile.regmask = ATARegtoMask(kATARegDriveHead) | | |
377 | ATARegtoMask(kATARegCommand); | |
378 | ||
379 | taskfile.resultmask = ATARegtoMask(kATARegError) | | |
380 | ATARegtoMask(kATARegSectorNumber) | | |
381 | ATARegtoMask(kATARegCylinderLow) | | |
382 | ATARegtoMask(kATARegCylinderHigh) | | |
383 | ATARegtoMask(kATARegDriveHead) | | |
384 | ATARegtoMask(kATARegStatus); | |
385 | ||
386 | taskfile.ataRegs[kATARegDriveHead] = kATAModeLBA | (_unit << 4); | |
387 | taskfile.ataRegs[kATARegCommand] = kIOATACommandFlushCache; | |
388 | ||
389 | cmd->setTaskfile(&taskfile); | |
390 | ||
391 | // This is a way to issue a command which will wait | |
392 | // for an interrupt, but does no data transfer. | |
393 | ||
394 | cmd->setPointers(0, 0, false); | |
395 | ||
396 | return cmd; | |
397 | } | |
398 | ||
399 | //--------------------------------------------------------------------------- | |
400 | // Return a STANDBY IMMEDIATE command. | |
401 | ||
402 | IOATACommand * | |
403 | IOATAHDDrive::ataCommandStandby() | |
404 | { | |
405 | ATATaskfile taskfile; | |
406 | IOATACommand * cmd = allocateCommand(); | |
407 | ||
408 | if (!cmd) return 0; // error, command allocation failed. | |
409 | ||
410 | // kATAProtocolSetRegs does not wait for an interrupt from the drive. | |
411 | ||
412 | taskfile.protocol = kATAProtocolPIO; | |
413 | ||
414 | taskfile.regmask = ATARegtoMask(kATARegDriveHead) | | |
415 | ATARegtoMask(kATARegCommand); | |
416 | ||
417 | taskfile.resultmask = ATARegtoMask(kATARegError) | | |
418 | ATARegtoMask(kATARegStatus); | |
419 | ||
420 | taskfile.ataRegs[kATARegDriveHead] = kATAModeLBA | (_unit << 4); | |
421 | taskfile.ataRegs[kATARegCommand] = kIOATACommandStandbyImmediate; | |
422 | ||
423 | cmd->setTaskfile(&taskfile); | |
424 | ||
425 | // This is a way to issue a command which will wait | |
426 | // for an interrupt, but does no data transfer. | |
427 | ||
428 | cmd->setPointers(0, 0, false); | |
429 | ||
430 | return cmd; | |
431 | } | |
432 | ||
433 | //--------------------------------------------------------------------------- | |
434 | // This routine is called by our provider when a command processing has | |
435 | // completed. | |
436 | ||
437 | void | |
438 | IOATAHDDrive::sHandleCommandCompletion(IOATAHDDrive * self, | |
439 | IOATACommand * cmd) | |
440 | { | |
441 | ATAResults results; | |
442 | IOATADevice * device; | |
443 | IOATAClientData * clientData; | |
444 | ||
445 | assert(cmd); | |
446 | device = cmd->getDevice(kIOATADevice); | |
447 | assert(device); | |
448 | ||
449 | clientData = ATA_CLIENT_DATA(cmd); | |
450 | assert(clientData); | |
451 | ||
452 | if ((cmd->getResults(&results) != kIOReturnSuccess) && | |
453 | (clientData->maxRetries-- > 0)) | |
454 | { | |
455 | cmd->execute(); | |
456 | return; | |
457 | } | |
458 | ||
459 | #if 0 | |
460 | // Force command retry to test retry logic. | |
461 | // Controller will reset the IOMemoryDescriptor's position, right? | |
462 | // | |
463 | cmd->getResults(&results); | |
464 | if (clientData->maxRetries-- > 2) { | |
465 | cmd->execute(); | |
466 | return; | |
467 | } | |
468 | #endif | |
469 | ||
470 | #ifdef DEBUG_LOG | |
471 | IOLog("%s: sHandleCommandCompletion %08x %08x %08x %08x %d\n", | |
472 | getName(), device, cmd, refcon, results.returnCode, | |
473 | results.bytesTransferred); | |
474 | #endif | |
475 | ||
476 | // Return IOReturn for sync commands. | |
477 | // | |
478 | clientData->returnCode = results.returnCode; | |
479 | ||
480 | if (clientData->isSync) { | |
481 | // For sync commands, unblock the client thread. | |
482 | // | |
483 | assert(clientData->completion.syncLock); | |
484 | clientData->completion.syncLock->signal(); // unblock the client. | |
485 | } | |
486 | else { | |
487 | // Signal the completion routine that the request has been completed. | |
488 | // | |
489 | ||
490 | IOStorage::complete(clientData->completion.async, | |
491 | results.returnCode, | |
492 | (UInt64) results.bytesTransferred); | |
493 | } | |
494 | ||
495 | // Release the IOMemoryDescriptor. | |
496 | // | |
497 | if (clientData->buffer) | |
498 | clientData->buffer->release(); | |
499 | ||
500 | // Command processing is complete, release the command object. | |
501 | // | |
502 | cmd->release(); | |
503 | } | |
504 | ||
505 | //--------------------------------------------------------------------------- | |
506 | // Issue a synchronous ATA command. | |
507 | ||
508 | IOReturn | |
509 | IOATAHDDrive::syncExecute(IOATACommand * cmd, /* command object */ | |
510 | UInt32 timeout, /* timeout in ms */ | |
511 | UInt retries, /* max retries */ | |
512 | IOMemoryDescriptor * senseData) | |
513 | { | |
514 | IOATAClientData * clientData = ATA_CLIENT_DATA(cmd); | |
515 | ||
516 | if ( _pmReady ) | |
517 | { | |
518 | activityTickle( kIOPMSuperclassPolicy1, 1 ); | |
519 | } | |
520 | ||
521 | // Bump the retain count on the command. The completion handler | |
522 | // will decrement the retain count. | |
523 | // | |
524 | cmd->retain(); | |
525 | ||
526 | // Set timeout and register the completion handler. | |
527 | // | |
528 | cmd->setPointers(senseData, | |
529 | senseData ? senseData->getLength() : 0, | |
530 | false, /* isWrite */ | |
531 | true ); /* isSense */ | |
532 | cmd->setTimeout(timeout); | |
533 | cmd->setCallback(this, | |
534 | (CallbackFn) &IOATAHDDrive::sHandleCommandCompletion, | |
535 | (void *) cmd); | |
536 | ||
537 | // Increment the retain count on the IOMemoryDescriptor. | |
538 | // Release when the completion routine gets called. | |
539 | // | |
540 | if (clientData->buffer) | |
541 | clientData->buffer->retain(); | |
542 | ||
543 | // Set the max retry count. If retry count is 0, then the command shall | |
544 | // not be retried if an error occurs. | |
545 | // | |
546 | clientData->maxRetries = retries; | |
547 | clientData->completion.syncLock = IOSyncer::create(); | |
548 | clientData->isSync = true; | |
549 | ||
550 | cmd->execute(); | |
551 | ||
552 | // Block client thread on lock until the completion handler | |
553 | // receives an indication that the processing is complete. | |
554 | // | |
555 | clientData->completion.syncLock->wait(); | |
556 | ||
557 | return clientData->returnCode; | |
558 | } | |
559 | ||
560 | //--------------------------------------------------------------------------- | |
561 | // Issue an asynchronous ATA command. | |
562 | ||
563 | IOReturn | |
564 | IOATAHDDrive::asyncExecute(IOATACommand * cmd, /* command object */ | |
565 | IOStorageCompletion completion, | |
566 | UInt32 timeout, /* timeout in ms */ | |
567 | UInt retries) /* max retries */ | |
568 | { | |
569 | IOATAClientData * clientData = ATA_CLIENT_DATA(cmd); | |
570 | ||
571 | if ( _pmReady ) | |
572 | { | |
573 | activityTickle( kIOPMSuperclassPolicy1, 1 ); | |
574 | } | |
575 | ||
576 | // Bump the retain count on the command. The completion handler | |
577 | // will decrement the retain count. | |
578 | // | |
579 | cmd->retain(); | |
580 | ||
581 | // Set timeout and register the completion handler. | |
582 | // | |
583 | cmd->setTimeout(timeout); | |
584 | cmd->setCallback(this, | |
585 | (CallbackFn) &IOATAHDDrive::sHandleCommandCompletion, | |
586 | (void *) cmd); | |
587 | ||
588 | // Increment the retain count on the IOMemoryDescriptor. | |
589 | // Release when the completion routine gets called. | |
590 | // | |
591 | if (clientData->buffer) | |
592 | clientData->buffer->retain(); | |
593 | ||
594 | // Set the max retry count. If retry count is 0, then the command shall | |
595 | // not be retried if an error occurs. | |
596 | // | |
597 | clientData->maxRetries = retries; | |
598 | clientData->isSync = false; | |
599 | ||
600 | clientData->completion.async = completion; | |
601 | ||
602 | return (cmd->execute() ? kIOReturnSuccess : kIOReturnNoResources); | |
603 | } | |
604 | ||
605 | //--------------------------------------------------------------------------- | |
606 | // Allocate an IOATACommand object with a fixed client data area. | |
607 | ||
608 | IOATACommand * | |
609 | IOATAHDDrive::allocateCommand() | |
610 | { | |
611 | return _ataDevice->allocCommand(kIOATADevice, sizeof(IOATAClientData)); | |
612 | } |