]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiScsiLib/UefiScsiLib.c
8fcc3d157dce8684d716443184632d8318109b6f
[mirror_edk2.git] / MdePkg / Library / UefiScsiLib / UefiScsiLib.c
1 /** @file
2 UEFI SCSI Library implementation
3
4 Copyright (c) 2006 - 2008, Intel Corporation.<BR>
5 All rights reserved. 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 six or ten
38 //
39 #define EFI_SCSI_OP_LENGTH_SIX 0x6
40 #define EFI_SCSI_OP_LENGTH_TEN 0xa
41
42
43
44 /**
45 Execute Test Unit Ready SCSI command on a specific SCSI target.
46
47 Executes the Test Unit Ready command on the SCSI target specified by ScsiIo.
48 If Timeout is zero, then this function waits indefinitely for the command to complete.
49 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
50 If ScsiIo is NULL, then ASSERT().
51 If SenseDataLength is NULL, then ASSERT().
52 If HostAdapterStatus is NULL, then ASSERT().
53 If TargetStatus is NULL, then ASSERT().
54
55
56 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
57 for the specific SCSI target.
58 @param[in] Timeout The timeout in 100 ns units to use for the execution
59 of this SCSI Request Packet. A Timeout value of
60 zero means that this function will wait indefinitely
61 for the SCSI Request Packet to execute. If Timeout
62 is greater than zero, then this function will return
63 EFI_TIMEOUT if the time required to execute the SCSI
64 Request Packet is greater than Timeout.
65 @param[in, out] SenseData A pointer to sense data that was generated by
66 the execution of the SCSI Request Packet. This
67 buffer must be allocated by the caller.
68 If SenseDataLength is 0, then this parameter is
69 optional and may be NULL.
70 @param[in, out] SenseDataLength On input, a pointer to the length in bytes of
71 the SenseData buffer. On output, a pointer to
72 the number of bytes written to the SenseData buffer.
73 @param[out] HostAdapterStatus The status of the SCSI Host Controller that produces
74 the SCSI bus containing the SCSI target specified by
75 ScsiIo when the SCSI Request Packet was executed.
76 See the EFI SCSI I/O Protocol in the UEFI Specification
77 for details on the possible return values.
78 @param[out] TargetStatus The status returned by the SCSI target specified
79 by ScsiIo when the SCSI Request Packet was executed
80 on the SCSI Host Controller. See the EFI SCSI I/O
81 Protocol in the UEFI Specification for details on
82 the possible return values.
83
84 @retval EFI_SUCCESS The command was executed successfully.
85 See HostAdapterStatus, TargetStatus, SenseDataLength,
86 and SenseData in that order for additional status
87 information.
88 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
89 there are too many SCSI Command Packets already
90 queued. The SCSI Request Packet was not sent, so
91 no additional status information is available.
92 The caller may retry again later.
93 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
94 SCSI Request Packet. See HostAdapterStatus,
95 TargetStatus, SenseDataLength, and SenseData in that
96 order for additional status information.
97 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
98 is not supported by the SCSI initiator(i.e., SCSI
99 Host Controller). The SCSI Request Packet was not
100 sent, so no additional status information is available.
101 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
102 Packet to execute. See HostAdapterStatus, TargetStatus,
103 SenseDataLength, and SenseData in that order for
104 additional status information.
105
106 **/
107 EFI_STATUS
108 EFIAPI
109 ScsiTestUnitReadyCommand (
110 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
111 IN UINT64 Timeout,
112 IN OUT VOID *SenseData, OPTIONAL
113 IN OUT UINT8 *SenseDataLength,
114 OUT UINT8 *HostAdapterStatus,
115 OUT UINT8 *TargetStatus
116 )
117 {
118 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
119 UINT64 Lun;
120 UINT8 *Target;
121 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
122 EFI_STATUS Status;
123 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
124
125 ASSERT (SenseDataLength != NULL);
126 ASSERT (HostAdapterStatus != NULL);
127 ASSERT (TargetStatus != NULL);
128 ASSERT (ScsiIo != NULL);
129
130 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
131 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
132
133 CommandPacket.Timeout = Timeout;
134 CommandPacket.InDataBuffer = NULL;
135 CommandPacket.InTransferLength= 0;
136 CommandPacket.OutDataBuffer = NULL;
137 CommandPacket.OutTransferLength= 0;
138 CommandPacket.SenseData = SenseData;
139 CommandPacket.Cdb = Cdb;
140 //
141 // Fill Cdb for Test Unit Ready Command
142 //
143 Target = &TargetArray[0];
144 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
145
146 Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY;
147 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
148 CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
149 CommandPacket.SenseDataLength = *SenseDataLength;
150
151 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
152
153 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
154 *TargetStatus = CommandPacket.TargetStatus;
155 *SenseDataLength = CommandPacket.SenseDataLength;
156
157 return Status;
158 }
159
160
161 /**
162 Execute Inquiry SCSI command on a specific SCSI target.
163
164 Executes the Inquiry command on the SCSI target specified by ScsiIo.
165 If Timeout is zero, then this function waits indefinitely for the command to complete.
166 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
167 If ScsiIo is NULL, then ASSERT().
168 If SenseDataLength is NULL, then ASSERT().
169 If HostAdapterStatus is NULL, then ASSERT().
170 If TargetStatus is NULL, then ASSERT().
171 If InquiryDataLength is NULL, then ASSERT().
172
173 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
174 for the specific SCSI target.
175 @param[in] Timeout The timeout in 100 ns units to use for the
176 execution of this SCSI Request Packet. A Timeout
177 value of zero means that this function will wait
178 indefinitely for the SCSI Request Packet to execute.
179 If Timeout is greater than zero, then this function
180 will return EFI_TIMEOUT if the time required to
181 execute the SCSI Request Packet is greater than Timeout.
182 @param[in, out] SenseData A pointer to sense data that was generated
183 by the execution of the SCSI Request Packet.
184 This buffer must be allocated by the caller.
185 If SenseDataLength is 0, then this parameter
186 is optional and may be NULL.
187 @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
188 On output, the number of bytes written to the SenseData buffer.
189 @param[out] HostAdapterStatus The status of the SCSI Host Controller that
190 produces the SCSI bus containing the SCSI
191 target specified by ScsiIo when the SCSI
192 Request Packet was executed. See the EFI
193 SCSI I/O Protocol in the UEFI Specification
194 for details on the possible return values.
195 @param[out] TargetStatus The status returned by the SCSI target specified
196 by ScsiIo when the SCSI Request Packet was
197 executed on the SCSI Host Controller.
198 See the EFI SCSI I/O Protocol in the UEFI
199 Specification for details on the possible
200 return values.
201 @param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated
202 by the execution of the SCSI Request Packet.
203 This buffer must be allocated by the caller.
204 If InquiryDataLength is 0, then this parameter
205 is optional and may be NULL.
206 @param[in, out] InquiryDataLength On input, a pointer to the length in bytes
207 of the InquiryDataBuffer buffer.
208 On output, a pointer to the number of bytes
209 written to the InquiryDataBuffer buffer.
210 @param[in] EnableVitalProductData If TRUE, then the supported vital product
211 data is returned in InquiryDataBuffer.
212 If FALSE, then the standard inquiry data is
213 returned in InquiryDataBuffer.
214
215 @retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus,
216 TargetStatus, SenseDataLength, and SenseData in that order
217 for additional status information.
218 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
219 InquiryDataBuffer could not be transferred. The actual
220 number of bytes transferred is returned in InquiryDataLength.
221 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there
222 are too many SCSI Command Packets already queued.
223 The SCSI Request Packet was not sent, so no additional
224 status information is available. The caller may retry again later.
225 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI
226 Request Packet. See HostAdapterStatus, TargetStatus,
227 SenseDataLength, and SenseData in that order for additional
228 status information.
229 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not
230 supported by the SCSI initiator(i.e., SCSI Host Controller).
231 The SCSI Request Packet was not sent, so no additional
232 status information is available.
233 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
234 Packet to execute. See HostAdapterStatus, TargetStatus,
235 SenseDataLength, and SenseData in that order for
236 additional status information.
237
238 **/
239 EFI_STATUS
240 EFIAPI
241 ScsiInquiryCommand (
242 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
243 IN UINT64 Timeout,
244 IN OUT VOID *SenseData, OPTIONAL
245 IN OUT UINT8 *SenseDataLength,
246 OUT UINT8 *HostAdapterStatus,
247 OUT UINT8 *TargetStatus,
248 IN OUT VOID *InquiryDataBuffer, OPTIONAL
249 IN OUT UINT32 *InquiryDataLength,
250 IN BOOLEAN EnableVitalProductData
251 )
252 {
253 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
254 UINT64 Lun;
255 UINT8 *Target;
256 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
257 EFI_STATUS Status;
258 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
259
260 ASSERT (SenseDataLength != NULL);
261 ASSERT (HostAdapterStatus != NULL);
262 ASSERT (TargetStatus != NULL);
263 ASSERT (InquiryDataLength != NULL);
264 ASSERT (ScsiIo != NULL);
265
266 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
267 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
268
269 CommandPacket.Timeout = Timeout;
270 CommandPacket.InDataBuffer = InquiryDataBuffer;
271 CommandPacket.InTransferLength= *InquiryDataLength;
272 CommandPacket.SenseData = SenseData;
273 CommandPacket.SenseDataLength = *SenseDataLength;
274 CommandPacket.Cdb = Cdb;
275
276 Target = &TargetArray[0];
277 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
278
279 Cdb[0] = EFI_SCSI_OP_INQUIRY;
280 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
281 if (EnableVitalProductData) {
282 Cdb[1] |= 0x01;
283 }
284
285 if (*InquiryDataLength > 0xff) {
286 *InquiryDataLength = 0xff;
287 }
288
289 Cdb[4] = (UINT8) (*InquiryDataLength);
290 CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
291 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
292
293 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
294
295 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
296 *TargetStatus = CommandPacket.TargetStatus;
297 *SenseDataLength = CommandPacket.SenseDataLength;
298 *InquiryDataLength = CommandPacket.InTransferLength;
299
300 return Status;
301 }
302
303
304 /**
305 Execute Mode Sense(10) SCSI command on a specific SCSI target.
306
307 Executes the SCSI Mode Sense(10) command on the SCSI target specified by ScsiIo.
308 If Timeout is zero, then this function waits indefinitely for the command to complete.
309 If Timeout is greater than zero, then the command is executed and will timeout
310 after Timeout 100 ns units. The DBDField, PageControl, and PageCode parameters
311 are used to construct the CDB for this SCSI command.
312 If ScsiIo is NULL, then ASSERT().
313 If SenseDataLength is NULL, then ASSERT().
314 If HostAdapterStatus is NULL, then ASSERT().
315 If TargetStatus is NULL, then ASSERT().
316 If DataLength is NULL, then ASSERT().
317
318
319 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
320 for the specific SCSI target.
321 @param[in] Timeout The timeout in 100 ns units to use for the
322 execution of this SCSI Request Packet. A Timeout
323 value of zero means that this function will wait
324 indefinitely for the SCSI Request Packet to execute.
325 If Timeout is greater than zero, then this function
326 will return EFI_TIMEOUT if the time required to
327 execute the SCSI Request Packet is greater than Timeout.
328 @param[in, out] SenseData A pointer to sense data that was generated
329 by the execution of the SCSI Request Packet.
330 This buffer must be allocated by the caller.
331 If SenseDataLength is 0, then this parameter
332 is optional and may be NULL.
333 @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
334 On output, the number of bytes written to the SenseData buffer.
335 @param[out] HostAdapterStatus The status of the SCSI Host Controller that
336 produces the SCSI bus containing the SCSI target
337 specified by ScsiIo when the SCSI Request Packet
338 was executed. See the EFI SCSI I/O Protocol in the
339 UEFI Specification for details on the possible
340 return values.
341 @param[out] TargetStatus The status returned by the SCSI target specified
342 by ScsiIo when the SCSI Request Packet was executed
343 on the SCSI Host Controller. See the EFI SCSI
344 I/O Protocol in the UEFI Specification for details
345 on the possible return values.
346 @param[in, out] DataBuffer A pointer to data that was generated by the
347 execution of the SCSI Request Packet. This
348 buffer must be allocated by the caller. If
349 DataLength is 0, then this parameter is optional
350 and may be NULL.
351 @param[in, out] DataLength On input, a pointer to the length in bytes of
352 the DataBuffer buffer. On output, a pointer
353 to the number of bytes written to the DataBuffer
354 buffer.
355 @param[in] DBDField Specifies the DBD field of the CDB for this SCSI Command.
356 @param[in] PageControl Specifies the PC field of the CDB for this SCSI Command.
357 @param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command.
358
359 @retval EFI_SUCCESS The command was executed successfully.
360 See HostAdapterStatus, TargetStatus, SenseDataLength,
361 and SenseData in that order for additional status information.
362 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the
363 entire DataBuffer could not be transferred.
364 The actual number of bytes transferred is returned
365 in DataLength.
366 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
367 there are too many SCSI Command Packets already queued.
368 The SCSI Request Packet was not sent, so no additional
369 status information is available. The caller may retry
370 again later.
371 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
372 SCSI Request Packet. See HostAdapterStatus, TargetStatus,
373 SenseDataLength, and SenseData in that order for
374 additional status information.
375 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
376 is not supported by the SCSI initiator(i.e., SCSI
377 Host Controller). The SCSI Request Packet was not
378 sent, so no additional status information is available.
379 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
380 Request Packet to execute. See HostAdapterStatus,
381 TargetStatus, SenseDataLength, and SenseData in that
382 order for additional status information.
383
384 **/
385 EFI_STATUS
386 EFIAPI
387 ScsiModeSense10Command (
388 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
389 IN UINT64 Timeout,
390 IN OUT VOID *SenseData, OPTIONAL
391 IN OUT UINT8 *SenseDataLength,
392 OUT UINT8 *HostAdapterStatus,
393 OUT UINT8 *TargetStatus,
394 IN OUT VOID *DataBuffer, OPTIONAL
395 IN OUT UINT32 *DataLength,
396 IN UINT8 DBDField, OPTIONAL
397 IN UINT8 PageControl,
398 IN UINT8 PageCode
399 )
400 {
401 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
402 UINT64 Lun;
403 UINT8 *Target;
404 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
405 EFI_STATUS Status;
406 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
407
408 ASSERT (SenseDataLength != NULL);
409 ASSERT (HostAdapterStatus != NULL);
410 ASSERT (TargetStatus != NULL);
411 ASSERT (DataLength != NULL);
412 ASSERT (ScsiIo != NULL);
413
414 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
415 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
416
417 CommandPacket.Timeout = Timeout;
418 CommandPacket.InDataBuffer = DataBuffer;
419 CommandPacket.SenseData = SenseData;
420 CommandPacket.InTransferLength= *DataLength;
421 CommandPacket.Cdb = Cdb;
422 //
423 // Fill Cdb for Mode Sense (10) Command
424 //
425 Target = &TargetArray[0];
426 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
427
428 Cdb[0] = EFI_SCSI_OP_MODE_SEN10;
429 //
430 // DBDField is in Cdb[1] bit3 of (bit7..0)
431 //
432 Cdb[1] = (UINT8) ((LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK) + ((DBDField << 3) & 0x08));
433 //
434 // PageControl is in Cdb[2] bit7..6, PageCode is in Cdb[2] bit5..0
435 //
436 Cdb[2] = (UINT8) (((PageControl << 6) & 0xc0) | (PageCode & 0x3f));
437 Cdb[7] = (UINT8) (*DataLength >> 8);
438 Cdb[8] = (UINT8) (*DataLength);
439
440 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
441 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
442 CommandPacket.SenseDataLength = *SenseDataLength;
443
444 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
445
446 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
447 *TargetStatus = CommandPacket.TargetStatus;
448 *SenseDataLength = CommandPacket.SenseDataLength;
449 *DataLength = CommandPacket.InTransferLength;
450
451 return Status;
452 }
453
454
455 /**
456 Execute Request Sense SCSI command on a specific SCSI target.
457
458 Executes the Request Sense command on the SCSI target specified by ScsiIo.
459 If Timeout is zero, then this function waits indefinitely for the command to complete.
460 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
461 If ScsiIo is NULL, then ASSERT().
462 If SenseDataLength is NULL, then ASSERT().
463 If HostAdapterStatus is NULL, then ASSERT().
464 If TargetStatus is NULL, then ASSERT().
465
466 @param[in] ScsiIo A pointer to SCSI IO protocol.
467 @param[in] Timeout The length of timeout period.
468 @param[in, out] SenseData A pointer to output sense data.
469 @param[in, out] SenseDataLength The length of output sense data.
470 @param[out] HostAdapterStatus The status of Host Adapter.
471 @param[out] TargetStatus The status of the target.
472
473 @retval EFI_SUCCESS Command is executed successfully.
474 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are
475 too many SCSI Command Packets already queued.
476 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
477 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
478 the SCSI initiator(i.e., SCSI Host Controller)
479 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
480
481 **/
482 EFI_STATUS
483 EFIAPI
484 ScsiRequestSenseCommand (
485 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
486 IN UINT64 Timeout,
487 IN OUT VOID *SenseData, OPTIONAL
488 IN OUT UINT8 *SenseDataLength,
489 OUT UINT8 *HostAdapterStatus,
490 OUT UINT8 *TargetStatus
491 )
492 {
493 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
494 UINT64 Lun;
495 UINT8 *Target;
496 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
497 EFI_STATUS Status;
498 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
499
500 ASSERT (SenseDataLength != NULL);
501 ASSERT (HostAdapterStatus != NULL);
502 ASSERT (TargetStatus != NULL);
503 ASSERT (ScsiIo != NULL);
504
505 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
506 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
507
508 CommandPacket.Timeout = Timeout;
509 CommandPacket.InDataBuffer = SenseData;
510 CommandPacket.SenseData = NULL;
511 CommandPacket.InTransferLength= *SenseDataLength;
512 CommandPacket.Cdb = Cdb;
513 //
514 // Fill Cdb for Request Sense Command
515 //
516 Target = &TargetArray[0];
517 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
518
519 Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE;
520 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
521 Cdb[4] = (UINT8) (*SenseDataLength);
522
523 CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
524 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
525 CommandPacket.SenseDataLength = 0;
526
527 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
528
529 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
530 *TargetStatus = CommandPacket.TargetStatus;
531 *SenseDataLength = (UINT8) CommandPacket.InTransferLength;
532
533 return Status;
534 }
535
536
537 /**
538 Execute Read Capacity SCSI command on a specific SCSI target.
539
540 Executes the SCSI Read Capacity command on the SCSI target specified by ScsiIo.
541 If Timeout is zero, then this function waits indefinitely for the command to complete.
542 If Timeout is greater than zero, then the command is executed and will timeout after
543 Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
544 If ScsiIo is NULL, then ASSERT().
545 If SenseDataLength is NULL, then ASSERT().
546 If HostAdapterStatus is NULL, then ASSERT().
547 If TargetStatus is NULL, then ASSERT().
548 If DataLength is NULL, then ASSERT().
549
550 @param[in] ScsiIo A pointer to SCSI IO protocol.
551 @param[in] Timeout The length of timeout period.
552 @param[in, out] SenseData A pointer to output sense data.
553 @param[in, out] SenseDataLength The length of output sense data.
554 @param[out] HostAdapterStatus The status of Host Adapter.
555 @param[out] TargetStatus The status of the target.
556 @param[in, out] DataBuffer A pointer to a data buffer.
557 @param[in, out] DataLength The length of data buffer.
558 @param[in] Pmi Partial medium indicator.
559
560 @retval EFI_SUCCESS Command is executed successfully.
561 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
562 DataBuffer could not be transferred. The actual
563 number of bytes transferred is returned in DataLength.
564 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
565 there are too many SCSI Command Packets already queued.
566 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
567 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
568 is not supported by the SCSI initiator(i.e., SCSI Host Controller)
569 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
570
571 **/
572 EFI_STATUS
573 EFIAPI
574 ScsiReadCapacityCommand (
575 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
576 IN UINT64 Timeout,
577 IN OUT VOID *SenseData, OPTIONAL
578 IN OUT UINT8 *SenseDataLength,
579 OUT UINT8 *HostAdapterStatus,
580 OUT UINT8 *TargetStatus,
581 IN OUT VOID *DataBuffer, OPTIONAL
582 IN OUT UINT32 *DataLength,
583 IN BOOLEAN Pmi
584 )
585 {
586 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
587 UINT64 Lun;
588 UINT8 *Target;
589 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
590 EFI_STATUS Status;
591 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
592
593 ASSERT (SenseDataLength != NULL);
594 ASSERT (HostAdapterStatus != NULL);
595 ASSERT (TargetStatus != NULL);
596 ASSERT (DataLength != NULL);
597 ASSERT (ScsiIo != NULL);
598
599 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
600 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
601
602 CommandPacket.Timeout = Timeout;
603 CommandPacket.InDataBuffer = DataBuffer;
604 CommandPacket.SenseData = SenseData;
605 CommandPacket.InTransferLength= *DataLength;
606 CommandPacket.Cdb = Cdb;
607 //
608 // Fill Cdb for Read Capacity Command
609 //
610 Target = &TargetArray[0];
611 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
612
613 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
614 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
615 if (!Pmi) {
616 //
617 // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO.
618 //
619 ZeroMem ((Cdb + 2), 4);
620 } else {
621 Cdb[8] |= 0x01;
622 }
623
624 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
625 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
626 CommandPacket.SenseDataLength = *SenseDataLength;
627
628 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
629
630 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
631 *TargetStatus = CommandPacket.TargetStatus;
632 *SenseDataLength = CommandPacket.SenseDataLength;
633 *DataLength = CommandPacket.InTransferLength;
634
635 return Status;
636 }
637
638
639 /**
640 Execute Read Capacity SCSI 16 command on a specific SCSI target.
641
642 Executes the SCSI Read Capacity 16 command on the SCSI target specified by ScsiIo.
643 If Timeout is zero, then this function waits indefinitely for the command to complete.
644 If Timeout is greater than zero, then the command is executed and will timeout after
645 Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
646 If ScsiIo is NULL, then ASSERT().
647 If SenseDataLength is NULL, then ASSERT().
648 If HostAdapterStatus is NULL, then ASSERT().
649 If TargetStatus is NULL, then ASSERT().
650 If DataLength is NULL, then ASSERT().
651
652 @param[in] ScsiIo A pointer to SCSI IO protocol.
653 @param[in] Timeout The length of timeout period.
654 @param[in, out] SenseData A pointer to output sense data.
655 @param[in, out] SenseDataLength The length of output sense data.
656 @param[out] HostAdapterStatus The status of Host Adapter.
657 @param[out] TargetStatus The status of the target.
658 @param[in, out] DataBuffer A pointer to a data buffer.
659 @param[in, out] DataLength The length of data buffer.
660 @param[in] Pmi Partial medium indicator.
661
662 @retval EFI_SUCCESS Command is executed successfully.
663 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
664 DataBuffer could not be transferred. The actual
665 number of bytes transferred is returned in DataLength.
666 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
667 there are too many SCSI Command Packets already queued.
668 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
669 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
670 is not supported by the SCSI initiator(i.e., SCSI Host Controller)
671 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
672
673 **/
674 EFI_STATUS
675 EFIAPI
676 ScsiReadCapacity16Command (
677 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
678 IN UINT64 Timeout,
679 IN OUT VOID *SenseData, OPTIONAL
680 IN OUT UINT8 *SenseDataLength,
681 OUT UINT8 *HostAdapterStatus,
682 OUT UINT8 *TargetStatus,
683 IN OUT VOID *DataBuffer, OPTIONAL
684 IN OUT UINT32 *DataLength,
685 IN BOOLEAN Pmi
686 )
687 {
688 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
689 UINT64 Lun;
690 UINT8 *Target;
691 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
692 EFI_STATUS Status;
693 UINT8 Cdb[16];
694
695 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
696 ZeroMem (Cdb, 16);
697
698 CommandPacket.Timeout = Timeout;
699 CommandPacket.InDataBuffer = DataBuffer;
700 CommandPacket.SenseData = SenseData;
701 CommandPacket.InTransferLength= *DataLength;
702 CommandPacket.Cdb = Cdb;
703 //
704 // Fill Cdb for Read Capacity Command
705 //
706 Target = &TargetArray[0];
707 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
708
709 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16;
710 Cdb[1] = 0x10;
711 if (!Pmi) {
712 //
713 // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.9 MUST BE ZERO.
714 //
715 ZeroMem ((Cdb + 2), 8);
716 } else {
717 Cdb[14] |= 0x01;
718 }
719
720 Cdb[13] = 0x20;
721 CommandPacket.CdbLength = 16;
722 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
723 CommandPacket.SenseDataLength = *SenseDataLength;
724
725 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
726
727 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
728 *TargetStatus = CommandPacket.TargetStatus;
729 *SenseDataLength = CommandPacket.SenseDataLength;
730 *DataLength = CommandPacket.InTransferLength;
731
732 return Status;
733 }
734
735
736 /**
737 Execute Read(10) SCSI command on a specific SCSI target.
738
739 Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo.
740 If Timeout is zero, then this function waits indefinitely for the command to complete.
741 If Timeout is greater than zero, then the command is executed and will timeout
742 after Timeout 100 ns units. The StartLba and SectorSize parameters are used to
743 construct the CDB for this SCSI command.
744 If ScsiIo is NULL, then ASSERT().
745 If SenseDataLength is NULL, then ASSERT().
746 If HostAdapterStatus is NULL, then ASSERT().
747 If TargetStatus is NULL, then ASSERT().
748 If DataLength is NULL, then ASSERT().
749
750
751 @param[in] ScsiIo A pointer to SCSI IO protocol.
752 @param[in] Timeout The length of timeout period.
753 @param[in, out] SenseData A pointer to output sense data.
754 @param[in, out] SenseDataLength The length of output sense data.
755 @param[out] HostAdapterStatus The status of Host Adapter.
756 @param[out] TargetStatus The status of the target.
757 @param[in, out] DataBuffer Read 10 command data.
758 @param[in, out] DataLength The length of data buffer.
759 @param[in] StartLba The start address of LBA.
760 @param[in] SectorSize The sector size.
761
762 @retval EFI_SUCCESS Command is executed successfully.
763 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
764 not be transferred. The actual number of bytes transferred is returned in DataLength.
765 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
766 SCSI Command Packets already queued.
767 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
768 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
769 the SCSI initiator(i.e., SCSI Host Controller)
770 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
771
772 **/
773 EFI_STATUS
774 EFIAPI
775 ScsiRead10Command (
776 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
777 IN UINT64 Timeout,
778 IN OUT VOID *SenseData, OPTIONAL
779 IN OUT UINT8 *SenseDataLength,
780 OUT UINT8 *HostAdapterStatus,
781 OUT UINT8 *TargetStatus,
782 IN OUT VOID *DataBuffer, OPTIONAL
783 IN OUT UINT32 *DataLength,
784 IN UINT32 StartLba,
785 IN UINT32 SectorSize
786 )
787 {
788 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
789 UINT64 Lun;
790 UINT8 *Target;
791 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
792 EFI_STATUS Status;
793 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
794
795 ASSERT (SenseDataLength != NULL);
796 ASSERT (HostAdapterStatus != NULL);
797 ASSERT (TargetStatus != NULL);
798 ASSERT (DataLength != NULL);
799 ASSERT (ScsiIo != NULL);
800
801 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
802 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
803
804 CommandPacket.Timeout = Timeout;
805 CommandPacket.InDataBuffer = DataBuffer;
806 CommandPacket.SenseData = SenseData;
807 CommandPacket.InTransferLength= *DataLength;
808 CommandPacket.Cdb = Cdb;
809 //
810 // Fill Cdb for Read (10) Command
811 //
812 Target = &TargetArray[0];
813 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
814
815 Cdb[0] = EFI_SCSI_OP_READ10;
816 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
817 Cdb[2] = (UINT8) (StartLba >> 24);
818 Cdb[3] = (UINT8) (StartLba >> 16);
819 Cdb[4] = (UINT8) (StartLba >> 8);
820 Cdb[5] = (UINT8) (StartLba & 0xff);
821 Cdb[7] = (UINT8) (SectorSize >> 8);
822 Cdb[8] = (UINT8) (SectorSize & 0xff);
823
824 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
825 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
826 CommandPacket.SenseDataLength = *SenseDataLength;
827
828 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
829
830 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
831 *TargetStatus = CommandPacket.TargetStatus;
832 *SenseDataLength = CommandPacket.SenseDataLength;
833 *DataLength = CommandPacket.InTransferLength;
834
835 return Status;
836 }
837
838
839 /**
840 Execute Write(10) SCSI command on a specific SCSI target.
841
842 Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo.
843 If Timeout is zero, then this function waits indefinitely for the command to complete.
844 If Timeout is greater than zero, then the command is executed and will timeout after
845 Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct
846 the CDB for this SCSI command.
847 If ScsiIo is NULL, then ASSERT().
848 If SenseDataLength is NULL, then ASSERT().
849 If HostAdapterStatus is NULL, then ASSERT().
850 If TargetStatus is NULL, then ASSERT().
851 If DataLength is NULL, then ASSERT().
852
853 @param[in] ScsiIo SCSI IO Protocol to use
854 @param[in] Timeout The length of timeout period.
855 @param[in, out] SenseData A pointer to output sense data.
856 @param[in, out] SenseDataLength The length of output sense data.
857 @param[out] HostAdapterStatus The status of Host Adapter.
858 @param[out] TargetStatus The status of the target.
859 @param[in, out] DataBuffer A pointer to a data buffer.
860 @param[in, out] DataLength The length of data buffer.
861 @param[in] StartLba The start address of LBA.
862 @param[in] SectorSize The sector size.
863
864 @retval EFI_SUCCESS Command is executed successfully.
865 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
866 not be transferred. The actual number of bytes transferred is returned in DataLength.
867 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
868 SCSI Command Packets already queued.
869 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
870 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
871 the SCSI initiator(i.e., SCSI Host Controller)
872 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
873
874 **/
875 EFI_STATUS
876 EFIAPI
877 ScsiWrite10Command (
878 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
879 IN UINT64 Timeout,
880 IN OUT VOID *SenseData, OPTIONAL
881 IN OUT UINT8 *SenseDataLength,
882 OUT UINT8 *HostAdapterStatus,
883 OUT UINT8 *TargetStatus,
884 IN OUT VOID *DataBuffer, OPTIONAL
885 IN OUT UINT32 *DataLength,
886 IN UINT32 StartLba,
887 IN UINT32 SectorSize
888 )
889 {
890 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
891 UINT64 Lun;
892 UINT8 *Target;
893 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
894 EFI_STATUS Status;
895 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
896
897 ASSERT (SenseDataLength != NULL);
898 ASSERT (HostAdapterStatus != NULL);
899 ASSERT (TargetStatus != NULL);
900 ASSERT (DataLength != NULL);
901 ASSERT (ScsiIo != NULL);
902
903 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
904 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
905
906 CommandPacket.Timeout = Timeout;
907 CommandPacket.OutDataBuffer = DataBuffer;
908 CommandPacket.SenseData = SenseData;
909 CommandPacket.OutTransferLength= *DataLength;
910 CommandPacket.Cdb = Cdb;
911 //
912 // Fill Cdb for Write (10) Command
913 //
914 Target = &TargetArray[0];
915 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
916
917 Cdb[0] = EFI_SCSI_OP_WRITE10;
918 Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
919 Cdb[2] = (UINT8) (StartLba >> 24);
920 Cdb[3] = (UINT8) (StartLba >> 16);
921 Cdb[4] = (UINT8) (StartLba >> 8);
922 Cdb[5] = (UINT8) StartLba;
923 Cdb[7] = (UINT8) (SectorSize >> 8);
924 Cdb[8] = (UINT8) SectorSize;
925
926 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
927 CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
928 CommandPacket.SenseDataLength = *SenseDataLength;
929
930 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
931
932 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
933 *TargetStatus = CommandPacket.TargetStatus;
934 *SenseDataLength = CommandPacket.SenseDataLength;
935 *DataLength = CommandPacket.OutTransferLength;
936
937 return Status;
938 }
939