]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiScsiLib/UefiScsiLib.c
Minor grammatical work--mostly adding periods. Items with ONLY period added did...
[mirror_edk2.git] / MdePkg / Library / UefiScsiLib / UefiScsiLib.c
1 /** @file
2 UEFI SCSI Library implementation
3
4 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include <Uefi.h>
17 #include <Library/BaseLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/UefiScsiLib.h>
20 #include <Library/BaseMemoryLib.h>
21
22 #include <IndustryStandard/Scsi.h>
23
24
25 //
26 // Max bytes needed to represent ID of a SCSI device
27 //
28 #define EFI_SCSI_TARGET_MAX_BYTES (0x10)
29
30 //
31 // bit5..7 are for Logical unit number
32 // 11100000b (0xe0)
33 //
34 #define EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK 0xe0
35
36 //
37 // Scsi Command Length
38 //
39 #define EFI_SCSI_OP_LENGTH_SIX 0x6
40 #define EFI_SCSI_OP_LENGTH_TEN 0xa
41 #define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10
42
43
44
45 /**
46 Execute Test Unit Ready SCSI command on a specific SCSI target.
47
48 Executes the Test Unit Ready command on the SCSI target specified by ScsiIo.
49 If Timeout is zero, then this function waits indefinitely for the command to complete.
50 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
51 If ScsiIo is NULL, then ASSERT().
52 If SenseDataLength is NULL, then ASSERT().
53 If HostAdapterStatus is NULL, then ASSERT().
54 If TargetStatus is NULL, then ASSERT().
55
56
57 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
58 for the specific SCSI target.
59 @param[in] Timeout The timeout in 100 ns units to use for the execution
60 of this SCSI Request Packet. A Timeout value of
61 zero means that this function will wait indefinitely
62 for the SCSI Request Packet to execute. If Timeout
63 is greater than zero, then this function will return
64 EFI_TIMEOUT if the time required to execute the SCSI
65 Request Packet is greater than Timeout.
66 @param[in, out] SenseData A pointer to sense data that was generated by
67 the execution of the SCSI Request Packet. This
68 buffer must be allocated by the caller.
69 If SenseDataLength is 0, then this parameter is
70 optional and may be NULL.
71 @param[in, out] SenseDataLength On input, a pointer to the length in bytes of
72 the SenseData buffer. On output, a pointer to
73 the number of bytes written to the SenseData buffer.
74 @param[out] HostAdapterStatus The status of the SCSI Host Controller that produces
75 the SCSI bus containing the SCSI target specified by
76 ScsiIo when the SCSI Request Packet was executed.
77 See the EFI SCSI I/O Protocol in the UEFI Specification
78 for details on the possible return values.
79 @param[out] TargetStatus The status returned by the SCSI target specified
80 by ScsiIo when the SCSI Request Packet was executed
81 on the SCSI Host Controller. See the EFI SCSI I/O
82 Protocol in the UEFI Specification for details on
83 the possible return values.
84
85 @retval EFI_SUCCESS The command was executed successfully.
86 See HostAdapterStatus, TargetStatus, SenseDataLength,
87 and SenseData in that order for additional status
88 information.
89 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
90 there are too many SCSI Command Packets already
91 queued. The SCSI Request Packet was not sent, so
92 no additional status information is available.
93 The caller may retry again later.
94 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
95 SCSI Request Packet. See HostAdapterStatus,
96 TargetStatus, SenseDataLength, and SenseData in that
97 order for additional status information.
98 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
99 is not supported by the SCSI initiator(i.e., SCSI
100 Host Controller). The SCSI Request Packet was not
101 sent, so no additional status information is available.
102 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
103 Packet to execute. See HostAdapterStatus, TargetStatus,
104 SenseDataLength, and SenseData in that order for
105 additional status information.
106
107 **/
108 EFI_STATUS
109 EFIAPI
110 ScsiTestUnitReadyCommand (
111 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
112 IN UINT64 Timeout,
113 IN OUT VOID *SenseData, OPTIONAL
114 IN OUT UINT8 *SenseDataLength,
115 OUT UINT8 *HostAdapterStatus,
116 OUT UINT8 *TargetStatus
117 )
118 {
119 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
120 UINT64 Lun;
121 UINT8 *Target;
122 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
123 EFI_STATUS Status;
124 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
125
126 ASSERT (SenseDataLength != NULL);
127 ASSERT (HostAdapterStatus != NULL);
128 ASSERT (TargetStatus != NULL);
129 ASSERT (ScsiIo != NULL);
130
131 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
132 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
133
134 CommandPacket.Timeout = Timeout;
135 CommandPacket.InDataBuffer = NULL;
136 CommandPacket.InTransferLength= 0;
137 CommandPacket.OutDataBuffer = NULL;
138 CommandPacket.OutTransferLength= 0;
139 CommandPacket.SenseData = SenseData;
140 CommandPacket.Cdb = Cdb;
141 //
142 // Fill Cdb for Test Unit Ready Command
143 //
144 Target = &TargetArray[0];
145 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
146
147 Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY;
148 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
149 CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
150 CommandPacket.SenseDataLength = *SenseDataLength;
151
152 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
153
154 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
155 *TargetStatus = CommandPacket.TargetStatus;
156 *SenseDataLength = CommandPacket.SenseDataLength;
157
158 return Status;
159 }
160
161
162 /**
163 Execute Inquiry SCSI command on a specific SCSI target.
164
165 Executes the Inquiry command on the SCSI target specified by ScsiIo.
166 If Timeout is zero, then this function waits indefinitely for the command to complete.
167 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
168 If ScsiIo is NULL, then ASSERT().
169 If SenseDataLength is NULL, then ASSERT().
170 If HostAdapterStatus is NULL, then ASSERT().
171 If TargetStatus is NULL, then ASSERT().
172 If InquiryDataLength is NULL, then ASSERT().
173
174 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
175 for the specific SCSI target.
176 @param[in] Timeout The timeout in 100 ns units to use for the
177 execution of this SCSI Request Packet. A Timeout
178 value of zero means that this function will wait
179 indefinitely for the SCSI Request Packet to execute.
180 If Timeout is greater than zero, then this function
181 will return EFI_TIMEOUT if the time required to
182 execute the SCSI Request Packet is greater than Timeout.
183 @param[in, out] SenseData A pointer to sense data that was generated
184 by the execution of the SCSI Request Packet.
185 This buffer must be allocated by the caller.
186 If SenseDataLength is 0, then this parameter
187 is optional and may be NULL.
188 @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
189 On output, the number of bytes written to the SenseData buffer.
190 @param[out] HostAdapterStatus The status of the SCSI Host Controller that
191 produces the SCSI bus containing the SCSI
192 target specified by ScsiIo when the SCSI
193 Request Packet was executed. See the EFI
194 SCSI I/O Protocol in the UEFI Specification
195 for details on the possible return values.
196 @param[out] TargetStatus The status returned by the SCSI target specified
197 by ScsiIo when the SCSI Request Packet was
198 executed on the SCSI Host Controller.
199 See the EFI SCSI I/O Protocol in the UEFI
200 Specification for details on the possible
201 return values.
202 @param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated
203 by the execution of the SCSI Request Packet.
204 This buffer must be allocated by the caller.
205 If InquiryDataLength is 0, then this parameter
206 is optional and may be NULL.
207 @param[in, out] InquiryDataLength On input, a pointer to the length in bytes
208 of the InquiryDataBuffer buffer.
209 On output, a pointer to the number of bytes
210 written to the InquiryDataBuffer buffer.
211 @param[in] EnableVitalProductData If TRUE, then the supported vital product
212 data is returned in InquiryDataBuffer.
213 If FALSE, then the standard inquiry data is
214 returned in InquiryDataBuffer.
215
216 @retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus,
217 TargetStatus, SenseDataLength, and SenseData in that order
218 for additional status information.
219 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
220 InquiryDataBuffer could not be transferred. The actual
221 number of bytes transferred is returned in InquiryDataLength.
222 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there
223 are too many SCSI Command Packets already queued.
224 The SCSI Request Packet was not sent, so no additional
225 status information is available. The caller may retry again later.
226 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI
227 Request Packet. See HostAdapterStatus, TargetStatus,
228 SenseDataLength, and SenseData in that order for additional
229 status information.
230 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not
231 supported by the SCSI initiator(i.e., SCSI Host Controller).
232 The SCSI Request Packet was not sent, so no additional
233 status information is available.
234 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
235 Packet to execute. See HostAdapterStatus, TargetStatus,
236 SenseDataLength, and SenseData in that order for
237 additional status information.
238
239 **/
240 EFI_STATUS
241 EFIAPI
242 ScsiInquiryCommand (
243 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
244 IN UINT64 Timeout,
245 IN OUT VOID *SenseData, OPTIONAL
246 IN OUT UINT8 *SenseDataLength,
247 OUT UINT8 *HostAdapterStatus,
248 OUT UINT8 *TargetStatus,
249 IN OUT VOID *InquiryDataBuffer, OPTIONAL
250 IN OUT UINT32 *InquiryDataLength,
251 IN BOOLEAN EnableVitalProductData
252 )
253 {
254 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
255 UINT64 Lun;
256 UINT8 *Target;
257 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
258 EFI_STATUS Status;
259 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
260
261 ASSERT (SenseDataLength != NULL);
262 ASSERT (HostAdapterStatus != NULL);
263 ASSERT (TargetStatus != NULL);
264 ASSERT (InquiryDataLength != NULL);
265 ASSERT (ScsiIo != NULL);
266
267 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
268 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
269
270 CommandPacket.Timeout = Timeout;
271 CommandPacket.InDataBuffer = InquiryDataBuffer;
272 CommandPacket.InTransferLength= *InquiryDataLength;
273 CommandPacket.SenseData = SenseData;
274 CommandPacket.SenseDataLength = *SenseDataLength;
275 CommandPacket.Cdb = Cdb;
276
277 Target = &TargetArray[0];
278 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
279
280 Cdb[0] = EFI_SCSI_OP_INQUIRY;
281 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
282 if (EnableVitalProductData) {
283 Cdb[1] |= 0x01;
284 }
285
286 if (*InquiryDataLength > 0xff) {
287 *InquiryDataLength = 0xff;
288 }
289
290 Cdb[4] = (UINT8) (*InquiryDataLength);
291 CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
292 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
293
294 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
295
296 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
297 *TargetStatus = CommandPacket.TargetStatus;
298 *SenseDataLength = CommandPacket.SenseDataLength;
299 *InquiryDataLength = CommandPacket.InTransferLength;
300
301 return Status;
302 }
303
304
305 /**
306 Execute Mode Sense(10) SCSI command on a specific SCSI target.
307
308 Executes the SCSI Mode Sense(10) command on the SCSI target specified by ScsiIo.
309 If Timeout is zero, then this function waits indefinitely for the command to complete.
310 If Timeout is greater than zero, then the command is executed and will timeout
311 after Timeout 100 ns units. The DBDField, PageControl, and PageCode parameters
312 are used to construct the CDB for this SCSI command.
313 If ScsiIo is NULL, then ASSERT().
314 If SenseDataLength is NULL, then ASSERT().
315 If HostAdapterStatus is NULL, then ASSERT().
316 If TargetStatus is NULL, then ASSERT().
317 If DataLength is NULL, then ASSERT().
318
319
320 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
321 for the specific SCSI target.
322 @param[in] Timeout The timeout in 100 ns units to use for the
323 execution of this SCSI Request Packet. A Timeout
324 value of zero means that this function will wait
325 indefinitely for the SCSI Request Packet to execute.
326 If Timeout is greater than zero, then this function
327 will return EFI_TIMEOUT if the time required to
328 execute the SCSI Request Packet is greater than Timeout.
329 @param[in, out] SenseData A pointer to sense data that was generated
330 by the execution of the SCSI Request Packet.
331 This buffer must be allocated by the caller.
332 If SenseDataLength is 0, then this parameter
333 is optional and may be NULL.
334 @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
335 On output, the number of bytes written to the SenseData buffer.
336 @param[out] HostAdapterStatus The status of the SCSI Host Controller that
337 produces the SCSI bus containing the SCSI target
338 specified by ScsiIo when the SCSI Request Packet
339 was executed. See the EFI SCSI I/O Protocol in the
340 UEFI Specification for details on the possible
341 return values.
342 @param[out] TargetStatus The status returned by the SCSI target specified
343 by ScsiIo when the SCSI Request Packet was executed
344 on the SCSI Host Controller. See the EFI SCSI
345 I/O Protocol in the UEFI Specification for details
346 on the possible return values.
347 @param[in, out] DataBuffer A pointer to data that was generated by the
348 execution of the SCSI Request Packet. This
349 buffer must be allocated by the caller. If
350 DataLength is 0, then this parameter is optional
351 and may be NULL.
352 @param[in, out] DataLength On input, a pointer to the length in bytes of
353 the DataBuffer buffer. On output, a pointer
354 to the number of bytes written to the DataBuffer
355 buffer.
356 @param[in] DBDField Specifies the DBD field of the CDB for this SCSI Command.
357 @param[in] PageControl Specifies the PC field of the CDB for this SCSI Command.
358 @param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command.
359
360 @retval EFI_SUCCESS The command was executed successfully.
361 See HostAdapterStatus, TargetStatus, SenseDataLength,
362 and SenseData in that order for additional status information.
363 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the
364 entire DataBuffer could not be transferred.
365 The actual number of bytes transferred is returned
366 in DataLength.
367 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
368 there are too many SCSI Command Packets already queued.
369 The SCSI Request Packet was not sent, so no additional
370 status information is available. The caller may retry
371 again later.
372 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
373 SCSI Request Packet. See HostAdapterStatus, TargetStatus,
374 SenseDataLength, and SenseData in that order for
375 additional status information.
376 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
377 is not supported by the SCSI initiator(i.e., SCSI
378 Host Controller). The SCSI Request Packet was not
379 sent, so no additional status information is available.
380 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
381 Request Packet to execute. See HostAdapterStatus,
382 TargetStatus, SenseDataLength, and SenseData in that
383 order for additional status information.
384
385 **/
386 EFI_STATUS
387 EFIAPI
388 ScsiModeSense10Command (
389 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
390 IN UINT64 Timeout,
391 IN OUT VOID *SenseData, OPTIONAL
392 IN OUT UINT8 *SenseDataLength,
393 OUT UINT8 *HostAdapterStatus,
394 OUT UINT8 *TargetStatus,
395 IN OUT VOID *DataBuffer, OPTIONAL
396 IN OUT UINT32 *DataLength,
397 IN UINT8 DBDField, OPTIONAL
398 IN UINT8 PageControl,
399 IN UINT8 PageCode
400 )
401 {
402 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
403 UINT64 Lun;
404 UINT8 *Target;
405 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
406 EFI_STATUS Status;
407 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
408
409 ASSERT (SenseDataLength != NULL);
410 ASSERT (HostAdapterStatus != NULL);
411 ASSERT (TargetStatus != NULL);
412 ASSERT (DataLength != NULL);
413 ASSERT (ScsiIo != NULL);
414
415 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
416 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
417
418 CommandPacket.Timeout = Timeout;
419 CommandPacket.InDataBuffer = DataBuffer;
420 CommandPacket.SenseData = SenseData;
421 CommandPacket.InTransferLength= *DataLength;
422 CommandPacket.Cdb = Cdb;
423 //
424 // Fill Cdb for Mode Sense (10) Command
425 //
426 Target = &TargetArray[0];
427 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
428
429 Cdb[0] = EFI_SCSI_OP_MODE_SEN10;
430 //
431 // DBDField is in Cdb[1] bit3 of (bit7..0)
432 //
433 Cdb[1] = (UINT8) ((LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK) + ((DBDField << 3) & 0x08));
434 //
435 // PageControl is in Cdb[2] bit7..6, PageCode is in Cdb[2] bit5..0
436 //
437 Cdb[2] = (UINT8) (((PageControl << 6) & 0xc0) | (PageCode & 0x3f));
438 Cdb[7] = (UINT8) (*DataLength >> 8);
439 Cdb[8] = (UINT8) (*DataLength);
440
441 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
442 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
443 CommandPacket.SenseDataLength = *SenseDataLength;
444
445 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
446
447 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
448 *TargetStatus = CommandPacket.TargetStatus;
449 *SenseDataLength = CommandPacket.SenseDataLength;
450 *DataLength = CommandPacket.InTransferLength;
451
452 return Status;
453 }
454
455
456 /**
457 Execute Request Sense SCSI command on a specific SCSI target.
458
459 Executes the Request Sense command on the SCSI target specified by ScsiIo.
460 If Timeout is zero, then this function waits indefinitely for the command to complete.
461 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
462 If ScsiIo is NULL, then ASSERT().
463 If SenseDataLength is NULL, then ASSERT().
464 If HostAdapterStatus is NULL, then ASSERT().
465 If TargetStatus is NULL, then ASSERT().
466
467 @param[in] ScsiIo A pointer to SCSI IO protocol.
468 @param[in] Timeout The length of timeout period.
469 @param[in, out] SenseData A pointer to output sense data.
470 @param[in, out] SenseDataLength The length of output sense data.
471 @param[out] HostAdapterStatus The status of Host Adapter.
472 @param[out] TargetStatus The status of the target.
473
474 @retval EFI_SUCCESS Command is executed successfully.
475 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are
476 too many SCSI Command Packets already queued.
477 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
478 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
479 the SCSI initiator(i.e., SCSI Host Controller)
480 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
481
482 **/
483 EFI_STATUS
484 EFIAPI
485 ScsiRequestSenseCommand (
486 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
487 IN UINT64 Timeout,
488 IN OUT VOID *SenseData, OPTIONAL
489 IN OUT UINT8 *SenseDataLength,
490 OUT UINT8 *HostAdapterStatus,
491 OUT UINT8 *TargetStatus
492 )
493 {
494 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
495 UINT64 Lun;
496 UINT8 *Target;
497 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
498 EFI_STATUS Status;
499 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
500
501 ASSERT (SenseDataLength != NULL);
502 ASSERT (HostAdapterStatus != NULL);
503 ASSERT (TargetStatus != NULL);
504 ASSERT (ScsiIo != NULL);
505
506 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
507 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
508
509 CommandPacket.Timeout = Timeout;
510 CommandPacket.InDataBuffer = SenseData;
511 CommandPacket.SenseData = NULL;
512 CommandPacket.InTransferLength= *SenseDataLength;
513 CommandPacket.Cdb = Cdb;
514 //
515 // Fill Cdb for Request Sense Command
516 //
517 Target = &TargetArray[0];
518 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
519
520 Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE;
521 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
522 Cdb[4] = (UINT8) (*SenseDataLength);
523
524 CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
525 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
526 CommandPacket.SenseDataLength = 0;
527
528 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
529
530 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
531 *TargetStatus = CommandPacket.TargetStatus;
532 *SenseDataLength = (UINT8) CommandPacket.InTransferLength;
533
534 return Status;
535 }
536
537
538 /**
539 Execute Read Capacity SCSI command on a specific SCSI target.
540
541 Executes the SCSI Read Capacity command on the SCSI target specified by ScsiIo.
542 If Timeout is zero, then this function waits indefinitely for the command to complete.
543 If Timeout is greater than zero, then the command is executed and will timeout after
544 Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
545 If ScsiIo is NULL, then ASSERT().
546 If SenseDataLength is NULL, then ASSERT().
547 If HostAdapterStatus is NULL, then ASSERT().
548 If TargetStatus is NULL, then ASSERT().
549 If DataLength is NULL, then ASSERT().
550
551 @param[in] ScsiIo A pointer to SCSI IO protocol.
552 @param[in] Timeout The length of timeout period.
553 @param[in, out] SenseData A pointer to output sense data.
554 @param[in, out] SenseDataLength The length of output sense data.
555 @param[out] HostAdapterStatus The status of Host Adapter.
556 @param[out] TargetStatus The status of the target.
557 @param[in, out] DataBuffer A pointer to a data buffer.
558 @param[in, out] DataLength The length of data buffer.
559 @param[in] Pmi Partial medium indicator.
560
561 @retval EFI_SUCCESS Command is executed successfully.
562 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
563 DataBuffer could not be transferred. The actual
564 number of bytes transferred is returned in DataLength.
565 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
566 there are too many SCSI Command Packets already queued.
567 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
568 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
569 is not supported by the SCSI initiator(i.e., SCSI Host Controller)
570 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
571
572 **/
573 EFI_STATUS
574 EFIAPI
575 ScsiReadCapacityCommand (
576 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
577 IN UINT64 Timeout,
578 IN OUT VOID *SenseData, OPTIONAL
579 IN OUT UINT8 *SenseDataLength,
580 OUT UINT8 *HostAdapterStatus,
581 OUT UINT8 *TargetStatus,
582 IN OUT VOID *DataBuffer, OPTIONAL
583 IN OUT UINT32 *DataLength,
584 IN BOOLEAN Pmi
585 )
586 {
587 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
588 UINT64 Lun;
589 UINT8 *Target;
590 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
591 EFI_STATUS Status;
592 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
593
594 ASSERT (SenseDataLength != NULL);
595 ASSERT (HostAdapterStatus != NULL);
596 ASSERT (TargetStatus != NULL);
597 ASSERT (DataLength != NULL);
598 ASSERT (ScsiIo != NULL);
599
600 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
601 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
602
603 CommandPacket.Timeout = Timeout;
604 CommandPacket.InDataBuffer = DataBuffer;
605 CommandPacket.SenseData = SenseData;
606 CommandPacket.InTransferLength= *DataLength;
607 CommandPacket.Cdb = Cdb;
608 //
609 // Fill Cdb for Read Capacity Command
610 //
611 Target = &TargetArray[0];
612 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
613
614 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
615 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
616 if (!Pmi) {
617 //
618 // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO.
619 //
620 ZeroMem ((Cdb + 2), 4);
621 } else {
622 Cdb[8] |= 0x01;
623 }
624
625 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
626 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
627 CommandPacket.SenseDataLength = *SenseDataLength;
628
629 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
630
631 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
632 *TargetStatus = CommandPacket.TargetStatus;
633 *SenseDataLength = CommandPacket.SenseDataLength;
634 *DataLength = CommandPacket.InTransferLength;
635
636 return Status;
637 }
638
639
640 /**
641 Execute Read Capacity SCSI 16 command on a specific SCSI target.
642
643 Executes the SCSI Read Capacity 16 command on the SCSI target specified by ScsiIo.
644 If Timeout is zero, then this function waits indefinitely for the command to complete.
645 If Timeout is greater than zero, then the command is executed and will timeout after
646 Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
647 If ScsiIo is NULL, then ASSERT().
648 If SenseDataLength is NULL, then ASSERT().
649 If HostAdapterStatus is NULL, then ASSERT().
650 If TargetStatus is NULL, then ASSERT().
651 If DataLength is NULL, then ASSERT().
652
653 @param[in] ScsiIo A pointer to SCSI IO protocol.
654 @param[in] Timeout The length of timeout period.
655 @param[in, out] SenseData A pointer to output sense data.
656 @param[in, out] SenseDataLength The length of output sense data.
657 @param[out] HostAdapterStatus The status of Host Adapter.
658 @param[out] TargetStatus The status of the target.
659 @param[in, out] DataBuffer A pointer to a data buffer.
660 @param[in, out] DataLength The length of data buffer.
661 @param[in] Pmi Partial medium indicator.
662
663 @retval EFI_SUCCESS Command is executed successfully.
664 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
665 DataBuffer could not be transferred. The actual
666 number of bytes transferred is returned in DataLength.
667 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
668 there are too many SCSI Command Packets already queued.
669 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
670 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
671 is not supported by the SCSI initiator(i.e., SCSI Host Controller)
672 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
673
674 **/
675 EFI_STATUS
676 EFIAPI
677 ScsiReadCapacity16Command (
678 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
679 IN UINT64 Timeout,
680 IN OUT VOID *SenseData, OPTIONAL
681 IN OUT UINT8 *SenseDataLength,
682 OUT UINT8 *HostAdapterStatus,
683 OUT UINT8 *TargetStatus,
684 IN OUT VOID *DataBuffer, OPTIONAL
685 IN OUT UINT32 *DataLength,
686 IN BOOLEAN Pmi
687 )
688 {
689 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
690 UINT64 Lun;
691 UINT8 *Target;
692 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
693 EFI_STATUS Status;
694 UINT8 Cdb[16];
695
696 ASSERT (SenseDataLength != NULL);
697 ASSERT (HostAdapterStatus != NULL);
698 ASSERT (TargetStatus != NULL);
699 ASSERT (DataLength != NULL);
700 ASSERT (ScsiIo != NULL);
701
702 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
703 ZeroMem (Cdb, 16);
704
705 CommandPacket.Timeout = Timeout;
706 CommandPacket.InDataBuffer = DataBuffer;
707 CommandPacket.SenseData = SenseData;
708 CommandPacket.InTransferLength= *DataLength;
709 CommandPacket.Cdb = Cdb;
710 //
711 // Fill Cdb for Read Capacity Command
712 //
713 Target = &TargetArray[0];
714 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
715
716 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16;
717 Cdb[1] = 0x10;
718 if (!Pmi) {
719 //
720 // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.9 MUST BE ZERO.
721 //
722 ZeroMem ((Cdb + 2), 8);
723 } else {
724 Cdb[14] |= 0x01;
725 }
726
727 Cdb[13] = 0x20;
728 CommandPacket.CdbLength = 16;
729 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
730 CommandPacket.SenseDataLength = *SenseDataLength;
731
732 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
733
734 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
735 *TargetStatus = CommandPacket.TargetStatus;
736 *SenseDataLength = CommandPacket.SenseDataLength;
737 *DataLength = CommandPacket.InTransferLength;
738
739 return Status;
740 }
741
742
743 /**
744 Execute Read(10) SCSI command on a specific SCSI target.
745
746 Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo.
747 If Timeout is zero, then this function waits indefinitely for the command to complete.
748 If Timeout is greater than zero, then the command is executed and will timeout
749 after Timeout 100 ns units. The StartLba and SectorSize parameters are used to
750 construct the CDB for this SCSI command.
751 If ScsiIo is NULL, then ASSERT().
752 If SenseDataLength is NULL, then ASSERT().
753 If HostAdapterStatus is NULL, then ASSERT().
754 If TargetStatus is NULL, then ASSERT().
755 If DataLength is NULL, then ASSERT().
756
757
758 @param[in] ScsiIo A pointer to SCSI IO protocol.
759 @param[in] Timeout The length of timeout period.
760 @param[in, out] SenseData A pointer to output sense data.
761 @param[in, out] SenseDataLength The length of output sense data.
762 @param[out] HostAdapterStatus The status of Host Adapter.
763 @param[out] TargetStatus The status of the target.
764 @param[in, out] DataBuffer Read 10 command data.
765 @param[in, out] DataLength The length of data buffer.
766 @param[in] StartLba The start address of LBA.
767 @param[in] SectorSize The sector size.
768
769 @retval EFI_SUCCESS Command is executed successfully.
770 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
771 not be transferred. The actual number of bytes transferred is returned in DataLength.
772 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
773 SCSI Command Packets already queued.
774 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
775 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
776 the SCSI initiator(i.e., SCSI Host Controller)
777 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
778
779 **/
780 EFI_STATUS
781 EFIAPI
782 ScsiRead10Command (
783 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
784 IN UINT64 Timeout,
785 IN OUT VOID *SenseData, OPTIONAL
786 IN OUT UINT8 *SenseDataLength,
787 OUT UINT8 *HostAdapterStatus,
788 OUT UINT8 *TargetStatus,
789 IN OUT VOID *DataBuffer, OPTIONAL
790 IN OUT UINT32 *DataLength,
791 IN UINT32 StartLba,
792 IN UINT32 SectorSize
793 )
794 {
795 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
796 UINT64 Lun;
797 UINT8 *Target;
798 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
799 EFI_STATUS Status;
800 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
801
802 ASSERT (SenseDataLength != NULL);
803 ASSERT (HostAdapterStatus != NULL);
804 ASSERT (TargetStatus != NULL);
805 ASSERT (DataLength != NULL);
806 ASSERT (ScsiIo != NULL);
807
808 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
809 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
810
811 CommandPacket.Timeout = Timeout;
812 CommandPacket.InDataBuffer = DataBuffer;
813 CommandPacket.SenseData = SenseData;
814 CommandPacket.InTransferLength= *DataLength;
815 CommandPacket.Cdb = Cdb;
816 //
817 // Fill Cdb for Read (10) Command
818 //
819 Target = &TargetArray[0];
820 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
821
822 Cdb[0] = EFI_SCSI_OP_READ10;
823 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
824 WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));
825 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize));
826
827 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
828 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
829 CommandPacket.SenseDataLength = *SenseDataLength;
830
831 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
832
833 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
834 *TargetStatus = CommandPacket.TargetStatus;
835 *SenseDataLength = CommandPacket.SenseDataLength;
836 *DataLength = CommandPacket.InTransferLength;
837
838 return Status;
839 }
840
841
842 /**
843 Execute Write(10) SCSI command on a specific SCSI target.
844
845 Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo.
846 If Timeout is zero, then this function waits indefinitely for the command to complete.
847 If Timeout is greater than zero, then the command is executed and will timeout after
848 Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct
849 the CDB for this SCSI command.
850 If ScsiIo is NULL, then ASSERT().
851 If SenseDataLength is NULL, then ASSERT().
852 If HostAdapterStatus is NULL, then ASSERT().
853 If TargetStatus is NULL, then ASSERT().
854 If DataLength is NULL, then ASSERT().
855
856 @param[in] ScsiIo SCSI IO Protocol to use
857 @param[in] Timeout The length of timeout period.
858 @param[in, out] SenseData A pointer to output sense data.
859 @param[in, out] SenseDataLength The length of output sense data.
860 @param[out] HostAdapterStatus The status of Host Adapter.
861 @param[out] TargetStatus The status of the target.
862 @param[in, out] DataBuffer A pointer to a data buffer.
863 @param[in, out] DataLength The length of data buffer.
864 @param[in] StartLba The start address of LBA.
865 @param[in] SectorSize The sector size.
866
867 @retval EFI_SUCCESS Command is executed successfully.
868 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
869 not be transferred. The actual number of bytes transferred is returned in DataLength.
870 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
871 SCSI Command Packets already queued.
872 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
873 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
874 the SCSI initiator(i.e., SCSI Host Controller)
875 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
876
877 **/
878 EFI_STATUS
879 EFIAPI
880 ScsiWrite10Command (
881 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
882 IN UINT64 Timeout,
883 IN OUT VOID *SenseData, OPTIONAL
884 IN OUT UINT8 *SenseDataLength,
885 OUT UINT8 *HostAdapterStatus,
886 OUT UINT8 *TargetStatus,
887 IN OUT VOID *DataBuffer, OPTIONAL
888 IN OUT UINT32 *DataLength,
889 IN UINT32 StartLba,
890 IN UINT32 SectorSize
891 )
892 {
893 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
894 UINT64 Lun;
895 UINT8 *Target;
896 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
897 EFI_STATUS Status;
898 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
899
900 ASSERT (SenseDataLength != NULL);
901 ASSERT (HostAdapterStatus != NULL);
902 ASSERT (TargetStatus != NULL);
903 ASSERT (DataLength != NULL);
904 ASSERT (ScsiIo != NULL);
905
906 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
907 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
908
909 CommandPacket.Timeout = Timeout;
910 CommandPacket.OutDataBuffer = DataBuffer;
911 CommandPacket.SenseData = SenseData;
912 CommandPacket.OutTransferLength= *DataLength;
913 CommandPacket.Cdb = Cdb;
914 //
915 // Fill Cdb for Write (10) Command
916 //
917 Target = &TargetArray[0];
918 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
919
920 Cdb[0] = EFI_SCSI_OP_WRITE10;
921 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
922 WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));
923 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize));
924
925 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
926 CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
927 CommandPacket.SenseDataLength = *SenseDataLength;
928
929 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
930
931 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
932 *TargetStatus = CommandPacket.TargetStatus;
933 *SenseDataLength = CommandPacket.SenseDataLength;
934 *DataLength = CommandPacket.OutTransferLength;
935
936 return Status;
937 }
938
939 /**
940 Execute Read(16) SCSI command on a specific SCSI target.
941
942 Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo.
943 If Timeout is zero, then this function waits indefinitely for the command to complete.
944 If Timeout is greater than zero, then the command is executed and will timeout
945 after Timeout 100 ns units. The StartLba and SectorSize parameters are used to
946 construct the CDB for this SCSI command.
947 If ScsiIo is NULL, then ASSERT().
948 If SenseDataLength is NULL, then ASSERT().
949 If HostAdapterStatus is NULL, then ASSERT().
950 If TargetStatus is NULL, then ASSERT().
951 If DataLength is NULL, then ASSERT().
952
953
954 @param[in] ScsiIo A pointer to SCSI IO protocol.
955 @param[in] Timeout The length of timeout period.
956 @param[in, out] SenseData A pointer to output sense data.
957 @param[in, out] SenseDataLength The length of output sense data.
958 @param[out] HostAdapterStatus The status of Host Adapter.
959 @param[out] TargetStatus The status of the target.
960 @param[in, out] DataBuffer Read 16 command data.
961 @param[in, out] DataLength The length of data buffer.
962 @param[in] StartLba The start address of LBA.
963 @param[in] SectorSize The sector size.
964
965 @retval EFI_SUCCESS Command is executed successfully.
966 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
967 not be transferred. The actual number of bytes transferred is returned in DataLength.
968 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
969 SCSI Command Packets already queued.
970 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
971 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
972 the SCSI initiator(i.e., SCSI Host Controller)
973 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
974
975 **/
976 EFI_STATUS
977 EFIAPI
978 ScsiRead16Command (
979 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
980 IN UINT64 Timeout,
981 IN OUT VOID *SenseData, OPTIONAL
982 IN OUT UINT8 *SenseDataLength,
983 OUT UINT8 *HostAdapterStatus,
984 OUT UINT8 *TargetStatus,
985 IN OUT VOID *DataBuffer, OPTIONAL
986 IN OUT UINT32 *DataLength,
987 IN UINT64 StartLba,
988 IN UINT32 SectorSize
989 )
990 {
991 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
992 UINT64 Lun;
993 UINT8 *Target;
994 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
995 EFI_STATUS Status;
996 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN];
997
998 ASSERT (SenseDataLength != NULL);
999 ASSERT (HostAdapterStatus != NULL);
1000 ASSERT (TargetStatus != NULL);
1001 ASSERT (DataLength != NULL);
1002 ASSERT (ScsiIo != NULL);
1003
1004 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
1005 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN);
1006
1007 CommandPacket.Timeout = Timeout;
1008 CommandPacket.InDataBuffer = DataBuffer;
1009 CommandPacket.SenseData = SenseData;
1010 CommandPacket.InTransferLength = *DataLength;
1011 CommandPacket.Cdb = Cdb;
1012 //
1013 // Fill Cdb for Read (16) Command
1014 //
1015 Target = &TargetArray[0];
1016 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
1017
1018 Cdb[0] = EFI_SCSI_OP_READ16;
1019 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
1020 WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
1021 WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));
1022
1023 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;
1024 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
1025 CommandPacket.SenseDataLength = *SenseDataLength;
1026
1027 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
1028
1029 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
1030 *TargetStatus = CommandPacket.TargetStatus;
1031 *SenseDataLength = CommandPacket.SenseDataLength;
1032 *DataLength = CommandPacket.InTransferLength;
1033
1034 return Status;
1035 }
1036
1037
1038 /**
1039 Execute Write(16) SCSI command on a specific SCSI target.
1040
1041 Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo.
1042 If Timeout is zero, then this function waits indefinitely for the command to complete.
1043 If Timeout is greater than zero, then the command is executed and will timeout after
1044 Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct
1045 the CDB for this SCSI command.
1046 If ScsiIo is NULL, then ASSERT().
1047 If SenseDataLength is NULL, then ASSERT().
1048 If HostAdapterStatus is NULL, then ASSERT().
1049 If TargetStatus is NULL, then ASSERT().
1050 If DataLength is NULL, then ASSERT().
1051
1052 @param[in] ScsiIo SCSI IO Protocol to use
1053 @param[in] Timeout The length of timeout period.
1054 @param[in, out] SenseData A pointer to output sense data.
1055 @param[in, out] SenseDataLength The length of output sense data.
1056 @param[out] HostAdapterStatus The status of Host Adapter.
1057 @param[out] TargetStatus The status of the target.
1058 @param[in, out] DataBuffer A pointer to a data buffer.
1059 @param[in, out] DataLength The length of data buffer.
1060 @param[in] StartLba The start address of LBA.
1061 @param[in] SectorSize The sector size.
1062
1063 @retval EFI_SUCCESS Command is executed successfully.
1064 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
1065 not be transferred. The actual number of bytes transferred is returned in DataLength.
1066 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
1067 SCSI Command Packets already queued.
1068 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
1069 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
1070 the SCSI initiator(i.e., SCSI Host Controller)
1071 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1072
1073 **/
1074 EFI_STATUS
1075 EFIAPI
1076 ScsiWrite16Command (
1077 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1078 IN UINT64 Timeout,
1079 IN OUT VOID *SenseData, OPTIONAL
1080 IN OUT UINT8 *SenseDataLength,
1081 OUT UINT8 *HostAdapterStatus,
1082 OUT UINT8 *TargetStatus,
1083 IN OUT VOID *DataBuffer, OPTIONAL
1084 IN OUT UINT32 *DataLength,
1085 IN UINT64 StartLba,
1086 IN UINT32 SectorSize
1087 )
1088 {
1089 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
1090 UINT64 Lun;
1091 UINT8 *Target;
1092 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
1093 EFI_STATUS Status;
1094 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN];
1095
1096 ASSERT (SenseDataLength != NULL);
1097 ASSERT (HostAdapterStatus != NULL);
1098 ASSERT (TargetStatus != NULL);
1099 ASSERT (DataLength != NULL);
1100 ASSERT (ScsiIo != NULL);
1101
1102 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
1103 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN);
1104
1105 CommandPacket.Timeout = Timeout;
1106 CommandPacket.OutDataBuffer = DataBuffer;
1107 CommandPacket.SenseData = SenseData;
1108 CommandPacket.OutTransferLength = *DataLength;
1109 CommandPacket.Cdb = Cdb;
1110 //
1111 // Fill Cdb for Write (16) Command
1112 //
1113 Target = &TargetArray[0];
1114 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
1115
1116 Cdb[0] = EFI_SCSI_OP_WRITE16;
1117 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
1118 WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
1119 WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));
1120
1121 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;
1122 CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
1123 CommandPacket.SenseDataLength = *SenseDataLength;
1124
1125 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
1126
1127 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
1128 *TargetStatus = CommandPacket.TargetStatus;
1129 *SenseDataLength = CommandPacket.SenseDataLength;
1130 *DataLength = CommandPacket.OutTransferLength;
1131
1132 return Status;
1133 }