]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiScsiLib/UefiScsiLib.c
89bb2f449b9fcd441bfec2b6478ecf94ff6103c2
[mirror_edk2.git] / MdePkg / Library / UefiScsiLib / UefiScsiLib.c
1 /** @file
2 UEFI SCSI Library implementation
3
4 Copyright (c) 2006 - 2007, 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 <PiDxe.h>
17 #include <Library/DebugLib.h>
18 #include <Library/ScsiLib.h>
19 #include <Library/BaseMemoryLib.h>
20
21 #include <IndustryStandard/Scsi.h>
22
23
24 /**
25 Function test the ready status of the SCSI unit.
26
27 @param[in] ScsiIo A pointer to SCSI IO protocol.
28 @param[in] Timeout The length of timeout period.
29 @param[in out] SenseData A pointer to the sense data that
30 was generated by the execution of the SCSI Request Packet.
31 @param[in out] SenseDataLength On input, the length in bytes of the SenseData buffer. On
32 output, the number of bytes written to the SenseData buffer.
33 @param[out] HostAdapterStatus The status of Host Adapter.
34 @param[out] TargetStatus The status of the target.
35
36 @retval EFI_SUCCESS The status of the unit is tested successfully.
37 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
38 but the entire DataBuffer could not be transferred.
39 The actual number of bytes transferred is returned
40 in InTransferLength.
41 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
42 there are too many SCSI Command Packets already
43 queued.
44 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
45 the SCSI Request Packet.
46 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid, or ScsiIo is NULL.
47 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
48 is not supported by the SCSI initiator(i.e., SCSI
49 Host Controller).
50 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
51 Request Packet to execute.
52
53 **/
54 EFI_STATUS
55 ScsiTestUnitReadyCommand (
56 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
57 IN UINT64 Timeout,
58 IN OUT VOID *SenseData,
59 IN OUT UINT8 *SenseDataLength,
60 OUT UINT8 *HostAdapterStatus,
61 OUT UINT8 *TargetStatus
62 )
63 {
64 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
65 UINT64 Lun;
66 UINT8 *Target;
67 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
68 EFI_STATUS Status;
69 UINT8 Cdb[6];
70
71 ASSERT (SenseDataLength != NULL);
72 ASSERT (HostAdapterStatus != NULL);
73 ASSERT (TargetStatus != NULL);
74
75 if (ScsiIo == NULL) {
76 return EFI_INVALID_PARAMETER;
77 }
78
79 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
80 ZeroMem (Cdb, 6);
81
82 CommandPacket.Timeout = Timeout;
83 CommandPacket.InDataBuffer = NULL;
84 CommandPacket.InTransferLength= 0;
85 CommandPacket.OutDataBuffer = NULL;
86 CommandPacket.OutTransferLength= 0;
87 CommandPacket.SenseData = SenseData;
88 CommandPacket.Cdb = Cdb;
89 //
90 // Fill Cdb for Test Unit Ready Command
91 //
92 Target = &TargetArray[0];
93 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
94
95 Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY;
96 Cdb[1] = (UINT8) (Lun & 0xe0);
97 CommandPacket.CdbLength = (UINT8) 6;
98 CommandPacket.SenseDataLength = *SenseDataLength;
99
100 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
101
102 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
103 *TargetStatus = CommandPacket.TargetStatus;
104 *SenseDataLength = CommandPacket.SenseDataLength;
105
106 return Status;
107 }
108
109
110 /**
111 Function to submit SCSI inquiry command.
112
113 @param[in] ScsiIo SCSI IO Protocol to use
114 @param[in] Timeout The length of timeout period.
115 @param[out] SenseData A pointer to output sense data.
116 @param[in out] SenseDataLength On input, the length in bytes of the SenseData buffer. On
117 output, the number of bytes written to the SenseData buffer.
118 @param[out] HostAdapterStatus The status of Host Adapter.
119 @param[out] TargetStatus The status of the target.
120 @param[in] InquirydataBuffer A pointer to inquiry data buffer.
121 @param[in,out] InquiryDataLength The length of inquiry data buffer.
122 @param[in] EnableVitalProductData Boolean to enable Vital Product Data.
123
124 @retval EFI_SUCCESS The status of the unit is tested successfully.
125 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
126 but the entire DataBuffer could not be transferred.
127 The actual number of bytes transferred is returned
128 in TransferLength.
129 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
130 there are too many SCSI Command Packets already
131 queued.
132 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
133 the SCSI Request Packet.
134 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid, or ScsiIo is NULL.
135 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
136 is not supported by the SCSI initiator(i.e., SCSI
137 Host Controller).
138 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
139 Request Packet to execute.
140
141 **/
142 EFI_STATUS
143 ScsiInquiryCommand (
144 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
145 IN UINT64 Timeout,
146 IN VOID *SenseData,
147 IN OUT UINT8 *SenseDataLength,
148 OUT UINT8 *HostAdapterStatus,
149 OUT UINT8 *TargetStatus,
150 IN VOID *InquiryDataBuffer,
151 IN OUT UINT32 *InquiryDataLength,
152 IN BOOLEAN EnableVitalProductData
153 )
154 {
155 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
156 UINT64 Lun;
157 UINT8 *Target;
158 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
159 EFI_STATUS Status;
160 UINT8 Cdb[6];
161
162 ASSERT (SenseDataLength != NULL);
163 ASSERT (HostAdapterStatus != NULL);
164 ASSERT (TargetStatus != NULL);
165 ASSERT (InquiryDataLength != NULL);
166
167 if (ScsiIo == NULL) {
168 return EFI_INVALID_PARAMETER;
169 }
170
171 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
172 ZeroMem (Cdb, 6);
173
174 CommandPacket.Timeout = Timeout;
175 CommandPacket.InDataBuffer = InquiryDataBuffer;
176 CommandPacket.InTransferLength= *InquiryDataLength;
177 CommandPacket.SenseData = SenseData;
178 CommandPacket.SenseDataLength = *SenseDataLength;
179 CommandPacket.Cdb = Cdb;
180
181 Target = &TargetArray[0];
182 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
183
184 Cdb[0] = EFI_SCSI_OP_INQUIRY;
185 Cdb[1] = (UINT8) (Lun & 0xe0);
186 if (EnableVitalProductData) {
187 Cdb[1] |= 0x01;
188 }
189
190 if (*InquiryDataLength > 0xff) {
191 *InquiryDataLength = 0xff;
192 }
193
194 Cdb[4] = (UINT8) (*InquiryDataLength);
195 CommandPacket.CdbLength = (UINT8) 6;
196 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
197
198 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
199
200 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
201 *TargetStatus = CommandPacket.TargetStatus;
202 *SenseDataLength = CommandPacket.SenseDataLength;
203 *InquiryDataLength = CommandPacket.InTransferLength;
204
205 return Status;
206 }
207
208
209 /**
210 Function to submit SCSI mode sense 10 command.
211
212 @param[in] ScsiIo A pointer to SCSI IO protocol.
213 @param[in] Timeout The length of timeout period.
214 @param[out] SenseData A pointer to output sense data.
215 @param[in out] SenseDataLength On input, the length in bytes of the SenseData buffer. On
216 output, the number of bytes written to the SenseData buffer.
217 @param[out] HostAdapterStatus The status of Host Adapter.
218 @param[out] TargetStatus The status of the target.
219 @param[in] DataBuffer A pointer to input data buffer.
220 @param[in,out] DataLength The length of input data buffer.
221 @param[in] DBDField The DBD Field (Optional).
222 @param[in] PageControl Page Control.
223 @param[in] PageCode Page code.
224
225 @retval EFI_SUCCESS The status of the unit is tested successfully.
226 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
227 but the entire DataBuffer could not be transferred.
228 The actual number of bytes transferred is returned
229 in TransferLength.
230 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
231 there are too many SCSI Command Packets already
232 queued.
233 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
234 the SCSI Request Packet.
235 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid, or ScsiIo is NULL.
236 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
237 is not supported by the SCSI initiator(i.e., SCSI
238 Host Controller).
239 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
240 Request Packet to execute.
241
242 **/
243 EFI_STATUS
244 ScsiModeSense10Command (
245 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
246 IN UINT64 Timeout,
247 IN VOID *SenseData,
248 IN OUT UINT8 *SenseDataLength,
249 OUT UINT8 *HostAdapterStatus,
250 OUT UINT8 *TargetStatus,
251 IN VOID *DataBuffer,
252 IN OUT UINT32 *DataLength,
253 IN UINT8 DBDField, OPTIONAL
254 IN UINT8 PageControl,
255 IN UINT8 PageCode
256 )
257 {
258 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
259 UINT64 Lun;
260 UINT8 *Target;
261 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
262 EFI_STATUS Status;
263 UINT8 Cdb[10];
264
265 ASSERT (SenseDataLength != NULL);
266 ASSERT (HostAdapterStatus != NULL);
267 ASSERT (TargetStatus != NULL);
268 ASSERT (DataLength != NULL);
269
270 if (ScsiIo == NULL) {
271 return EFI_INVALID_PARAMETER;
272 }
273
274 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
275 ZeroMem (Cdb, 10);
276
277 CommandPacket.Timeout = Timeout;
278 CommandPacket.InDataBuffer = DataBuffer;
279 CommandPacket.SenseData = SenseData;
280 CommandPacket.InTransferLength= *DataLength;
281 CommandPacket.Cdb = Cdb;
282 //
283 // Fill Cdb for Mode Sense (10) Command
284 //
285 Target = &TargetArray[0];
286 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
287
288 Cdb[0] = EFI_SCSI_OP_MODE_SEN10;
289 Cdb[1] = (UINT8) ((Lun & 0xe0) + ((DBDField << 3) & 0x08));
290 Cdb[2] = (UINT8) ((PageControl & 0xc0) | (PageCode & 0x3f));
291 Cdb[7] = (UINT8) (*DataLength >> 8);
292 Cdb[8] = (UINT8) (*DataLength);
293
294 CommandPacket.CdbLength = 10;
295 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
296 CommandPacket.SenseDataLength = *SenseDataLength;
297
298 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
299
300 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
301 *TargetStatus = CommandPacket.TargetStatus;
302 *SenseDataLength = CommandPacket.SenseDataLength;
303 *DataLength = CommandPacket.InTransferLength;
304
305 return Status;
306 }
307
308
309 /**
310 Function to submit SCSI request sense command.
311
312 @param[in] ScsiIo A pointer to SCSI IO protocol.
313 @param[in] Timeout The length of timeout period.
314 @param[in] SenseData A pointer to output sense data.
315 @param[in out] SenseDataLength On input, the length in bytes of the SenseData buffer. On
316 output, the number of bytes written to the SenseData buffer.
317 @param[out] HostAdapterStatus The status of Host Adapter.
318 @param[out] TargetStatus The status of the target.
319
320 @retval EFI_SUCCESS Valid data returned
321 @retval EFI_SUCCESS The status of the unit is tested successfully.
322 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
323 but the entire DataBuffer could not be transferred.
324 The actual number of bytes transferred is returned
325 in TransferLength.
326 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
327 there are too many SCSI Command Packets already
328 queued.
329 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
330 the SCSI Request Packet.
331 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid, or ScsiIo is NULL.
332 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
333 is not supported by the SCSI initiator(i.e., SCSI
334 Host Controller).
335 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
336 Request Packet to execute.
337
338 **/
339 EFI_STATUS
340 ScsiRequestSenseCommand (
341 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
342 IN UINT64 Timeout,
343 IN VOID *SenseData,
344 IN OUT UINT8 *SenseDataLength,
345 OUT UINT8 *HostAdapterStatus,
346 OUT UINT8 *TargetStatus
347 )
348 {
349 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
350 UINT64 Lun;
351 UINT8 *Target;
352 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
353 EFI_STATUS Status;
354 UINT8 Cdb[6];
355
356 ASSERT (SenseDataLength != NULL);
357 ASSERT (HostAdapterStatus != NULL);
358 ASSERT (TargetStatus != NULL);
359
360 if (ScsiIo == NULL) {
361 return EFI_INVALID_PARAMETER;
362 }
363
364 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
365 ZeroMem (Cdb, 6);
366
367 CommandPacket.Timeout = Timeout;
368 CommandPacket.InDataBuffer = SenseData;
369 CommandPacket.SenseData = NULL;
370 CommandPacket.InTransferLength= *SenseDataLength;
371 CommandPacket.Cdb = Cdb;
372 //
373 // Fill Cdb for Request Sense Command
374 //
375 Target = &TargetArray[0];
376 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
377
378 Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE;
379 Cdb[1] = (UINT8) (Lun & 0xe0);
380 Cdb[4] = (UINT8) (*SenseDataLength);
381
382 CommandPacket.CdbLength = (UINT8) 6;
383 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
384 CommandPacket.SenseDataLength = 0;
385
386 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
387
388 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
389 *TargetStatus = CommandPacket.TargetStatus;
390 *SenseDataLength = (UINT8) CommandPacket.InTransferLength;
391
392 return Status;
393 }
394
395
396 /**
397 Function to submit read capacity command.
398
399 @param[in] ScsiIo A pointer to SCSI IO protocol.
400 @param[in] Timeout The length of timeout period.
401 @param[out] SenseData A pointer to output sense data.
402 @param[in out] SenseDataLength On input, the length in bytes of the SenseData buffer. On
403 output, the number of bytes written to the SenseData buffer.
404 @param[out] HostAdapterStatus The status of Host Adapter.
405 @param[out] TargetStatus The status of the target.
406 @param[out] DataBuffer A pointer to a data buffer.
407 @param[in,out] DataLength The length of data buffer.
408 @param[in] PMI Partial medium indicator.
409
410 @retval EFI_SUCCESS The status of the unit is tested successfully.
411 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
412 but the entire DataBuffer could not be transferred.
413 The actual number of bytes transferred is returned
414 in TransferLength.
415 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
416 there are too many SCSI Command Packets already
417 queued.
418 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
419 the SCSI Request Packet.
420 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid, or ScsiIo is NULL.
421 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
422 is not supported by the SCSI initiator(i.e., SCSI
423 Host Controller).
424 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
425 Request Packet to execute.
426
427 **/
428 EFI_STATUS
429 ScsiReadCapacityCommand (
430 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
431 IN UINT64 Timeout,
432 IN VOID *SenseData,
433 IN OUT UINT8 *SenseDataLength,
434 OUT UINT8 *HostAdapterStatus,
435 OUT UINT8 *TargetStatus,
436 OUT VOID *DataBuffer,
437 IN OUT UINT32 *DataLength,
438 IN BOOLEAN PMI
439 )
440 {
441 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
442 UINT64 Lun;
443 UINT8 *Target;
444 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
445 EFI_STATUS Status;
446 UINT8 Cdb[10];
447
448 ASSERT (SenseDataLength != NULL);
449 ASSERT (HostAdapterStatus != NULL);
450 ASSERT (TargetStatus != NULL);
451 ASSERT (DataLength != NULL);
452
453 if (ScsiIo == NULL) {
454 return EFI_INVALID_PARAMETER;
455 }
456
457 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
458 ZeroMem (Cdb, 10);
459
460 CommandPacket.Timeout = Timeout;
461 CommandPacket.InDataBuffer = DataBuffer;
462 CommandPacket.SenseData = SenseData;
463 CommandPacket.InTransferLength= *DataLength;
464 CommandPacket.Cdb = Cdb;
465 //
466 // Fill Cdb for Read Capacity Command
467 //
468 Target = &TargetArray[0];
469 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
470
471 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
472 Cdb[1] = (UINT8) (Lun & 0xe0);
473 if (!PMI) {
474 //
475 // Partial medium indicator,if PMI is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO.
476 //
477 ZeroMem ((Cdb + 2), 4);
478 } else {
479 Cdb[8] |= 0x01;
480 }
481
482 CommandPacket.CdbLength = 10;
483 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
484 CommandPacket.SenseDataLength = *SenseDataLength;
485
486 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
487
488 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
489 *TargetStatus = CommandPacket.TargetStatus;
490 *SenseDataLength = CommandPacket.SenseDataLength;
491 *DataLength = CommandPacket.InTransferLength;
492
493 return Status;
494 }
495
496
497 /**
498 Function to submit read 10 command.
499
500 @param[in] ScsiIo A pointer to SCSI IO protocol.
501 @param[in] Timeout The length of timeout period.
502 @param[out] SenseData A pointer to output sense data.
503 @param[in out] SenseDataLength On input, the length in bytes of the SenseData buffer. On
504 output, the number of bytes written to the SenseData buffer.
505 @param[out] HostAdapterStatus The status of Host Adapter.
506 @param[out] TargetStatus The status of the target.
507 @param[out] DataBuffer Read 10 command data.
508 @param[in,out] DataLength The length of data buffer.
509 @param[in] StartLba The start address of LBA.
510 @param[in] SectorSize The sector size.
511
512 @retval EFI_SUCCESS The status of the unit is tested successfully.
513 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
514 but the entire DataBuffer could not be transferred.
515 The actual number of bytes transferred is returned
516 in TransferLength.
517 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
518 there are too many SCSI Command Packets already
519 queued.
520 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
521 the SCSI Request Packet.
522 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid, or ScsiIo is NULL.
523 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
524 is not supported by the SCSI initiator(i.e., SCSI
525 Host Controller).
526 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
527 Request Packet to execute.
528
529 **/
530 EFI_STATUS
531 ScsiRead10Command (
532 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
533 IN UINT64 Timeout,
534 IN VOID *SenseData,
535 IN OUT UINT8 *SenseDataLength,
536 OUT UINT8 *HostAdapterStatus,
537 OUT UINT8 *TargetStatus,
538 OUT VOID *DataBuffer,
539 IN OUT UINT32 *DataLength,
540 IN UINT32 StartLba,
541 IN UINT32 SectorSize
542 )
543 {
544 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
545 UINT64 Lun;
546 UINT8 *Target;
547 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
548 EFI_STATUS Status;
549 UINT8 Cdb[10];
550
551 ASSERT (SenseDataLength != NULL);
552 ASSERT (HostAdapterStatus != NULL);
553 ASSERT (TargetStatus != NULL);
554 ASSERT (DataLength != NULL);
555
556 if (ScsiIo == NULL) {
557 return EFI_INVALID_PARAMETER;
558 }
559
560 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
561 ZeroMem (Cdb, 10);
562
563 CommandPacket.Timeout = Timeout;
564 CommandPacket.InDataBuffer = DataBuffer;
565 CommandPacket.SenseData = SenseData;
566 CommandPacket.InTransferLength= *DataLength;
567 CommandPacket.Cdb = Cdb;
568 //
569 // Fill Cdb for Read (10) Command
570 //
571 Target = &TargetArray[0];
572 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
573
574 Cdb[0] = EFI_SCSI_OP_READ10;
575 Cdb[1] = (UINT8) (Lun & 0xe0);
576 Cdb[2] = (UINT8) (StartLba >> 24);
577 Cdb[3] = (UINT8) (StartLba >> 16);
578 Cdb[4] = (UINT8) (StartLba >> 8);
579 Cdb[5] = (UINT8) (StartLba & 0xff);
580 Cdb[7] = (UINT8) (SectorSize >> 8);
581 Cdb[8] = (UINT8) (SectorSize & 0xff);
582
583 CommandPacket.CdbLength = 10;
584 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
585 CommandPacket.SenseDataLength = *SenseDataLength;
586
587 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
588
589 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
590 *TargetStatus = CommandPacket.TargetStatus;
591 *SenseDataLength = CommandPacket.SenseDataLength;
592 *DataLength = CommandPacket.InTransferLength;
593
594 return Status;
595 }
596
597
598 /**
599 Function to submit SCSI write 10 command.
600
601 @param[in] ScsiIo SCSI IO Protocol to use
602 @param[in] Timeout The length of timeout period.
603 @param[out] SenseData A pointer to output sense data.
604 @param[in out] SenseDataLength On input, the length in bytes of the SenseData buffer. On
605 output, the number of bytes written to the SenseData buffer.
606 @param[out] HostAdapterStatus The status of Host Adapter.
607 @param[out] TargetStatus The status of the target.
608 @param[out] DataBuffer A pointer to a data buffer.
609 @param[in,out] DataLength The length of data buffer.
610 @param[in] StartLba The start address of LBA.
611 @param[in] SectorSize The sector size.
612
613 @retval EFI_SUCCESS The status of the unit is tested successfully.
614 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
615 but the entire DataBuffer could not be transferred.
616 The actual number of bytes transferred is returned
617 in InTransferLength.
618 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
619 there are too many SCSI Command Packets already
620 queued.
621 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
622 the SCSI Request Packet.
623 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid, or ScsiIo is NULL.
624 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
625 is not supported by the SCSI initiator(i.e., SCSI
626 Host Controller).
627 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
628 Request Packet to execute.
629
630 **/
631 EFI_STATUS
632 ScsiWrite10Command (
633 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
634 IN UINT64 Timeout,
635 IN VOID *SenseData,
636 IN OUT UINT8 *SenseDataLength,
637 OUT UINT8 *HostAdapterStatus,
638 OUT UINT8 *TargetStatus,
639 OUT VOID *DataBuffer,
640 IN OUT UINT32 *DataLength,
641 IN UINT32 StartLba,
642 IN UINT32 SectorSize
643 )
644 {
645 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
646 UINT64 Lun;
647 UINT8 *Target;
648 UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
649 EFI_STATUS Status;
650 UINT8 Cdb[10];
651
652 ASSERT (SenseDataLength != NULL);
653 ASSERT (HostAdapterStatus != NULL);
654 ASSERT (TargetStatus != NULL);
655 ASSERT (DataLength != NULL);
656
657 if (ScsiIo == NULL) {
658 return EFI_INVALID_PARAMETER;
659 }
660
661 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
662 ZeroMem (Cdb, 10);
663
664 CommandPacket.Timeout = Timeout;
665 CommandPacket.OutDataBuffer = DataBuffer;
666 CommandPacket.SenseData = SenseData;
667 CommandPacket.OutTransferLength= *DataLength;
668 CommandPacket.Cdb = Cdb;
669 //
670 // Fill Cdb for Write (10) Command
671 //
672 Target = &TargetArray[0];
673 ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
674
675 Cdb[0] = EFI_SCSI_OP_WRITE10;
676 Cdb[1] = (UINT8) (Lun & 0xe0);
677 Cdb[2] = (UINT8) (StartLba >> 24);
678 Cdb[3] = (UINT8) (StartLba >> 16);
679 Cdb[4] = (UINT8) (StartLba >> 8);
680 Cdb[5] = (UINT8) StartLba;
681 Cdb[7] = (UINT8) (SectorSize >> 8);
682 Cdb[8] = (UINT8) SectorSize;
683
684 CommandPacket.CdbLength = 10;
685 CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
686 CommandPacket.SenseDataLength = *SenseDataLength;
687
688 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
689
690 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
691 *TargetStatus = CommandPacket.TargetStatus;
692 *SenseDataLength = CommandPacket.SenseDataLength;
693 *DataLength = CommandPacket.OutTransferLength;
694
695 return Status;
696 }