]>
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 | * IOBasicSCSI.h | |
26 | * | |
27 | * This class implements generic SCSI functionality. | |
28 | */ | |
29 | ||
30 | #ifndef _IOBASICSCSI_H | |
31 | #define _IOBASICSCSI_H | |
32 | ||
33 | #include <IOKit/IOTypes.h> | |
34 | #include <IOKit/IOService.h> | |
35 | #include <IOKit/IOSyncer.h> | |
36 | #include <IOKit/scsi/IOSCSIDeviceInterface.h> | |
37 | #include <IOKit/storage/IOStorage.h> | |
38 | ||
39 | const int kMinInqSize = 5; /* minimal, supported by all devs */ | |
40 | const int kReadCapSize = 8; | |
41 | const int kModeSenseSize = 64; | |
42 | const int kMaxInqSize = 256; | |
43 | ||
44 | const int kCheckCondition = 0x02; | |
45 | const int kUnitAttention = 0x06; | |
46 | ||
47 | /* SCSI operation codes: */ | |
48 | ||
49 | const UInt8 SOP_TUR = 0x00; /* test unit ready */ | |
50 | const UInt8 SOP_INQUIRY = 0x12; /* inquiry */ | |
51 | const UInt8 SOP_MODESELECT = 0x15; /* mode select */ | |
52 | const UInt8 SOP_MODESENSE = 0x1a; /* mode sense */ | |
53 | const UInt8 SOP_READCAP = 0x25; /* read capacity */ | |
54 | const UInt8 SOP_READ10 = 0x28; /* read (10-byte) */ | |
55 | const UInt8 SOP_WRITE10 = 0x2a; /* write (10-byte) */ | |
56 | ||
57 | struct IOTURcdb { | |
58 | UInt8 opcode; | |
59 | UInt8 lunbits; | |
60 | UInt8 reserved1; | |
61 | UInt8 reserved2; | |
62 | UInt8 reserved3; | |
63 | UInt8 ctlbyte; | |
64 | }; | |
65 | ||
66 | struct IORWcdb { /* CDB for read and write */ | |
67 | UInt8 opcode; /* read=0x28, write=0x2a */ | |
68 | UInt8 lunbits; /* lun and control bits */ | |
69 | UInt8 lba_3; /* logical block address: msb */ | |
70 | UInt8 lba_2; | |
71 | UInt8 lba_1; | |
72 | UInt8 lba_0; /* logical block address: lsb */ | |
73 | UInt8 reserved; | |
74 | UInt8 count_msb; /* block count: msb */ | |
75 | UInt8 count_lsb; /* block count: lsb */ | |
76 | UInt8 ctlbyte; | |
77 | }; | |
78 | ||
79 | struct IOInquirycdb { /* inquiry */ | |
80 | UInt8 opcode; /* 0x12 */ | |
81 | UInt8 lunbits; /* lun and control bits */ | |
82 | UInt8 pagecode; /* page code/op code */ | |
83 | UInt8 reserved; | |
84 | UInt8 len; /* allocation length */ | |
85 | UInt8 ctlbyte; | |
86 | }; | |
87 | ||
88 | struct IOReadCapcdb { | |
89 | UInt8 opcode; | |
90 | UInt8 lunbits; | |
91 | UInt8 lba_3; | |
92 | UInt8 lba_2; | |
93 | UInt8 lba_1; | |
94 | UInt8 lba_0; | |
95 | UInt8 reserved1; | |
96 | UInt8 reserved2; | |
97 | UInt8 reserved3; | |
98 | UInt8 ctlbyte; | |
99 | }; | |
100 | ||
101 | struct IOModeSensecdb { | |
102 | UInt8 opcode; | |
103 | UInt8 lunbits; /* lun and control bits */ | |
104 | UInt8 pagecode; | |
105 | UInt8 reserved; | |
106 | UInt8 len; /* allocation length */ | |
107 | UInt8 ctlbyte; | |
108 | }; | |
109 | ||
110 | struct IOModeSelectcdb { | |
111 | UInt8 opcode; | |
112 | UInt8 lunbits; | |
113 | UInt8 reserved1; | |
114 | UInt8 reserved2; | |
115 | UInt8 paramlen; | |
116 | UInt8 ctlbyte; | |
117 | }; | |
118 | ||
119 | /*! | |
120 | * @enum stateValues | |
121 | * @discussion | |
122 | * These state values are used to determin the state of an IO operation. | |
123 | * Some are simply for debugging use. | |
124 | * @constant kNone | |
125 | * Nothing happening. | |
126 | * @constant kAsyncReadWrite | |
127 | * Doing an asynchronous IO operation. | |
128 | * @constant kSimpleSynchIO | |
129 | * Doing a simple synchronous IO operation. | |
130 | * @constant kHandlingUnitAttention | |
131 | * Currently handling a Unit-Attention condition. | |
132 | * @constant kDoneHandlingUnitAttention | |
133 | * Done handling Unit Attention; command should be reissued. | |
134 | * @constant kAwaitingPower | |
135 | * Awaiting power. | |
136 | * @constant kMaxValidState | |
137 | * The maximum valid state value. | |
138 | * @constant kMaxStateValue | |
139 | * The maximum state value possible. | |
140 | */ | |
141 | enum stateValues { | |
142 | kNone = 0, | |
143 | kAsyncReadWrite = 1, | |
144 | kSimpleSynchIO = 2, | |
145 | kHandlingUnitAttention = 3, | |
146 | kHandlingRecoveryAfterBusReset = 4, | |
147 | kAwaitingPower = 5, | |
148 | ||
149 | kMaxValidState = kAwaitingPower, | |
150 | ||
151 | kMaxStateValue = 255 | |
152 | }; | |
153 | /*! | |
154 | * @typedef statevalue | |
155 | * @discussion | |
156 | * Shorthand for enum StateValues. | |
157 | */ | |
158 | typedef enum stateValues stateValue; | |
159 | ||
160 | const bool kSync = true; /* type info for requests awaiting power */ | |
161 | const bool kAsync = false; | |
162 | ||
163 | const UInt32 kMaxRetries = 3; | |
164 | ||
165 | /*! | |
166 | * @class | |
167 | * IOBasicSCSI : public IOService | |
168 | * @abstract | |
169 | * Basic SCSI support functions. | |
170 | * @discussion | |
171 | * IOBasicSCSI provides a set of basic SCSI functions and support | |
172 | * utilities. It is intended to be the base class for a SCSI Transport | |
173 | * Driver. | |
174 | */ | |
175 | ||
176 | class IOBasicSCSI : public IOService { | |
177 | ||
178 | OSDeclareAbstractStructors(IOBasicSCSI) | |
179 | ||
180 | public: | |
181 | ||
182 | /*! | |
183 | * @struct completion | |
184 | * @field action | |
185 | * The C function called upon completion of the operation. | |
186 | * @field target | |
187 | * The C++ class pointer, passed to tha action function. | |
188 | * @field param | |
189 | * A value passed to the action function. This value is not touched. | |
190 | */ | |
191 | /*! | |
192 | * @struct context | |
193 | * @discussion | |
194 | * The context structure contains all persistent information needed for a | |
195 | * synchronous or asynchronous IO operation. | |
196 | * @field completion | |
197 | * The completion information for an asynchronous read or write operation. | |
198 | * @field state | |
199 | * The current state of the operation. | |
200 | * @field step | |
201 | * The current step value, if we are handling a Unit Attention. | |
202 | * @field originalContext | |
203 | * A pointer to the context for the command that caused the Unit Attention | |
204 | * condition. | |
205 | * @field scsireq | |
206 | * A pointer to the IOSCSIRequest object. | |
207 | * @field memory | |
208 | * The data buffer for the operation. A pointer to an IOMemoryDescriptor. | |
209 | * @field scsiresult | |
210 | * A pointer to the IOSCSIResult object. | |
211 | * @field desiredPower | |
212 | * The desired power level for the operation to execute. | |
213 | * @field isSync | |
214 | * True if synchronous; False if asynchronous. | |
215 | * @field next | |
216 | * A pointer to a context structure, used as a queue forward-link. | |
217 | * @field sync | |
218 | * A syncer used to block a thread awaiting a power level, or for completion | |
219 | * of a synchronous operation. | |
220 | */ | |
221 | struct context { | |
222 | ||
223 | /* Completion information for our client, used only for async operations. | |
224 | * Typically this information will only be used by subclasses. | |
225 | */ | |
226 | IOStorageCompletion completion; /* function to call */ | |
227 | ||
228 | /* Parameters used during an IO retry: */ | |
229 | ||
230 | stateValue state; /* what state we're in */ | |
231 | UInt32 step; | |
232 | struct context *originalIOContext; /* original SCSI IO if doing a retry */ | |
233 | bool retryInProgress; | |
234 | UInt32 retryCount; | |
235 | ||
236 | IOMemoryDescriptor *memory; | |
237 | ||
238 | UInt32 desiredPower; /* desired power level state */ | |
239 | bool isSync; /* true if sync, false if async */ | |
240 | struct context *next; /* for queue of requests pending power */ | |
241 | /* Parameters to hand off to the SCSI provider: */ | |
242 | ||
243 | IOSCSICommand *scsireq; | |
244 | SCSISenseData *senseData; | |
245 | IOMemoryDescriptor *senseDataDesc; | |
246 | ||
247 | IOSyncer *sync; /* to wait for completion */ | |
248 | }; | |
249 | ||
250 | /* Overrides from IOService: */ | |
251 | ||
252 | virtual void free(void); | |
253 | ||
254 | virtual bool init(OSDictionary * properties); | |
255 | ||
256 | /*! | |
257 | * @function message | |
258 | * @discussion | |
259 | * This override allows us to receive notification of Bus Reset events from | |
260 | * the SCSI Device. | |
261 | */ | |
262 | virtual IOReturn message(UInt32 type,IOService * provider,void * argument); | |
263 | ||
264 | /*! | |
265 | * @function probe | |
266 | * @abstract | |
267 | * Determine if device matches expected type. | |
268 | * @discussion | |
269 | * This method is responsible for matching the device type. It calls | |
270 | * doInquiry to issue a SCSI Inquiry command to the device, then calls | |
271 | * deviceTypeMatches to ensure that the device type matches the expected | |
272 | * type. (The Vendor, Product, and Revision strings are unconditionally | |
273 | * copied from the inquiry data). If deviceTypeMatches returns true, "this" is | |
274 | * returned. If the device type does not match, NULL is returned. | |
275 | * | |
276 | * The default implementation passes the score parameter to deviceTypeMatches | |
277 | * so that method may alter the match score. | |
278 | */ | |
279 | virtual IOService * probe(IOService * provider,SInt32 * score); | |
280 | ||
281 | virtual bool start(IOService *provider); | |
282 | ||
283 | /* --- end of IOService overrides --- */ | |
284 | ||
285 | /*! | |
286 | * @function deviceTypeMatches | |
287 | * @abstract | |
288 | * Determine if device type matches expected type. | |
289 | * @discussion | |
290 | * This method must be implemented by a device-specific subclass. | |
291 | * @param inqBuf | |
292 | * A pointer to the SCSI inquiry data for the device. | |
293 | * @param inqLen | |
294 | * The size of the data in the inquiry buffer. | |
295 | * @param score | |
296 | * A pointer to the match score, which will be returned by probe. | |
297 | * @result | |
298 | * True indicates a match; False indicates a failure. | |
299 | */ | |
300 | virtual bool deviceTypeMatches(UInt8 inqBuf[],UInt32 inqLen,SInt32 *score) = 0; | |
301 | ||
302 | /*! | |
303 | * @function getAdditionalDeviceInfoString | |
304 | * @abstract | |
305 | * Return additional informational string for the device. | |
306 | * @result | |
307 | * A pointer to a static character string. The default implementation | |
308 | * returns "[SCSI]" . | |
309 | */ | |
310 | virtual char * getAdditionalDeviceInfoString(void); | |
311 | ||
312 | /*! | |
313 | * @function getVendorString | |
314 | * @abstract | |
315 | * Return Vendor Name string | |
316 | * @result | |
317 | * A pointer to a static character string, copied from the inquiry data. | |
318 | */ | |
319 | virtual char * getVendorString(void); | |
320 | ||
321 | /*! | |
322 | * @function getProductString | |
323 | * @abstract | |
324 | * Return Product Name string for the device. | |
325 | * @result | |
326 | A pointer to a static character string, copied from the inquiry data. | |
327 | */ | |
328 | virtual char * getProductString(void); | |
329 | ||
330 | /*! | |
331 | * @function getRevisionString | |
332 | * @abstract | |
333 | * Return Product Revision string for the device. | |
334 | * @result | |
335 | * A pointer to a static character string, copied from the inquiry data. | |
336 | */ | |
337 | virtual char * getRevisionString(void); | |
338 | ||
339 | /*! | |
340 | * @function reportBlockSize | |
341 | * @abstract | |
342 | * Report the block size for the device, in bytes. | |
343 | * @discussion | |
344 | * This method returns the block size for the media. The default | |
345 | * implementation obtains the block size from the SCSI Read Capacity | |
346 | * command. Since the result of the Read Capacity is used by this | |
347 | * method and reportMaxValidBlock, this method either returns a cached | |
348 | * value or calls doReadCapacity to issue the command and cache both | |
349 | * values. | |
350 | * @param blockSize | |
351 | * Pointer to returned block size value. | |
352 | */ | |
353 | virtual IOReturn reportBlockSize(UInt64 *blockSize); | |
354 | ||
355 | /*! | |
356 | * @function reportEjectability | |
357 | * @abstract | |
358 | * Report if the media is ejectable under software control. | |
359 | * @discussion | |
360 | * This method reports whether the media is ejectable under software | |
361 | * control. The default implementation always reports that removable | |
362 | * media is ejectable. | |
363 | * | |
364 | * This method should only be called if the media is known to be removable. | |
365 | * @param isEjectable | |
366 | * Pointer to returned result. True indicates the media is ejectable, False indicates | |
367 | * the media cannot be ejected under software control. | |
368 | */ | |
369 | virtual IOReturn reportEjectability(bool *isEjectable); | |
370 | ||
371 | /*! | |
372 | * @function reportLockability | |
373 | * @abstract | |
374 | * Report if the media is lockable under software control. | |
375 | * @discussion | |
376 | * This method reports whether the media can be locked under software | |
377 | * control, to prevent the user from removing the media manually, e.g. | |
378 | * by pressing a button on the drive. This method is only called by | |
379 | * the generic driver when the media is known to be removable. The | |
380 | * default implementation always returns true. | |
381 | * | |
382 | * This method should only be called if the media is known to be removable. | |
383 | * @param isLockable | |
384 | * Pointer to returned result. True indicates the media can be locked in place; False | |
385 | * indicates the media cannot be locked by software. | |
386 | */ | |
387 | virtual IOReturn reportLockability(bool *isLockable); | |
388 | ||
389 | /*! | |
390 | * @function reportMaxReadTransfer | |
391 | * @abstract | |
392 | * Report the maximum allowed byte transfer for read operations. | |
393 | * @discussion | |
394 | * Some devices impose a maximum data transfer size. Because this limit | |
395 | * may be determined by the size of a block-count field in a command, the limit may | |
396 | * depend on the block size of the transfer. | |
397 | * The default implementation reports blocksize * 65536, which is the maximum | |
398 | * number of bytes that can be transferred | |
399 | * in a SCSI command with a standard 16-bit block count field. | |
400 | * @param blockSize | |
401 | * The block size desired for the transfer. | |
402 | * @param max | |
403 | * Pointer to returned result. | |
404 | */ | |
405 | virtual IOReturn reportMaxReadTransfer (UInt64 blocksize,UInt64 *max); | |
406 | ||
407 | /*! | |
408 | * @function reportMaxValidBlock | |
409 | * @abstract | |
410 | * Report the highest valid block for the device. | |
411 | * @discussion | |
412 | * This method reports the maximum allowable block number. The default | |
413 | * implementation obtains the block number from the SCSI Read Capacity | |
414 | * command. Since the result of the Read Capacity is used by this | |
415 | * method and reportBlockSize, this method either returns a cached | |
416 | * value or calls doReadCapacity to issue the command and cache both | |
417 | * values. | |
418 | * @param maxBlock | |
419 | * Pointer to returned result | |
420 | */ | |
421 | virtual IOReturn reportMaxValidBlock(UInt64 *maxBlock); | |
422 | ||
423 | /*! | |
424 | * @function reportMaxWriteTransfer | |
425 | * @abstract | |
426 | * Report the maximum allowed byte transfer for write operations. | |
427 | * @discussion | |
428 | * Some devices impose a maximum data transfer size. Because this limit | |
429 | * may be determined by the size of a block-count field in a command, the limit may | |
430 | * depend on the block size of the transfer. | |
431 | * The default implementation reports blocksize * 65536, which is the maximum | |
432 | * number of bytes that can be transferred | |
433 | * in a SCSI command with a standard 16-bit block count field. | |
434 | * @param blockSize | |
435 | * The block size desired for the transfer. | |
436 | * @param max | |
437 | * Pointer to returned result. | |
438 | */ | |
439 | virtual IOReturn reportMaxWriteTransfer(UInt64 blocksize,UInt64 *max); | |
440 | ||
441 | /*! | |
442 | * @function reportPollRequirements | |
443 | * @abstract | |
444 | * Report if it's necessary to poll for media insertion, and if polling is expensive. | |
445 | * @discussion | |
446 | * This method reports whether the device must be polled to detect media | |
447 | * insertion, and whether a poll is expensive to perform. | |
448 | * | |
449 | * The term "expensive" typically implies a device that must be spun-up to detect media, | |
450 | * as on a PC floppy. Most devices can detect media inexpensively. | |
451 | * | |
452 | * The default implementation of this method always reports an | |
453 | * inexpensive poll (pollIsExpensive = false), and that all removable | |
454 | * media must be polled. | |
455 | * @param pollRequired | |
456 | * Pointer to returned result. True indicates that polling is required; False indicates | |
457 | * that polling is not required to detect media. | |
458 | * @param pollIsExpensive | |
459 | * Pointer to returned result. True indicates that the polling operation is expensive; | |
460 | * False indicates that the polling operation is cheap. | |
461 | */ | |
462 | virtual IOReturn reportPollRequirements(bool *pollRequired,bool *pollIsExpensive); | |
463 | ||
464 | /*! | |
465 | * @function reportRemovability | |
466 | * @abstract | |
467 | * Report whether the media is removable or not. | |
468 | * @discussion | |
469 | * This method reports whether the media is removable, but it does not | |
470 | * provide detailed information regarding software eject or lock/unlock capability. | |
471 | * | |
472 | * The default implementation of this method examines the cached | |
473 | * Inquiry data to determine if media is removable. If the RMB bit | |
474 | * (0x80 of Inquiry data byte 1) is set, the media is removable. If | |
475 | * there is no Inquiry data, the media is reported to be nonremovable. | |
476 | * | |
477 | * This method also sets the instance variable _removable. | |
478 | * @param isRemovable | |
479 | * Pointer to returned result. True indicates that the media is removable; False | |
480 | * indicates the media is not removable. | |
481 | */ | |
482 | virtual IOReturn reportRemovability(bool *isRemovable); | |
483 | ||
484 | /*! | |
485 | * @function reportWriteProtection | |
486 | * @abstract | |
487 | * Report whether the media is write-protected or not. | |
488 | * @discussion | |
489 | * The default implementation of this method issues a SCSI Mode Sense | |
490 | * command to test the WP bit( 0x80 of byte 2 of the Mode Sense Header | |
491 | * data). A request is made for Mode Sense Page 1, though any valid | |
492 | * page will return a header. If the bit is set, the media is considered | |
493 | * write-protected. | |
494 | * @param isWriteProtected | |
495 | * Pointer to returned result. True indicates that the media is write-protected (it | |
496 | * cannot be written); False indicates that the media is not write-protected (it | |
497 | * is permissible to write). | |
498 | */ | |
499 | virtual IOReturn reportWriteProtection(bool *isWriteProtected); | |
500 | ||
501 | protected: | |
502 | ||
503 | /*! | |
504 | * @function createReadCdb | |
505 | * @abstract | |
506 | * Create a SCSI CDB for a read operation. | |
507 | * @discussion | |
508 | * Override this to control the cdb created for a read operation. | |
509 | * The default implementation creates a 10-byte read command with | |
510 | * disconnect allowed, 8-byte autosense, and a 2-second timeout. | |
511 | * @param cdb | |
512 | * A pointer to the CDB bytes. | |
513 | * @param cdbLength | |
514 | * The length of the CDB in bytes. | |
515 | * @param block | |
516 | * The device block to be read. | |
517 | * @param nblks | |
518 | * The number of blocks to be transferred. | |
519 | * @param maxAutoSenseLength | |
520 | * The maximum size of the autosense data, in bytes. A value of zero | |
521 | * will disable autosense. | |
522 | * @param timeoutSeconds | |
523 | * The command timeout in seconds. | |
524 | * @result | |
525 | * The IOSCSICommandOptions returned will be used to issue the command. | |
526 | */ | |
527 | virtual UInt32 createReadCdb( | |
528 | UInt8 *cdb, /* in */ | |
529 | UInt32 *cdbLength, /* out */ | |
530 | UInt32 block, /* in */ | |
531 | UInt32 nblks, /* in */ | |
532 | UInt32 *maxAutoSenseLength, /* out */ | |
533 | UInt32 *timeoutSeconds); /* out */ | |
534 | ||
535 | /*! | |
536 | * @function createWriteCdb | |
537 | * @abstract | |
538 | * Create a SCSI CDB for a write operation. | |
539 | * @discussion | |
540 | * Override this to control the cdb created for a write operation. | |
541 | * The default implementation creates a 10-byte write command with | |
542 | * disconnect allowed, 8-byte autosense, and a 2-second timeout. | |
543 | * @param cdb | |
544 | * A pointer to the CDB bytes. | |
545 | * @param cdbLength | |
546 | * The length of the CDB in bytes. | |
547 | * @param block | |
548 | * The device block to be written. | |
549 | * @param nblks | |
550 | * The number of blocks to be transferred. | |
551 | * @param maxAutoSenseLength | |
552 | * The maximum size of the autosense data, in bytes. A value of zero | |
553 | * will disable autosense. | |
554 | * @param timeoutSeconds | |
555 | * The command timeout in seconds. | |
556 | * @result | |
557 | * The IOSCSICommandOptions returned will be used to issue the command. | |
558 | */ | |
559 | virtual UInt32 createWriteCdb( | |
560 | UInt8 *cdb, /* in */ | |
561 | UInt32 *cdbLength, /* out */ | |
562 | UInt32 block, /* in */ | |
563 | UInt32 nblks, /* in */ | |
564 | UInt32 *maxAutoSenseLength, /* out */ | |
565 | UInt32 *timeoutSeconds); /* out */ | |
566 | ||
567 | ||
568 | /*! | |
569 | * @function doInquiry | |
570 | * @abstract | |
571 | * Obtain SCSI Inquiry data from the device. | |
572 | * @discussion | |
573 | * This method issues a SCSI Inquiry command to the device, to obtain | |
574 | * the result in the supplied buffer. The method first issues an | |
575 | * inquiry with a 5-byte length, to obtain the full length of the | |
576 | * devices inquiry data. The second Inquiry command is issued to get | |
577 | * the full inquiry data (limited to maxLen, of course). | |
578 | * @param inqBuf | |
579 | * A pointer to the buffer. | |
580 | * @param maxLen | |
581 | * The maximum number of bytes the buffer can contain. | |
582 | * @param actualLen | |
583 | * A pointer to the returned byte count actually transferred. | |
584 | */ | |
585 | virtual IOReturn doInquiry(UInt8 *inqBuf,UInt32 maxLen,UInt32 *actualLen); | |
586 | ||
587 | /* ---------------- Internally used methods. ---------------- */ | |
588 | ||
589 | /* | |
590 | * @group | |
591 | * Internally Used Methods | |
592 | * @discussion | |
593 | * These methods are used internally, and will not generally be modified. | |
594 | */ | |
595 | ||
596 | /*! | |
597 | * @function allocateContext | |
598 | * @abstract | |
599 | * Allocate a context structure for use with the current IO operation. | |
600 | */ | |
601 | virtual struct context * allocateContext(void); | |
602 | ||
603 | /*! | |
604 | * @function allocateInquiryBuffer | |
605 | * @abstract | |
606 | * Allocate an inquiry buffer. | |
607 | * @param buf | |
608 | * A pointer for the returned buffer pointer. | |
609 | * @param size | |
610 | * The requested size of the buffer, in bytes. | |
611 | */ | |
612 | virtual IOReturn allocateInquiryBuffer(UInt8 **buf,UInt32 size); | |
613 | ||
614 | /*! | |
615 | * @function allocateTempBuffer | |
616 | * @abstract | |
617 | * Allocate a buffer for temporary use. | |
618 | * @param buf | |
619 | * A pointer for the returned buffer pointer. | |
620 | * @param size | |
621 | * The requested size of the buffer, in bytes. | |
622 | */ | |
623 | virtual IOReturn allocateTempBuffer(UInt8 **buf,UInt32 size); | |
624 | ||
625 | /*! | |
626 | * @function allocateReadCapacityBuffer | |
627 | * @abstract | |
628 | * Allocate a buffer for Read-Capacity data. | |
629 | * @param buf | |
630 | * A pointer for the returned buffer pointer. | |
631 | * @param size | |
632 | * The requested size of the buffer, in bytes. | |
633 | */ | |
634 | virtual IOReturn allocateReadCapacityBuffer(UInt8 **buf,UInt8 size); | |
635 | ||
636 | /*! | |
637 | * @function automaticRetry | |
638 | * @abstract | |
639 | * Return TRUE if we should automatically retry the command just completed. | |
640 | * @discussion | |
641 | * The default implementation of this method reacts to Unit Attention and | |
642 | * Bus Reset conditions, possibly starting the recovery processes for those | |
643 | * conditions and arranging that the subject command is retried after | |
644 | * the recovery procedure finishes. | |
645 | * @param cx | |
646 | * A pointer to the context for the command just completed. | |
647 | */ | |
648 | virtual bool automaticRetry(struct context *cx); | |
649 | ||
650 | /*! | |
651 | * @function beginBusResetRecovery | |
652 | * @abstract | |
653 | * Begin the Bus Reset recovery process. | |
654 | * @discussion | |
655 | * This method can be overridden to issue the first command necessary | |
656 | * to perform the Bus Reset recovery process for the device. | |
657 | * | |
658 | * The default implementation does nothing and simply calls finishBusResetRecovery. | |
659 | */ | |
660 | virtual void beginBusResetRecovery(void); | |
661 | ||
662 | /*! | |
663 | * @function beginUnitAttentionRecovery | |
664 | * @abstract | |
665 | * Begin the Unit Attention recovery process. | |
666 | * @discussion | |
667 | * This method can be overridden to issue the first command necessary | |
668 | * to perform the Bus Reset recovery process for the device. | |
669 | * | |
670 | * The default implementation does nothing and simply calls finishUnitAttentionRecovery. | |
671 | */ | |
672 | virtual void beginUnitAttentionRecovery(void); | |
673 | ||
674 | /*! | |
675 | * @function busResetRecoveryCommandComplete | |
676 | * @abstract | |
677 | * Handle a command completion during the Bus Reset recovery process. | |
678 | * @discussion | |
679 | * This method can be overridden to check the result of each command issued | |
680 | * during the Bus Reset recovery process for the device. Typically it would | |
681 | * bump the "step" value and issue the next command, calling finishBusResetRecovery | |
682 | * when the process is complete. | |
683 | * | |
684 | * The default implementation does nothing. | |
685 | */ | |
686 | virtual void busResetRecoveryCommandComplete(struct context *cx); | |
687 | ||
688 | /*! | |
689 | * @function customAutomaticRetry | |
690 | * @abstract | |
691 | * Return TRUE if we should automatically retry the command just completed. | |
692 | * @discussion | |
693 | * This method should be overridden to allow checking for, and causing, an | |
694 | * automatic retry of a command. | |
695 | * | |
696 | * The default implementation of this method does nothing except return FALSE. | |
697 | * @param cx | |
698 | * A pointer to the context for the command just completed. | |
699 | */ | |
700 | virtual bool customAutomaticRetry(struct context *cx); | |
701 | ||
702 | /*! | |
703 | * @function deleteContext | |
704 | * @abstract | |
705 | * Delete a context structure. | |
706 | * @discussion | |
707 | * This method also issues a "release" for the IO buffer and/or lock, if any. | |
708 | * @param cx | |
709 | * A pointer to the context structure to be deleted. | |
710 | */ | |
711 | virtual void deleteContext(struct context *cx); | |
712 | ||
713 | /*! | |
714 | * @function deleteInquiryBuffer | |
715 | * @abstract | |
716 | * Delete an inquiry data buffer. | |
717 | * @param buf | |
718 | * A pointer to the buffer. | |
719 | * @param size | |
720 | * The requested size of the buffer, in bytes. | |
721 | */ | |
722 | virtual void deleteInquiryBuffer(UInt8 *buf,UInt32 size); | |
723 | ||
724 | /*! | |
725 | * @function deleteTempBuffer | |
726 | * @abstract | |
727 | * Delete a temporary data buffer. | |
728 | * @param buf | |
729 | * A pointer to the buffer. | |
730 | * @param len | |
731 | * The requested size of the buffer, in bytes. | |
732 | */ | |
733 | virtual void deleteTempBuffer(UInt8 *buf,UInt32 len); | |
734 | ||
735 | /*! | |
736 | * @function deleteReadCapacityBuffer | |
737 | * @abstract | |
738 | * Delete a Read-Capacity data buffer. | |
739 | * @param buf | |
740 | * A pointer to the buffer. | |
741 | * @param len | |
742 | * The requested size of the buffer, in bytes. | |
743 | */ | |
744 | virtual void deleteReadCapacityBuffer(UInt8 *buf,UInt32 len); | |
745 | ||
746 | /*! | |
747 | * @function doReadCapacity | |
748 | * @abstract | |
749 | * @discussion | |
750 | * The default implementation of this method issues a standard SCSI | |
751 | * Read Capacity command. The block size and maximum valid block are | |
752 | * extracted from the returned data in an endian-neutral way. | |
753 | * @param blockSize | |
754 | * A pointer to the returned block size value. | |
755 | * @param maxBlock | |
756 | * A pointer to the returned maximum block number. | |
757 | */ | |
758 | virtual IOReturn doReadCapacity(UInt64 *blockSize,UInt64 *maxBlock); | |
759 | ||
760 | /*! | |
761 | * @function finishBusResetRecovery | |
762 | * @abstract | |
763 | * Finish up after the Bus Reset recovery process is complete. | |
764 | * @discussion | |
765 | * This method would usually not require an override. | |
766 | */ | |
767 | virtual void finishBusResetRecovery(void); | |
768 | ||
769 | /*! | |
770 | * @function finishUnitAttentionRecovery | |
771 | * @abstract | |
772 | * Finish up after the Unit Attention recovery process is complete. | |
773 | * @discussion | |
774 | * This method would usually not require an override. | |
775 | */ | |
776 | virtual void finishUnitAttentionRecovery(void); | |
777 | ||
778 | /*! | |
779 | * @function getBlockSize | |
780 | * @abstract | |
781 | * Return the device block size. | |
782 | * @discussion | |
783 | * This method obtains the block size from the Read-Capacity data. If RC data is | |
784 | * not yet cached, a call is made to doReadCapacity to obtain the data. | |
785 | */ | |
786 | virtual UInt64 getBlockSize(void); | |
787 | ||
788 | ||
789 | /*! | |
790 | * @function dequeueCommands | |
791 | * @abstract | |
792 | * Dequeue commands previously enqueued awaiting the proper device power level. | |
793 | * @discussion | |
794 | * This method is called when a command is queued (from queueCommand), when a call | |
795 | * completes (from RWCompletion), and when the device power level changes. All commands | |
796 | * for which the device power level is proper are immediately dequeued. | |
797 | * | |
798 | * Queued synchronous commands are simply "awakened" by unlocking a lock. The originating | |
799 | * thread then continues and issues the command. Asynchronous commands are immediately | |
800 | * dispatched via a call to standardAsyncReadWriteExecute. | |
801 | */ | |
802 | virtual void dequeueCommands(void); | |
803 | ||
804 | /*! | |
805 | * @function queueCommand | |
806 | * @abstract | |
807 | * Queue commands awaiting the proper device power level. | |
808 | * @discussion | |
809 | * This method is called prior to issuing any IO command, so that each command can | |
810 | * be enqueued awaiting its desired device power level. After queuing the command, a | |
811 | * call is made to dequeueCommands to attempt to dequeue any available command that can | |
812 | * be executed (including the one just queued). Putting commands into the queue ensures | |
813 | * that the proper sequence is maintained. | |
814 | * @param cx | |
815 | * The context for the command being queued. | |
816 | * @param isSync | |
817 | * True if the command is synchronous; False if the command is asynchronous. | |
818 | * @param desiredPower | |
819 | * The device power level needed before the command can execute. | |
820 | */ | |
821 | virtual void queueCommand(struct context *cx,bool isSync,UInt32 desiredPower); | |
822 | ||
823 | /*! | |
824 | * @function RWCompletion | |
825 | * @abstract | |
826 | * Asynchronous read/write completion routine. | |
827 | * @discussion | |
828 | * A subclass must implement the read-write completion, called upon completion | |
829 | * of an IO started by doAsyncReadWrite. | |
830 | * @param cx | |
831 | * A pointer to the context structure for the completing command. | |
832 | */ | |
833 | virtual void RWCompletion(struct context *cx) = 0; | |
834 | ||
835 | /*! | |
836 | * @function setupBusResetRecovery | |
837 | * @abstract | |
838 | * Set up to begin Bus Reset recovery. | |
839 | * @discussion | |
840 | * This method would usually not require an override. | |
841 | */ | |
842 | virtual void setupBusResetRecovery(void); | |
843 | ||
844 | /*! | |
845 | * @function setupUnitAttentionRecovery | |
846 | * @abstract | |
847 | * Set up to begin Unit Attention recovery. | |
848 | * @discussion | |
849 | * This method would usually not require an override. | |
850 | */ | |
851 | virtual void setupUnitAttentionRecovery(struct context *cx); | |
852 | ||
853 | /*! | |
854 | * @function simpleAsynchIO | |
855 | * @abstract | |
856 | * Issue a simple asynchronous SCSI command. | |
857 | * @discussion | |
858 | * This method issues a single SCSI command. | |
859 | * The SCSI command must already be set up in the context structure. | |
860 | * @param cx | |
861 | * A pointer to the context structure for the command. | |
862 | */ | |
863 | virtual IOReturn simpleAsynchIO(struct context *cx); | |
864 | ||
865 | /*! | |
866 | * @function simpleSynchIO | |
867 | * @abstract | |
868 | * Issue a simple synchronous SCSI command. | |
869 | * @discussion | |
870 | * This method issues a single SCSI command and waits for the command | |
871 | * to complete. The SCSI command must already be set up in the context | |
872 | * structure. | |
873 | * @param cx | |
874 | * A pointer to the context structure for the command. | |
875 | */ | |
876 | virtual IOReturn simpleSynchIO(struct context *cx); | |
877 | ||
878 | /*! | |
879 | * @function standardAsyncReadWrite | |
880 | * @abstract | |
881 | * Start an asynchronous read or write operation. | |
882 | * @discussion | |
883 | * This method starts an asynchronous read or write operation. No | |
884 | * incoming parameters are validated. The default implementation | |
885 | * calls createReadCdb or createWriteCdb, | |
886 | * then issues a SCSI command to IOSCSIDevice. If the command is | |
887 | * accepted, then the completion will be called at some future time. | |
888 | * @result | |
889 | * The only possible returns from this method are: | |
890 | * | |
891 | * kIOReturnSuccess, meaning that the IO was accepted by the transport | |
892 | * drivers provider (e.g. IOSCSIDevice), and that the completion | |
893 | * function will be called when the IO completes, i.e. target->action(param). | |
894 | * | |
895 | * kIOReturnNoMemory, meaning that memory allocation failed. | |
896 | * | |
897 | * Other kIOReturn codes from the provider which occurred | |
898 | * because the IO was not accepted in that provider's queue. This | |
899 | * might indicate a full queue or bad parameter. | |
900 | * @param buffer | |
901 | * An IOMemoryDescriptor describing the data-transfer buffer. The data direction | |
902 | * is contained in the IOMemoryDescriptor. Responsiblity for releasing the descriptor | |
903 | * rests with the caller. | |
904 | * @param block | |
905 | * The starting block number of the data transfer. | |
906 | * @param nblks | |
907 | * The integral number of blocks to be transferred. | |
908 | * @param action | |
909 | * The C function called upon completion of the data transfer. | |
910 | * @param target | |
911 | * The C++ class "this" pointer, passed as an argument to "action." | |
912 | * @param param | |
913 | * This value is passed as an argument to "action." It is not validated or modified. | |
914 | */ | |
915 | virtual IOReturn standardAsyncReadWrite(IOMemoryDescriptor *buffer, | |
916 | UInt32 block,UInt32 nblks, | |
917 | IOStorageCompletion completion); | |
918 | ||
919 | /*! | |
920 | * @function standardAsyncReadWriteExecute | |
921 | * @abstract | |
922 | * Issue an asynchronous read/write operation after dequeuing. | |
923 | * @param cx | |
924 | * A pointer to the context structure for the command. | |
925 | */ | |
926 | virtual IOReturn standardAsyncReadWriteExecute(struct context *cx); | |
927 | ||
928 | /*! | |
929 | * @function standardSyncReadWrite | |
930 | * Perform a synchronous read or write operation. | |
931 | * @param buffer | |
932 | * An IOMemoryDescriptor describing the data-transfer buffer. The data direction | |
933 | * is contained in the IOMemoryDescriptor. Responsiblity for releasing the descriptor | |
934 | * rests with the caller. | |
935 | * @param block | |
936 | * The starting block number of the data transfer. | |
937 | * @param nblks | |
938 | * The integral number of blocks to be transferred. | |
939 | */ | |
940 | virtual IOReturn standardSyncReadWrite(IOMemoryDescriptor *buffer,UInt32 block,UInt32 nblks); | |
941 | ||
942 | /*! | |
943 | * @function stringFromState | |
944 | * @abstract | |
945 | * Return a string description of a state value. | |
946 | * @discussion | |
947 | * Used for debugging. | |
948 | * @param state | |
949 | * The state to be converted to a string description. | |
950 | */ | |
951 | virtual char * stringFromState(stateValue state); | |
952 | ||
953 | /*! | |
954 | * @function unitAttentionRecoveryCommandComplete | |
955 | * @abstract | |
956 | * Handle a command completion during the Unit Attention recovery process. | |
957 | * @discussion | |
958 | * This method can be overridden to check the result of each command issued | |
959 | * during the Unit Attention recovery process for the device. Typically it would | |
960 | * bump the "step" value and issue the next command, calling finishUnitAttentionRecovery | |
961 | * when the process is complete. | |
962 | * | |
963 | * The default implementation does nothing. | |
964 | */ | |
965 | virtual void unitAttentionRecoveryCommandComplete(struct context *cx); | |
966 | ||
967 | /*! | |
968 | * @function unitAttentionDetected | |
969 | * @abstract | |
970 | * Determine if a Unit Attention condition occurred. | |
971 | * @param cx | |
972 | * A pointer to the context structure for the command just executed. | |
973 | */ | |
974 | virtual bool unitAttentionDetected(struct context *cx); | |
975 | ||
976 | public: | |
977 | ||
978 | /*! | |
979 | * @function genericCompletion | |
980 | * @abstract | |
981 | * Generic IO completion function. | |
982 | * @discussion | |
983 | * This method handles completion of a SCSI command. It implements a | |
984 | * simple state machine to handle a Unit Attention condition on a | |
985 | * command. | |
986 | * | |
987 | * This method must be public so we can reach it from | |
988 | * the C-language callback "glue" routine. It should not be called | |
989 | * from outside this class. | |
990 | * | |
991 | * | |
992 | * | |
993 | * If a Unit Attention condition occurs, we set the state to | |
994 | * kHandlingUnitAttention and call handleUnitAttention to do whatever | |
995 | * is necessary to clear the condition. Eventually, handleUnitAttention | |
996 | * resets the state to kDoneHandlingUnitAttention, which will allow | |
997 | * the state machine to reissue the original command. | |
998 | * | |
999 | * If we are already processing a Unit Attention, then genericCompletion | |
1000 | * increments a step counter and calls handleUnitAttention. The step | |
1001 | * counter allows handleUnitAttention to issue multiple SCSI commands | |
1002 | * to clear the condition. The handleUnitAttention method is called | |
1003 | * repeatedly, until the state is set to kDoneHandlingUnitAttention. | |
1004 | * | |
1005 | * If this operation is a normal asynchronous read or write (usually | |
1006 | * started by standardAsyncReadWrite, though this is not required), | |
1007 | * then a call is made to RWCompletion, followed by deletion of the | |
1008 | * context structure for the command. RWCompletion is implemented by | |
1009 | * the subclass of IOBasicSCSI, for example in IOSCSIHDDrive. | |
1010 | * @param cx | |
1011 | * A pointer to the context structure for the command. | |
1012 | */ | |
1013 | virtual void genericCompletion(struct context *cx); | |
1014 | ||
1015 | /* | |
1016 | * @endgroup | |
1017 | */ | |
1018 | ||
1019 | protected: | |
1020 | ||
1021 | /* | |
1022 | * @group | |
1023 | * Power Management Methods | |
1024 | * @discussion | |
1025 | * A subclass must implement these to report the power level required to do various commands. | |
1026 | */ | |
1027 | ||
1028 | /*! | |
1029 | * @function getExecuteCDBPowerState | |
1030 | * @abstract | |
1031 | * Return the required device power level to execute a client CDB. | |
1032 | */ | |
1033 | virtual UInt32 getExecuteCDBPowerState(void) = 0; | |
1034 | ||
1035 | /*! | |
1036 | * @function getInquiryPowerState | |
1037 | * @abstract | |
1038 | * Return the required device power level to issue an Inquiry command. | |
1039 | */ | |
1040 | virtual UInt32 getInquiryPowerState(void) = 0; | |
1041 | ||
1042 | /*! | |
1043 | * @function getReadCapacityPowerState | |
1044 | * @abstract | |
1045 | * Return the required device power level to issue a Read Capacity command. | |
1046 | */ | |
1047 | virtual UInt32 getReadCapacityPowerState(void) = 0; | |
1048 | ||
1049 | /*! | |
1050 | * @function getReadWritePowerState | |
1051 | * @abstract | |
1052 | * Return the required device power level to issue a data read or write. | |
1053 | */ | |
1054 | virtual UInt32 getReadWritePowerState(void) = 0; | |
1055 | ||
1056 | /*! | |
1057 | * @function getReportWriteProtectionPowerState | |
1058 | * @abstract | |
1059 | * Return the required device power level to determine media write protection. | |
1060 | */ | |
1061 | virtual UInt32 getReportWriteProtectionPowerState(void) = 0; | |
1062 | ||
1063 | /*! | |
1064 | * @function powerTickle | |
1065 | * @abstract | |
1066 | * Check for the device power state currently being in the desired state. | |
1067 | * @discussion | |
1068 | * A subclass must implement powerTickle, which is called when we desire power to | |
1069 | * execute a command. PowerTickle may handle generic or a subclass-expanded set of | |
1070 | * power states. The implementation will usually relay the call to the Power Management | |
1071 | * subsystem function activityTickle. For a device without power management capability, | |
1072 | * the implementation should always return True. | |
1073 | * @param desiredState | |
1074 | * The desired device power level. | |
1075 | * @result | |
1076 | * True if power is in the desired state (or better); False if the caller must wait | |
1077 | * until power is available. | |
1078 | */ | |
1079 | virtual bool powerTickle(UInt32 desiredState) = 0; | |
1080 | ||
1081 | /* | |
1082 | * @endgroup | |
1083 | */ | |
1084 | ||
1085 | /*! | |
1086 | * @var _provider | |
1087 | * A pointer to our provider. | |
1088 | */ | |
1089 | IOSCSIDevice * _provider; | |
1090 | ||
1091 | /*! | |
1092 | * @var _busResetContext | |
1093 | * A pointer to a context struct to be used by recoverAfterBusReset. | |
1094 | */ | |
1095 | struct context * _busResetContext; | |
1096 | ||
1097 | /*! | |
1098 | * @var _unitAttentionContext | |
1099 | * A pointer to a context struct to be used by handleUnitAttention. | |
1100 | */ | |
1101 | struct context * _unitAttentionContext; | |
1102 | ||
1103 | /*! | |
1104 | * @var _busResetRecoveryInProgress | |
1105 | * True if recovery from Bus Reset is in progress. | |
1106 | */ | |
1107 | bool _busResetRecoveryInProgress; | |
1108 | ||
1109 | /*! | |
1110 | * @var _unitAttentionRecoveryInProgress | |
1111 | * True if recovery from Unit Attention is in progress. | |
1112 | */ | |
1113 | bool _unitAttentionRecoveryInProgress; | |
1114 | ||
1115 | /* Device information : */ | |
1116 | ||
1117 | /*! | |
1118 | * @var _inqBuf | |
1119 | * A pointer to the allocate Inquiry Data buffer. | |
1120 | */ | |
1121 | UInt8 * _inqBuf; /* the Inquiry data buffer */ | |
1122 | ||
1123 | /*! | |
1124 | * @var _inqBufSize | |
1125 | * The size of the inquiry data buffer, in bytes. | |
1126 | */ | |
1127 | UInt32 _inqBufSize; /* size of the buffer */ | |
1128 | ||
1129 | /*! | |
1130 | * @var _inqLen | |
1131 | * The number of valid bytes of inquiry data. | |
1132 | */ | |
1133 | UInt32 _inqLen; /* valid bytes in buffer */ | |
1134 | ||
1135 | /*! | |
1136 | * @var _vendor | |
1137 | * The Vendor Name string from the inquiry data, null-terminated. | |
1138 | */ | |
1139 | char _vendor[9]; /* info from Inquiry data */ | |
1140 | ||
1141 | /*! | |
1142 | * @var _product | |
1143 | * The Product Name string from the inquiry data, null-terminated. | |
1144 | */ | |
1145 | char _product[17]; | |
1146 | ||
1147 | /*! | |
1148 | * @var _rev | |
1149 | * The Product Revision string from the inquiry data, null-terminated. | |
1150 | */ | |
1151 | char _rev[5]; | |
1152 | ||
1153 | /* Since we get both of these items from the same command, we | |
1154 | * just cache both values if we get either call, so we only | |
1155 | * have to issue the command once. | |
1156 | */ | |
1157 | ||
1158 | /*! | |
1159 | * @var _readCapDone | |
1160 | * True if we have issued a Read-Capacity command to obtain the | |
1161 | * values for _maxBlock and _blockSize. | |
1162 | */ | |
1163 | bool _readCapDone; | |
1164 | ||
1165 | /*! | |
1166 | * @var _removable | |
1167 | * True if the media is removable; False if the media is fixed. | |
1168 | */ | |
1169 | bool _removable; | |
1170 | ||
1171 | /*! | |
1172 | * @var _maxBlock | |
1173 | * The highest valid block on the media, relative to zero. | |
1174 | */ | |
1175 | UInt64 _maxBlock; | |
1176 | ||
1177 | /*! | |
1178 | * @var _blockSize | |
1179 | * The block size of the media in bytes. | |
1180 | */ | |
1181 | UInt64 _blockSize; | |
1182 | ||
1183 | /* The queue of pending requests awaiting power: */ | |
1184 | ||
1185 | /*! | |
1186 | * @struct queue | |
1187 | * @discussion | |
1188 | * A data structure for a queue. | |
1189 | * @field head | |
1190 | * A pointer to the head item. | |
1191 | * @field tail | |
1192 | * A pointer to the tail item. | |
1193 | * @field lock | |
1194 | * A lock used to protect the queue during changes. | |
1195 | */ | |
1196 | /*! | |
1197 | * @var _powerQueue | |
1198 | * A queue structure containing operations queued awaiting power level. | |
1199 | */ | |
1200 | struct queue { | |
1201 | struct context * head; | |
1202 | struct context * tail; | |
1203 | IOLock * lock; | |
1204 | } _powerQueue; | |
1205 | ||
1206 | }; | |
1207 | #endif |