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