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