]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiScsiLib/UefiScsiLib.c
Add back logic to encode LUN in CDB for compatibility with SCSI-2 spec, although...
[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 << 5) & 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 Packet 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 << 5) & 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 Packet 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 << 5) & 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 << 6) & 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 << 5) & 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 << 5) & 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 Capacity SCSI 16 command on a specific SCSI target.
640
641 Executes the SCSI Read Capacity 16 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 after
644 Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
645 If ScsiIo is NULL, then ASSERT().
646 If SenseDataLength is NULL, then ASSERT().
647 If HostAdapterStatus is NULL, then ASSERT().
648 If TargetStatus is NULL, then ASSERT().
649 If DataLength is NULL, then ASSERT().
650
651 @param[in] ScsiIo A pointer to SCSI IO protocol.
652 @param[in] Timeout The length of timeout period.
653 @param[in, out] SenseData A pointer to output sense data.
654 @param[in, out] SenseDataLength The length of output sense data.
655 @param[out] HostAdapterStatus The status of Host Adapter.
656 @param[out] TargetStatus The status of the target.
657 @param[in, out] DataBuffer A pointer to a data buffer.
658 @param[in, out] DataLength The length of data buffer.
659 @param[in] Pmi Partial medium indicator.
660
661 @retval EFI_SUCCESS Command is executed successfully.
662 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
663 DataBuffer could not be transferred. The actual
664 number of bytes transferred is returned in DataLength.
665 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
666 there are too many SCSI Command Packets already queued.
667 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
668 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
669 is not supported by the SCSI initiator(i.e., SCSI Host Controller)
670 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
671
672 **/
673 EFI_STATUS
674 EFIAPI
675 ScsiReadCapacity16Command (
676 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
677 IN UINT64 Timeout,
678 IN OUT VOID *SenseData, OPTIONAL
679 IN OUT UINT8 *SenseDataLength,
680 OUT UINT8 *HostAdapterStatus,
681 OUT UINT8 *TargetStatus,
682 IN OUT VOID *DataBuffer, OPTIONAL
683 IN OUT UINT32 *DataLength,
684 IN BOOLEAN Pmi
685 )
686 {
687 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
688 UINT64 Lun;
689 UINT8 *Target;
690 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
691 EFI_STATUS Status;
692 UINT8 Cdb[16];
693
694 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
695 ZeroMem (Cdb, 16);
696
697 CommandPacket.Timeout = Timeout;
698 CommandPacket.InDataBuffer = DataBuffer;
699 CommandPacket.SenseData = SenseData;
700 CommandPacket.InTransferLength= *DataLength;
701 CommandPacket.Cdb = Cdb;
702 //
703 // Fill Cdb for Read Capacity Command
704 //
705 Target = &TargetArray[0];
706 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
707
708 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16;
709 Cdb[1] = 0x10;
710 if (!Pmi) {
711 //
712 // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.9 MUST BE ZERO.
713 //
714 ZeroMem ((Cdb + 2), 8);
715 } else {
716 Cdb[14] |= 0x01;
717 }
718
719 Cdb[13] = 0x20;
720 CommandPacket.CdbLength = 16;
721 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
722 CommandPacket.SenseDataLength = *SenseDataLength;
723
724 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
725
726 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
727 *TargetStatus = CommandPacket.TargetStatus;
728 *SenseDataLength = CommandPacket.SenseDataLength;
729 *DataLength = CommandPacket.InTransferLength;
730
731 return Status;
732 }
733
734
735 /**
736 Execute Read(10) SCSI command on a specific SCSI target.
737
738 Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo.
739 If Timeout is zero, then this function waits indefinitely for the command to complete.
740 If Timeout is greater than zero, then the command is executed and will timeout
741 after Timeout 100 ns units. The StartLba and SectorSize parameters are used to
742 construct the CDB for this SCSI command.
743 If ScsiIo is NULL, then ASSERT().
744 If SenseDataLength is NULL, then ASSERT().
745 If HostAdapterStatus is NULL, then ASSERT().
746 If TargetStatus is NULL, then ASSERT().
747 If DataLength is NULL, then ASSERT().
748
749
750 @param[in] ScsiIo A pointer to SCSI IO protocol.
751 @param[in] Timeout The length of timeout period.
752 @param[in, out] SenseData A pointer to output sense data.
753 @param[in, out] SenseDataLength The length of output sense data.
754 @param[out] HostAdapterStatus The status of Host Adapter.
755 @param[out] TargetStatus The status of the target.
756 @param[in, out] DataBuffer Read 10 command data.
757 @param[in, out] DataLength The length of data buffer.
758 @param[in] StartLba The start address of LBA.
759 @param[in] SectorSize The sector size.
760
761 @retval EFI_SUCCESS Command is executed successfully.
762 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
763 not be transferred. The actual number of bytes transferred is returned in DataLength.
764 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
765 SCSI Command Packets already queued.
766 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
767 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
768 the SCSI initiator(i.e., SCSI Host Controller)
769 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
770
771 **/
772 EFI_STATUS
773 EFIAPI
774 ScsiRead10Command (
775 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
776 IN UINT64 Timeout,
777 IN OUT VOID *SenseData, OPTIONAL
778 IN OUT UINT8 *SenseDataLength,
779 OUT UINT8 *HostAdapterStatus,
780 OUT UINT8 *TargetStatus,
781 IN OUT VOID *DataBuffer, OPTIONAL
782 IN OUT UINT32 *DataLength,
783 IN UINT32 StartLba,
784 IN UINT32 SectorSize
785 )
786 {
787 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
788 UINT64 Lun;
789 UINT8 *Target;
790 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
791 EFI_STATUS Status;
792 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
793
794 ASSERT (SenseDataLength != NULL);
795 ASSERT (HostAdapterStatus != NULL);
796 ASSERT (TargetStatus != NULL);
797 ASSERT (DataLength != NULL);
798 ASSERT (ScsiIo != NULL);
799
800 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
801 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
802
803 CommandPacket.Timeout = Timeout;
804 CommandPacket.InDataBuffer = DataBuffer;
805 CommandPacket.SenseData = SenseData;
806 CommandPacket.InTransferLength= *DataLength;
807 CommandPacket.Cdb = Cdb;
808 //
809 // Fill Cdb for Read (10) Command
810 //
811 Target = &TargetArray[0];
812 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
813
814 Cdb[0] = EFI_SCSI_OP_READ10;
815 Cdb[1] = (UINT8) ((Lun << 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
816 Cdb[2] = (UINT8) (StartLba >> 24);
817 Cdb[3] = (UINT8) (StartLba >> 16);
818 Cdb[4] = (UINT8) (StartLba >> 8);
819 Cdb[5] = (UINT8) (StartLba & 0xff);
820 Cdb[7] = (UINT8) (SectorSize >> 8);
821 Cdb[8] = (UINT8) (SectorSize & 0xff);
822
823 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
824 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
825 CommandPacket.SenseDataLength = *SenseDataLength;
826
827 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
828
829 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
830 *TargetStatus = CommandPacket.TargetStatus;
831 *SenseDataLength = CommandPacket.SenseDataLength;
832 *DataLength = CommandPacket.InTransferLength;
833
834 return Status;
835 }
836
837
838 /**
839 Execute Write(10) SCSI command on a specific SCSI target.
840
841 Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo.
842 If Timeout is zero, then this function waits indefinitely for the command to complete.
843 If Timeout is greater than zero, then the command is executed and will timeout after
844 Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct
845 the CDB for this SCSI command.
846 If ScsiIo is NULL, then ASSERT().
847 If SenseDataLength is NULL, then ASSERT().
848 If HostAdapterStatus is NULL, then ASSERT().
849 If TargetStatus is NULL, then ASSERT().
850 If DataLength is NULL, then ASSERT().
851
852 @param[in] ScsiIo SCSI IO Protocol to use
853 @param[in] Timeout The length of timeout period.
854 @param[in, out] SenseData A pointer to output sense data.
855 @param[in, out] SenseDataLength The length of output sense data.
856 @param[out] HostAdapterStatus The status of Host Adapter.
857 @param[out] TargetStatus The status of the target.
858 @param[in, out] DataBuffer A pointer to a data buffer.
859 @param[in, out] DataLength The length of data buffer.
860 @param[in] StartLba The start address of LBA.
861 @param[in] SectorSize The sector size.
862
863 @retval EFI_SUCCESS Command is executed successfully.
864 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
865 not be transferred. The actual number of bytes transferred is returned in DataLength.
866 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
867 SCSI Command Packets already queued.
868 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
869 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
870 the SCSI initiator(i.e., SCSI Host Controller)
871 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
872
873 **/
874 EFI_STATUS
875 EFIAPI
876 ScsiWrite10Command (
877 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
878 IN UINT64 Timeout,
879 IN OUT VOID *SenseData, OPTIONAL
880 IN OUT UINT8 *SenseDataLength,
881 OUT UINT8 *HostAdapterStatus,
882 OUT UINT8 *TargetStatus,
883 IN OUT VOID *DataBuffer, OPTIONAL
884 IN OUT UINT32 *DataLength,
885 IN UINT32 StartLba,
886 IN UINT32 SectorSize
887 )
888 {
889 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
890 UINT64 Lun;
891 UINT8 *Target;
892 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
893 EFI_STATUS Status;
894 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
895
896 ASSERT (SenseDataLength != NULL);
897 ASSERT (HostAdapterStatus != NULL);
898 ASSERT (TargetStatus != NULL);
899 ASSERT (DataLength != NULL);
900 ASSERT (ScsiIo != NULL);
901
902 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
903 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
904
905 CommandPacket.Timeout = Timeout;
906 CommandPacket.OutDataBuffer = DataBuffer;
907 CommandPacket.SenseData = SenseData;
908 CommandPacket.OutTransferLength= *DataLength;
909 CommandPacket.Cdb = Cdb;
910 //
911 // Fill Cdb for Write (10) Command
912 //
913 Target = &TargetArray[0];
914 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
915
916 Cdb[0] = EFI_SCSI_OP_WRITE10;
917 Cdb[1] = (UINT8) ((Lun << 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
918 Cdb[2] = (UINT8) (StartLba >> 24);
919 Cdb[3] = (UINT8) (StartLba >> 16);
920 Cdb[4] = (UINT8) (StartLba >> 8);
921 Cdb[5] = (UINT8) StartLba;
922 Cdb[7] = (UINT8) (SectorSize >> 8);
923 Cdb[8] = (UINT8) SectorSize;
924
925 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
926 CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
927 CommandPacket.SenseDataLength = *SenseDataLength;
928
929 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
930
931 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
932 *TargetStatus = CommandPacket.TargetStatus;
933 *SenseDataLength = CommandPacket.SenseDataLength;
934 *DataLength = CommandPacket.OutTransferLength;
935
936 return Status;
937 }
938