For USB mass storage, READ_FORMAT_CAPACITIES command returns wrong value for USB2...
[mirror_edk2.git] / EdkModulePkg / Bus / Usb / UsbMassStorage / Dxe / UsbMassStorageHelper.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 UsbMassStorageHelper.c
15
16 Abstract:
17
18 Helper functions for USB Mass Storage Driver
19
20 Revision History
21
22 --*/
23
24 #include "UsbMassStorageHelper.h"
25
26 STATIC
27 BOOLEAN
28 IsNoMedia (
29 IN REQUEST_SENSE_DATA *SenseData,
30 IN UINTN SenseCounts
31 );
32
33 STATIC
34 BOOLEAN
35 IsMediaError (
36 IN REQUEST_SENSE_DATA *SenseData,
37 IN UINTN SenseCounts
38 );
39
40 STATIC
41 BOOLEAN
42 IsMediaChange (
43 IN REQUEST_SENSE_DATA *SenseData,
44 IN UINTN SenseCounts
45 );
46
47 STATIC
48 BOOLEAN
49 IsDriveReady (
50 IN REQUEST_SENSE_DATA *SenseData,
51 IN UINTN SenseCounts,
52 OUT BOOLEAN *NeedRetry
53 );
54
55 STATIC
56 BOOLEAN
57 IsMediaWriteProtected (
58 IN REQUEST_SENSE_DATA *SenseData,
59 IN UINTN SenseCounts
60 );
61
62 STATIC
63 BOOLEAN
64 IsLogicalUnitCommunicationOverRun (
65 IN REQUEST_SENSE_DATA *SenseData,
66 IN UINTN SenseCounts
67 );
68
69 EFI_STATUS
70 USBFloppyPacketCommand (
71 USB_FLOPPY_DEV *UsbFloppyDevice,
72 VOID *Command,
73 UINT8 CommandSize,
74 VOID *DataBuffer,
75 UINT32 BufferLength,
76 EFI_USB_DATA_DIRECTION Direction,
77 UINT16 TimeOutInMilliSeconds
78 )
79 /*++
80
81 Routine Description:
82 Sends Packet Command to USB Floppy Drive.
83
84 Arguments:
85 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
86 Command - A pointer to the command packet.
87 CommandSize - Indicates the size of the command packet.
88 DataBuffer - A pointer to the buffer for the data transfer
89 after the command packet.
90 BufferLength - Indicates the size of the Data Buffer.
91 Direction - Transfer Direction
92 TimeOutInMilliSeconds - Timeout Value
93 Returns:
94 EFI_SUCCESS - Success
95 --*/
96 {
97 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
98 EFI_STATUS Status;
99
100 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
101 //
102 // Directly calling EFI_USB_ATAPI_PROTOCOL.UsbAtapiPacketCmd()
103 // to perform the command request.
104 //
105 Status = UsbAtapiInterface->UsbAtapiPacketCmd (
106 UsbAtapiInterface,
107 Command,
108 CommandSize,
109 DataBuffer,
110 BufferLength,
111 Direction,
112 TimeOutInMilliSeconds
113 );
114
115 return Status;
116 }
117
118 EFI_STATUS
119 USBFloppyIdentify (
120 IN USB_FLOPPY_DEV *UsbFloppyDevice
121 )
122 /*++
123
124 Routine Description:
125 Retrieves device information to tell the device type.
126
127 Arguments:
128 UsbFloppyDevice The USB_FLOPPY_DEV instance.
129
130 Returns:
131 EFI_DEVICE_ERROR - Hardware error
132 EFI_SUCCESS - Success
133 --*/
134 {
135
136 EFI_STATUS Status;
137 USB_INQUIRY_DATA *Idata;
138 BOOLEAN MediaChange;
139
140 //
141 // Send Inquiry Packet Command to get INQUIRY data.
142 //
143 Status = USBFloppyInquiry (UsbFloppyDevice, &Idata);
144 if (EFI_ERROR (Status)) {
145 return EFI_DEVICE_ERROR;
146 }
147
148 //
149 // Get media removable info from INQUIRY data.
150 //
151 UsbFloppyDevice->BlkIo.Media->RemovableMedia = (UINT8) ((Idata->RMB & 0x80) == 0x80);
152
153 //
154 // Identify device type via INQUIRY data.
155 //
156 switch ((Idata->peripheral_type) & 0x1f) {
157 //
158 // Floppy
159 //
160 case 0x00:
161 UsbFloppyDevice->DeviceType = USBFLOPPY;
162 UsbFloppyDevice->BlkIo.Media->MediaId = 0;
163 UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
164 UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
165 UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200;
166 break;
167
168 //
169 // CD-ROM
170 //
171 case 0x05:
172 UsbFloppyDevice->DeviceType = USBCDROM;
173 UsbFloppyDevice->BlkIo.Media->MediaId = 0;
174 UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
175 UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
176 UsbFloppyDevice->BlkIo.Media->BlockSize = 0x800;
177 UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE;
178 break;
179
180 default:
181 gBS->FreePool (Idata);
182 return EFI_DEVICE_ERROR;
183 };
184
185 //
186 // Initialize some device specific data.
187 //
188 //
189 // original sense data numbers
190 //
191 UsbFloppyDevice->SenseDataNumber = 6;
192
193 if (UsbFloppyDevice->SenseData != NULL) {
194 gBS->FreePool (UsbFloppyDevice->SenseData);
195 UsbFloppyDevice->SenseData = NULL;
196 }
197
198 UsbFloppyDevice->SenseData = AllocatePool (UsbFloppyDevice->SenseDataNumber * sizeof (REQUEST_SENSE_DATA));
199
200 if (UsbFloppyDevice->SenseData == NULL) {
201 gBS->FreePool (Idata);
202 return EFI_DEVICE_ERROR;
203 }
204
205 //
206 // Get media information.
207 //
208 UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange);
209
210 gBS->FreePool (Idata);
211
212 return EFI_SUCCESS;
213 }
214
215 EFI_STATUS
216 USBFloppyInquiry (
217 IN USB_FLOPPY_DEV *UsbFloppyDevice,
218 OUT USB_INQUIRY_DATA **Idata
219 )
220 /*++
221
222 Routine Description:
223 Send Inquiry Packet Command to device and retrieve Inquiry Data.
224
225 Arguments:
226 UsbFloppyDevice The USB_FLOPPY_DEV instance.
227 Idata A pointer pointing to the address of
228 Inquiry Data.
229
230 Returns:
231 EFI_DEVICE_ERROR - Hardware error
232 EFI_SUCCESS - Success
233 --*/
234 {
235 ATAPI_PACKET_COMMAND Packet;
236 EFI_STATUS Status;
237 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
238
239 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
240
241 //
242 // prepare command packet for the Inquiry Packet Command.
243 //
244 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
245 Packet.Inquiry.opcode = INQUIRY;
246 Packet.Inquiry.page_code = 0;
247 Packet.Inquiry.allocation_length = sizeof (USB_INQUIRY_DATA);
248
249 *Idata = AllocateZeroPool (sizeof (USB_INQUIRY_DATA));
250 if (*Idata == NULL) {
251 return EFI_DEVICE_ERROR;
252 }
253 //
254 // Send command packet and retrieve requested Inquiry Data.
255 //
256 Status = USBFloppyPacketCommand (
257 UsbFloppyDevice,
258 &Packet,
259 sizeof (ATAPI_PACKET_COMMAND),
260 (VOID *) (*Idata),
261 sizeof (USB_INQUIRY_DATA),
262 EfiUsbDataIn,
263 USBFLPTIMEOUT * 3
264 );
265 if (EFI_ERROR (Status)) {
266 gBS->FreePool (*Idata);
267 return EFI_DEVICE_ERROR;
268 }
269
270 return EFI_SUCCESS;
271 }
272
273 EFI_STATUS
274 USBFloppyRead10 (
275 IN USB_FLOPPY_DEV *UsbFloppyDevice,
276 IN VOID *Buffer,
277 IN EFI_LBA Lba,
278 IN UINTN NumberOfBlocks
279 )
280 /*++
281
282 Routine Description:
283 Sends Read10 Packet Command to device to perform data transfer
284 from device to host.
285
286 Arguments:
287 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
288 Buffer - A pointer to the destination buffer for the data.
289 The caller is responsible for either having implicit
290 or explicit ownership of the buffer.
291 Lba - The starting logical block address to read from
292 on the device.
293 NumberOfBlocks - Indicates the number of blocks that the read
294 operation requests.
295
296 Returns:
297 EFI_DEVICE_ERROR - Hardware error
298 EFI_SUCCESS - Success
299 --*/
300 {
301 ATAPI_PACKET_COMMAND Packet;
302 READ10_CMD *Read10Packet;
303 UINT16 MaxBlock;
304 UINT16 BlocksRemaining;
305 UINT16 SectorCount;
306 UINT32 Lba32;
307 UINT32 BlockSize;
308 UINT32 ByteCount;
309 VOID *ptrBuffer;
310 EFI_STATUS Status;
311 UINT16 TimeOut;
312 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
313 UINTN SenseCounts;
314
315 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
316
317 //
318 // prepare command packet for the Inquiry Packet Command.
319 //
320 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
321 Read10Packet = &Packet.Read10;
322 Lba32 = (UINT32) Lba;
323 ptrBuffer = Buffer;
324 BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize;
325
326 MaxBlock = (UINT16) (65536 / BlockSize);
327 BlocksRemaining = (UINT16) NumberOfBlocks;
328
329 Status = EFI_SUCCESS;
330 while (BlocksRemaining > 0) {
331 if (BlocksRemaining <= MaxBlock) {
332 SectorCount = BlocksRemaining;
333 } else {
334 SectorCount = MaxBlock;
335 }
336 //
337 // fill the Packet data structure
338 //
339 Read10Packet->opcode = READ_10;
340
341 //
342 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
343 // Lba0 is MSB, Lba3 is LSB
344 //
345 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
346 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);
347 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);
348 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);
349
350 //
351 // TranLen0 ~ TranLen1 specify the transfer length in block unit.
352 // TranLen0 is MSB, TranLen is LSB
353 //
354 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
355 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
356
357 ByteCount = SectorCount * BlockSize;
358
359 TimeOut = (UINT16) (SectorCount * USBFLPTIMEOUT);
360
361 Status = USBFloppyPacketCommand (
362 UsbFloppyDevice,
363 &Packet,
364 sizeof (ATAPI_PACKET_COMMAND),
365 (VOID *) ptrBuffer,
366 ByteCount,
367 EfiUsbDataIn,
368 TimeOut
369 );
370 if (EFI_ERROR (Status)) {
371
372 Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts);
373 if (!EFI_ERROR (Status)) {
374 if (IsLogicalUnitCommunicationOverRun (
375 UsbFloppyDevice->SenseData,
376 SenseCounts
377 )) {
378 Lba32 = (UINT32) Lba;
379 ptrBuffer = Buffer;
380 BlocksRemaining = (UINT16) NumberOfBlocks;
381 MaxBlock = (UINT16) (MaxBlock / 4);
382 if (MaxBlock < 1) {
383 MaxBlock = 1;
384 }
385
386 continue;
387 }
388 } else {
389 return EFI_DEVICE_ERROR;
390 }
391 //
392 // retry read10 command
393 //
394 Status = USBFloppyPacketCommand (
395 UsbFloppyDevice,
396 &Packet,
397 sizeof (ATAPI_PACKET_COMMAND),
398 (VOID *) ptrBuffer,
399 ByteCount,
400 EfiUsbDataIn,
401 TimeOut
402 );
403 if (EFI_ERROR (Status)) {
404 return EFI_DEVICE_ERROR;
405 }
406 }
407
408 Lba32 += SectorCount;
409 ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize;
410 BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
411 }
412
413 return Status;
414 }
415
416 EFI_STATUS
417 USBFloppyReadCapacity (
418 IN USB_FLOPPY_DEV *UsbFloppyDevice
419 )
420 /*++
421
422 Routine Description:
423 Retrieves media capacity information via
424 sending Read Capacity Packet Command.
425
426 Arguments:
427 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
428
429 Returns:
430 EFI_DEVICE_ERROR - Hardware error
431 EFI_SUCCESS - Success
432 --*/
433 {
434 //
435 // status returned by Read Capacity Packet Command
436 //
437 EFI_STATUS Status;
438 ATAPI_PACKET_COMMAND Packet;
439 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
440
441 //
442 // used for capacity data returned from Usb Floppy
443 //
444 READ_CAPACITY_DATA Data;
445
446 ZeroMem (&Data, sizeof (Data));
447
448 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
449
450 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
451 Packet.Inquiry.opcode = READ_CAPACITY;
452 Status = USBFloppyPacketCommand (
453 UsbFloppyDevice,
454 &Packet,
455 sizeof (ATAPI_PACKET_COMMAND),
456 (VOID *) &Data,
457 sizeof (READ_CAPACITY_DATA),
458 EfiUsbDataIn,
459 USBFLPTIMEOUT
460 );
461
462 if (EFI_ERROR (Status)) {
463 return EFI_DEVICE_ERROR;
464 }
465
466 UsbFloppyDevice->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |
467 (Data.LastLba2 << 16) |
468 (Data.LastLba1 << 8) |
469 Data.LastLba0;
470
471 UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE;
472
473 UsbFloppyDevice->BlkIo.Media->BlockSize = 0x800;
474
475 return EFI_SUCCESS;
476
477 }
478
479 EFI_STATUS
480 USBFloppyReadFormatCapacity (
481 IN USB_FLOPPY_DEV *UsbFloppyDevice
482 )
483 /*++
484
485 Routine Description:
486 Retrieves media capacity information via sending Read Format
487 Capacity Packet Command.
488
489 Arguments:
490 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
491
492 Returns:
493 EFI_DEVICE_ERROR - Hardware error
494 EFI_SUCCESS - Success
495 --*/
496 {
497 //
498 // status returned by Read Capacity Packet Command
499 //
500 EFI_STATUS Status;
501 ATAPI_PACKET_COMMAND Packet;
502 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
503
504 //
505 // used for capacity data returned from Usb Floppy
506 //
507 READ_FORMAT_CAPACITY_DATA FormatData;
508
509 ZeroMem (&FormatData, sizeof (FormatData));
510
511 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
512
513 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
514 Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY;
515 Packet.ReadFormatCapacity.allocation_length_lo = 12;
516 Status = USBFloppyPacketCommand (
517 UsbFloppyDevice,
518 &Packet,
519 sizeof (ATAPI_PACKET_COMMAND),
520 (VOID *) &FormatData,
521 sizeof (READ_FORMAT_CAPACITY_DATA),
522 EfiUsbDataIn,
523 USBFLPTIMEOUT
524 );
525
526 if (EFI_ERROR (Status)) {
527 return EFI_DEVICE_ERROR;
528 }
529
530 if (FormatData.DesCode == 3) {
531 //
532 // Media is not present
533 //
534 UsbFloppyDevice->BlkIo.Media->MediaId = 0;
535 UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
536 UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
537 } else {
538
539 UsbFloppyDevice->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) |
540 (FormatData.LastLba2 << 16) |
541 (FormatData.LastLba1 << 8) |
542 FormatData.LastLba0;
543
544 UsbFloppyDevice->BlkIo.Media->LastBlock--;
545
546 UsbFloppyDevice->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |
547 (FormatData.BlockSize1 << 8) |
548 FormatData.BlockSize0;
549
550 UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE;
551
552 UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200;
553
554 }
555
556 return EFI_SUCCESS;
557
558 }
559
560 EFI_STATUS
561 UsbFloppyRequestSense (
562 IN USB_FLOPPY_DEV *UsbFloppyDevice,
563 OUT UINTN *SenseCounts
564 )
565 /*++
566
567 Routine Description:
568 Retrieves Sense Data from device via
569 sending Request Sense Packet Command.
570
571 Arguments:
572 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
573 SenseCounts - A pointer to the number of Sense Data returned.
574
575 Returns:
576 EFI_DEVICE_ERROR - Hardware error
577 EFI_SUCCESS - Success
578 --*/
579 {
580 EFI_STATUS Status;
581 REQUEST_SENSE_DATA *Sense;
582 UINT8 *Ptr;
583 BOOLEAN SenseReq;
584 ATAPI_PACKET_COMMAND Packet;
585 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
586
587 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
588
589 *SenseCounts = 0;
590
591 ZeroMem (
592 UsbFloppyDevice->SenseData,
593 sizeof (REQUEST_SENSE_DATA) * (UsbFloppyDevice->SenseDataNumber)
594 );
595 //
596 // fill command packet for Request Sense Packet Command
597 //
598 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
599 Packet.RequestSense.opcode = REQUEST_SENSE;
600 Packet.RequestSense.allocation_length = sizeof (REQUEST_SENSE_DATA);
601
602 //
603 // initialize pointer
604 //
605 Ptr = (UINT8 *) (UsbFloppyDevice->SenseData);
606
607 //
608 // request sense data from device continuously
609 // until no sense data exists in the device.
610 //
611 for (SenseReq = TRUE; SenseReq;) {
612
613 Sense = (REQUEST_SENSE_DATA *) Ptr;
614
615 //
616 // send out Request Sense Packet Command and get one Sense
617 // data from device.
618 //
619 Status = USBFloppyPacketCommand (
620 UsbFloppyDevice,
621 &Packet,
622 sizeof (ATAPI_PACKET_COMMAND),
623 (VOID *) Ptr,
624 sizeof (REQUEST_SENSE_DATA),
625 EfiUsbDataIn,
626 USBFLPTIMEOUT
627 );
628 //
629 // failed to get Sense data
630 //
631 if (EFI_ERROR (Status)) {
632 //
633 // Recovery the device back to normal state.
634 //
635 UsbFloppyDevice->AtapiProtocol->UsbAtapiReset (
636 UsbFloppyDevice->AtapiProtocol,
637 TRUE
638 );
639
640 if (*SenseCounts == 0) {
641 //
642 // never retrieved any sense data from device,
643 // just return error.
644 //
645 return EFI_DEVICE_ERROR;
646 } else {
647 //
648 // has retrieved some sense data from device,
649 // so return success.
650 //
651 return EFI_SUCCESS;
652 }
653 }
654
655 if (Sense->sense_key != SK_NO_SENSE) {
656 //
657 // Ptr is byte based pointer
658 //
659 Ptr += sizeof (REQUEST_SENSE_DATA);
660
661 (*SenseCounts)++;
662
663 } else {
664 //
665 // when no sense key, skip out the loop
666 //
667 SenseReq = FALSE;
668 }
669
670 //
671 // If the sense key numbers exceed Sense Data Buffer size,
672 // just skip the loop and do not fetch the sense key in this function.
673 //
674 if (*SenseCounts == UsbFloppyDevice->SenseDataNumber) {
675 SenseReq = FALSE;
676 }
677 }
678
679 return EFI_SUCCESS;
680 }
681
682 EFI_STATUS
683 UsbFloppyTestUnitReady (
684 IN USB_FLOPPY_DEV *UsbFloppyDevice
685 )
686 /*++
687
688 Routine Description:
689 Sends Test Unit ReadyPacket Command to the device.
690
691 Arguments:
692 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
693
694 Returns:
695 EFI_DEVICE_ERROR - Hardware error
696 EFI_SUCCESS - Success
697 --*/
698 {
699 ATAPI_PACKET_COMMAND Packet;
700 EFI_STATUS Status;
701 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
702 UINT32 RetryIndex;
703 UINT32 MaximumRetryTimes;
704
705 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
706 MaximumRetryTimes = 2;
707 //
708 // fill command packet
709 //
710 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
711 Packet.TestUnitReady.opcode = TEST_UNIT_READY;
712
713 //
714 // send command packet
715 //
716 Status = EFI_DEVICE_ERROR;
717
718 for (RetryIndex = 0; RetryIndex < MaximumRetryTimes && EFI_ERROR (Status); RetryIndex++) {
719
720 Status = USBFloppyPacketCommand (
721 UsbFloppyDevice,
722 &Packet,
723 sizeof (ATAPI_PACKET_COMMAND),
724 NULL,
725 0,
726 EfiUsbNoData,
727 USBFLPTIMEOUT
728 );
729
730 if (EFI_ERROR (Status)) {
731 gBS->Stall (100 * STALL_1_MILLI_SECOND);
732 }
733 }
734
735 return Status;
736 }
737
738 EFI_STATUS
739 USBFloppyWrite10 (
740 IN USB_FLOPPY_DEV *UsbFloppyDevice,
741 IN VOID *Buffer,
742 IN EFI_LBA Lba,
743 IN UINTN NumberOfBlocks
744 )
745 /*++
746
747 Routine Description:
748 Sends Write10 Packet Command to device to perform data transfer
749 from host to device.
750
751 Arguments:
752 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
753 Buffer - A pointer to the source buffer for the data.
754 The caller is responsible for either having implicit
755 or explicit ownership of the buffer.
756 Lba - The starting logical block address to written to
757 the device.
758 NumberOfBlocks - Indicates the number of blocks that the write
759 operation requests.
760
761 Returns:
762 EFI_DEVICE_ERROR - Hardware error
763 EFI_SUCCESS - Success
764 --*/
765 {
766 ATAPI_PACKET_COMMAND Packet;
767 READ10_CMD *Write10Packet;
768 UINT16 MaxBlock;
769 UINT16 BlocksRemaining;
770 UINT16 SectorCount;
771 UINT32 Lba32;
772 UINT32 BlockSize;
773 UINT32 ByteCount;
774 VOID *ptrBuffer;
775 EFI_STATUS Status;
776 UINT16 TimeOut;
777 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
778 UINTN SenseCounts;
779
780 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
781
782 //
783 // prepare command packet for the Write10 Packet Command.
784 //
785 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
786 Write10Packet = &Packet.Read10;
787 Lba32 = (UINT32) Lba;
788 ptrBuffer = Buffer;
789 BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize;
790
791 MaxBlock = (UINT16) (65536 / BlockSize);
792 BlocksRemaining = (UINT16) NumberOfBlocks;
793
794 Status = EFI_SUCCESS;
795 while (BlocksRemaining > 0) {
796
797 if (BlocksRemaining <= MaxBlock) {
798
799 SectorCount = BlocksRemaining;
800 } else {
801
802 SectorCount = MaxBlock;
803 }
804 //
805 // fill the Packet data structure
806 //
807 Write10Packet->opcode = WRITE_10;
808
809 //
810 // Lba0 ~ Lba3 specify the start logical block address
811 // of the data transfer.
812 // Lba0 is MSB, Lba3 is LSB
813 //
814 Write10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
815 Write10Packet->Lba2 = (UINT8) (Lba32 >> 8);
816 Write10Packet->Lba1 = (UINT8) (Lba32 >> 16);
817 Write10Packet->Lba0 = (UINT8) (Lba32 >> 24);
818
819 //
820 // TranLen0 ~ TranLen1 specify the transfer length in block unit.
821 // TranLen0 is MSB, TranLen is LSB
822 //
823 Write10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
824 Write10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
825
826 ByteCount = SectorCount * BlockSize;
827
828 TimeOut = (UINT16) (SectorCount * USBFLPTIMEOUT);
829
830 Status = USBFloppyPacketCommand (
831 UsbFloppyDevice,
832 &Packet,
833 sizeof (ATAPI_PACKET_COMMAND),
834 (VOID *) ptrBuffer,
835 ByteCount,
836 EfiUsbDataOut,
837 TimeOut
838 );
839 if (EFI_ERROR (Status)) {
840 Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts);
841 if (!EFI_ERROR (Status)) {
842 if (IsLogicalUnitCommunicationOverRun (
843 UsbFloppyDevice->SenseData,
844 SenseCounts
845 )) {
846 Lba32 = (UINT32) Lba;
847 ptrBuffer = Buffer;
848 BlocksRemaining = (UINT16) NumberOfBlocks;
849 MaxBlock = (UINT16) (MaxBlock / 4);
850 if (MaxBlock < 1) {
851 MaxBlock = 1;
852 }
853
854 continue;
855 }
856 }
857 //
858 // retry write10 command
859 //
860 Status = USBFloppyPacketCommand (
861 UsbFloppyDevice,
862 &Packet,
863 sizeof (ATAPI_PACKET_COMMAND),
864 (VOID *) ptrBuffer,
865 ByteCount,
866 EfiUsbDataOut,
867 TimeOut
868 );
869 if (EFI_ERROR (Status)) {
870 return EFI_DEVICE_ERROR;
871 }
872 }
873
874 Lba32 += SectorCount;
875 ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize;
876 BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
877 }
878
879 return Status;
880 }
881
882 EFI_STATUS
883 UsbFloppyDetectMedia (
884 IN USB_FLOPPY_DEV *UsbFloppyDevice,
885 OUT BOOLEAN *MediaChange
886 )
887 /*++
888
889 Routine Description:
890 Retrieves media information.
891
892 Arguments:
893 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
894 MediaChange - Indicates whether media was changed.
895
896 Returns:
897 EFI_DEVICE_ERROR - Hardware error
898 EFI_SUCCESS - Success
899 EFI_INVALID_PARAMETER - Parameter is error
900 --*/
901 {
902 EFI_STATUS Status;
903 EFI_STATUS FloppyStatus;
904 //
905 // the following variables are used to record previous media information
906 //
907 EFI_BLOCK_IO_MEDIA OldMediaInfo;
908 UINTN SenseCounts;
909 UINTN RetryIndex;
910 UINTN RetryTimes;
911 UINTN MaximumRetryTimes;
912 BOOLEAN NeedRetry;
913
914 //
915 // a flag used to determine whether need to perform Read Capacity command.
916 //
917 BOOLEAN NeedReadCapacity;
918
919 REQUEST_SENSE_DATA *SensePtr;
920
921 //
922 // init
923 //
924 Status = EFI_SUCCESS;
925 FloppyStatus = EFI_SUCCESS;
926 CopyMem (&OldMediaInfo, UsbFloppyDevice->BlkIo.Media, sizeof (OldMediaInfo));
927 *MediaChange = FALSE;
928 NeedReadCapacity = TRUE;
929
930 //
931 // if there is no media present,or media not changed,
932 // the request sense command will detect faster than read capacity command.
933 // read capacity command can be bypassed, thus improve performance.
934 //
935 SenseCounts = 0;
936 Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts);
937
938 if (!EFI_ERROR (Status)) {
939
940 SensePtr = UsbFloppyDevice->SenseData;
941
942 //
943 // No Media
944 //
945 if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) {
946
947 NeedReadCapacity = FALSE;
948 UsbFloppyDevice->BlkIo.Media->MediaId = 0;
949 UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
950 UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
951 } else {
952 //
953 // Media Changed
954 //
955 if (IsMediaChange (UsbFloppyDevice->SenseData, SenseCounts)) {
956 UsbFloppyDevice->BlkIo.Media->MediaId++;
957 }
958
959 //
960 // Media Write-protected
961 //
962 if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) {
963 UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE;
964 }
965
966 //
967 // Media Error
968 //
969 if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) {
970 //
971 // if media error encountered, make it look like no media present.
972 //
973 UsbFloppyDevice->BlkIo.Media->MediaId = 0;
974 UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
975 UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
976 }
977
978 }
979
980 }
981
982 if (NeedReadCapacity) {
983 //
984 // at most retry 5 times
985 //
986 MaximumRetryTimes = 5;
987 //
988 // initial retry twice
989 //
990 RetryTimes = 2;
991
992 for (RetryIndex = 0; (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); RetryIndex++) {
993 //
994 // Using different command to retrieve media capacity.
995 //
996 switch (UsbFloppyDevice->DeviceType) {
997
998 case USBCDROM:
999 Status = USBFloppyReadCapacity (UsbFloppyDevice);
1000 break;
1001
1002 case USBFLOPPY2:
1003 UsbMassStorageModeSense (UsbFloppyDevice);
1004 Status = USBFloppyReadFormatCapacity (UsbFloppyDevice);
1005 if (EFI_ERROR (Status) || !UsbFloppyDevice->BlkMedia.MediaPresent) {
1006 //
1007 // retry the ReadCapacity command
1008 //
1009 UsbFloppyDevice->DeviceType = USBFLOPPY;
1010 Status = EFI_DEVICE_ERROR;
1011 }
1012 break;
1013
1014 case USBFLOPPY:
1015 UsbMassStorageModeSense (UsbFloppyDevice);
1016 Status = USBFloppyReadCapacity (UsbFloppyDevice);
1017 if (EFI_ERROR (Status)) {
1018 //
1019 // retry the ReadFormatCapacity command
1020 //
1021 UsbFloppyDevice->DeviceType = USBFLOPPY2;
1022 }
1023 //
1024 // force the BlockSize to be 0x200.
1025 //
1026 UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200;
1027 break;
1028
1029 default:
1030 return EFI_INVALID_PARAMETER;
1031 }
1032
1033 if (!EFI_ERROR (Status)) {
1034 //
1035 // skip the loop when read capacity succeeds.
1036 //
1037 break;
1038 }
1039
1040 SenseCounts = 0;
1041
1042 FloppyStatus = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts);
1043
1044 //
1045 // If Request Sense data failed,retry.
1046 //
1047 if (EFI_ERROR (FloppyStatus)) {
1048 //
1049 // retry once more
1050 //
1051 RetryTimes++;
1052 continue;
1053 }
1054 //
1055 // No Media
1056 //
1057 if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) {
1058
1059 UsbFloppyDevice->BlkIo.Media->MediaId = 0;
1060 UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
1061 UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
1062 break;
1063 }
1064
1065 if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) {
1066 //
1067 // if media error encountered, make it look like no media present.
1068 //
1069 UsbFloppyDevice->BlkIo.Media->MediaId = 0;
1070 UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
1071 UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
1072 break;
1073 }
1074
1075 if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) {
1076 UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE;
1077 continue;
1078 }
1079
1080 if (!IsDriveReady (UsbFloppyDevice->SenseData, SenseCounts, &NeedRetry)) {
1081
1082 //
1083 // Drive not ready: if NeedRetry, then retry once more;
1084 // else return error
1085 //
1086 if (NeedRetry) {
1087 //
1088 // Stall 0.1 second to wait for drive becoming ready
1089 //
1090 gBS->Stall (100 * STALL_1_MILLI_SECOND);
1091 //
1092 // reset retry variable to zero,
1093 // to make it retry for "drive in progress of becoming ready".
1094 //
1095 RetryIndex = 0;
1096 continue;
1097 } else {
1098 return EFI_DEVICE_ERROR;
1099 }
1100 }
1101 //
1102 // if read capacity fail not for above reasons, retry once more
1103 //
1104 RetryTimes++;
1105
1106 }
1107 //
1108 // ENDFOR
1109 //
1110
1111 //
1112 // tell whether the readcapacity process is successful or not
1113 // ("Status" variable record the latest status returned
1114 // by ReadCapacity AND "FloppyStatus" record the latest status
1115 // returned by RequestSense)
1116 //
1117 if (EFI_ERROR (Status) && EFI_ERROR (FloppyStatus)) {
1118 return EFI_DEVICE_ERROR;
1119 }
1120
1121 }
1122
1123 if (UsbFloppyDevice->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {
1124
1125 if (UsbFloppyDevice->BlkIo.Media->MediaPresent) {
1126 UsbFloppyDevice->BlkIo.Media->MediaId = 1;
1127 }
1128
1129 *MediaChange = TRUE;
1130 }
1131
1132 if (UsbFloppyDevice->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {
1133 *MediaChange = TRUE;
1134 UsbFloppyDevice->BlkIo.Media->MediaId += 1;
1135 }
1136
1137 if (UsbFloppyDevice->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {
1138 *MediaChange = TRUE;
1139 UsbFloppyDevice->BlkIo.Media->MediaId += 1;
1140 }
1141
1142 if (UsbFloppyDevice->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {
1143 *MediaChange = TRUE;
1144 UsbFloppyDevice->BlkIo.Media->MediaId += 1;
1145 }
1146
1147 if (UsbFloppyDevice->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {
1148 *MediaChange = TRUE;
1149 }
1150
1151 return EFI_SUCCESS;
1152 }
1153
1154
1155
1156 EFI_STATUS
1157 UsbFloppyModeSense5APage5 (
1158 IN USB_FLOPPY_DEV *UsbFloppyDevice
1159 )
1160 /*++
1161
1162 Routine Description:
1163 Retrieves media capacity information via sending Read Format
1164 Capacity Packet Command.
1165
1166 Arguments:
1167 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
1168
1169 Returns:
1170 EFI_DEVICE_ERROR - Hardware error
1171 EFI_SUCCESS - Success
1172
1173 --*/
1174 {
1175 //
1176 // status returned by Read Capacity Packet Command
1177 //
1178 EFI_STATUS Status;
1179 ATAPI_PACKET_COMMAND Packet;
1180 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
1181 UFI_MODE_PARAMETER_PAGE_5 ModePage5;
1182 EFI_LBA LastBlock;
1183 UINT32 SectorsPerTrack;
1184 UINT32 NumberOfCylinders;
1185 UINT32 NumberOfHeads;
1186 UINT32 DataBytesPerSector;
1187
1188 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
1189
1190 ZeroMem (&ModePage5, sizeof (UFI_MODE_PARAMETER_PAGE_5));
1191
1192 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
1193 Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A;
1194 //
1195 // Flexible Disk Page
1196 //
1197 Packet.ModeSenseUFI.page_code = 5;
1198 //
1199 // current values
1200 //
1201 Packet.ModeSenseUFI.page_control = 0;
1202 Packet.ModeSenseUFI.parameter_list_length_hi = 0;
1203 Packet.ModeSenseUFI.parameter_list_length_lo = sizeof (UFI_MODE_PARAMETER_PAGE_5);
1204 Status = USBFloppyPacketCommand (
1205 UsbFloppyDevice,
1206 &Packet,
1207 sizeof (ATAPI_PACKET_COMMAND),
1208 (VOID *) &ModePage5,
1209 sizeof (UFI_MODE_PARAMETER_PAGE_5),
1210 EfiUsbDataIn,
1211 USBFLPTIMEOUT
1212 );
1213
1214 if (EFI_ERROR (Status)) {
1215 return EFI_DEVICE_ERROR;
1216 }
1217
1218 NumberOfHeads = ModePage5.flex_disk_page.number_of_heads;
1219 SectorsPerTrack = ModePage5.flex_disk_page.sectors_per_track;
1220 NumberOfCylinders = ModePage5.flex_disk_page.number_of_cylinders_msb << 8 |
1221 ModePage5.flex_disk_page.number_of_cylinders_lsb;
1222
1223 LastBlock = SectorsPerTrack * NumberOfHeads * NumberOfCylinders;
1224 DataBytesPerSector = ModePage5.flex_disk_page.databytes_per_sector_msb << 8 |
1225 ModePage5.flex_disk_page.databytes_per_sector_lsb;
1226
1227 UsbFloppyDevice->BlkIo.Media->LastBlock = LastBlock;
1228
1229 UsbFloppyDevice->BlkIo.Media->LastBlock--;
1230
1231 UsbFloppyDevice->BlkIo.Media->BlockSize = DataBytesPerSector;
1232
1233 UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE;
1234
1235 UsbFloppyDevice->BlkIo.Media->ReadOnly =
1236 ModePage5.mode_param_header.write_protected;
1237
1238 return EFI_SUCCESS;
1239
1240 }
1241
1242 EFI_STATUS
1243 UsbFloppyModeSense5APage1C (
1244 IN USB_FLOPPY_DEV *UsbFloppyDevice
1245 )
1246 /*++
1247
1248 Routine Description:
1249 Retrieves media capacity information via sending Read Format
1250 Capacity Packet Command.
1251
1252 Arguments:
1253 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
1254
1255 Returns:
1256 EFI_DEVICE_ERROR - Hardware error
1257 EFI_SUCCESS - Success
1258
1259 --*/
1260 {
1261 //
1262 // status returned by Read Capacity Packet Command
1263 //
1264 EFI_STATUS Status;
1265 ATAPI_PACKET_COMMAND Packet;
1266 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
1267 UFI_MODE_PARAMETER_PAGE_1C ModePage1C;
1268
1269 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
1270
1271 ZeroMem (&ModePage1C, sizeof (UFI_MODE_PARAMETER_PAGE_1C));
1272
1273 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
1274 Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A;
1275 //
1276 // Flexible Disk Page
1277 //
1278 Packet.ModeSenseUFI.page_code = 0x1C;
1279 //
1280 // current values
1281 //
1282 Packet.ModeSenseUFI.page_control = 0;
1283 Packet.ModeSenseUFI.parameter_list_length_hi = 0;
1284 Packet.ModeSenseUFI.parameter_list_length_lo = sizeof (UFI_MODE_PARAMETER_PAGE_1C);
1285 Status = USBFloppyPacketCommand (
1286 UsbFloppyDevice,
1287 &Packet,
1288 sizeof (ATAPI_PACKET_COMMAND),
1289 (VOID *) &ModePage1C,
1290 sizeof (UFI_MODE_PARAMETER_PAGE_1C),
1291 EfiUsbDataIn,
1292 USBFLPTIMEOUT
1293 );
1294
1295 if (EFI_ERROR (Status)) {
1296 return EFI_DEVICE_ERROR;
1297 }
1298
1299 UsbFloppyDevice->BlkIo.Media->ReadOnly = ModePage1C.mode_param_header.write_protected;
1300
1301 return EFI_SUCCESS;
1302
1303 }
1304
1305 EFI_STATUS
1306 UsbMassStorageModeSense (
1307 IN USB_FLOPPY_DEV *UsbFloppyDevice
1308 )
1309 {
1310 if (UsbFloppyDevice->AtapiProtocol->CommandProtocol == EFI_USB_SUBCLASS_SCSI) {
1311 return UsbSCSIModeSense1APage3F (UsbFloppyDevice);
1312 } else {
1313 return UsbFloppyModeSense5APage3F (UsbFloppyDevice);
1314 }
1315 }
1316
1317 EFI_STATUS
1318 UsbFloppyModeSense5APage3F (
1319 IN USB_FLOPPY_DEV *UsbFloppyDevice
1320 )
1321 /*++
1322
1323 Routine Description:
1324 Retrieves mode sense information via sending Mode Sense
1325 Packet Command.
1326
1327 Arguments:
1328 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
1329
1330 Returns:
1331 EFI_DEVICE_ERROR - Hardware error
1332 EFI_SUCCESS - Success
1333
1334 --*/
1335 {
1336 //
1337 // status returned by Read Capacity Packet Command
1338 //
1339 EFI_STATUS Status;
1340 ATAPI_PACKET_COMMAND Packet;
1341 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
1342 UFI_MODE_PARAMETER_HEADER Header;
1343 UINT32 Size;
1344
1345 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
1346
1347 Size = sizeof (UFI_MODE_PARAMETER_HEADER);
1348
1349 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
1350 Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A;
1351 Packet.ModeSenseUFI.page_code = 0x3F;
1352 Packet.ModeSenseUFI.page_control = 0;
1353 Packet.ModeSenseUFI.parameter_list_length_hi = 0;
1354 Packet.ModeSenseUFI.parameter_list_length_lo = (UINT8) Size;
1355 Status = USBFloppyPacketCommand (
1356 UsbFloppyDevice,
1357 &Packet,
1358 sizeof (ATAPI_PACKET_COMMAND),
1359 &Header,
1360 Size,
1361 EfiUsbDataIn,
1362 USBFLPTIMEOUT
1363 );
1364
1365 if (EFI_ERROR (Status)) {
1366 return EFI_DEVICE_ERROR;
1367 }
1368
1369 UsbFloppyDevice->BlkIo.Media->ReadOnly = Header.write_protected;
1370
1371 return EFI_SUCCESS;
1372
1373 }
1374
1375 EFI_STATUS
1376 UsbSCSIModeSense1APage3F (
1377 IN USB_FLOPPY_DEV *UsbFloppyDevice
1378 )
1379 /*++
1380
1381 Routine Description:
1382 Retrieves mode sense information via sending Mode Sense
1383 Packet Command.
1384
1385 Arguments:
1386 UsbFloppyDevice - The USB_FLOPPY_DEV instance.
1387
1388 Returns:
1389 EFI_DEVICE_ERROR - Hardware error
1390 EFI_SUCCESS - Success
1391
1392 --*/
1393 {
1394 //
1395 // status returned by Read Capacity Packet Command
1396 //
1397 EFI_STATUS Status;
1398 ATAPI_PACKET_COMMAND Packet;
1399 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
1400 SCSI_MODE_PARAMETER_HEADER6 Header;
1401 UINT32 Size;
1402
1403 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
1404
1405 Size = sizeof (SCSI_MODE_PARAMETER_HEADER6);
1406
1407 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
1408 Packet.ModeSenseSCSI.opcode = SCSI_MODE_SENSE1A;
1409 Packet.ModeSenseSCSI.page_code = 0x3F;
1410 Packet.ModeSenseSCSI.page_control = 0;
1411 Packet.ModeSenseSCSI.allocation_length = (UINT8) Size;
1412 Status = USBFloppyPacketCommand (
1413 UsbFloppyDevice,
1414 &Packet,
1415 sizeof (MODE_SENSE_CMD_SCSI),
1416 &Header,
1417 Size,
1418 EfiUsbDataIn,
1419 USBFLPTIMEOUT
1420 );
1421
1422 if (EFI_ERROR (Status)) {
1423 return EFI_DEVICE_ERROR;
1424 }
1425
1426 UsbFloppyDevice->BlkIo.Media->ReadOnly = Header.write_protected;
1427 return EFI_SUCCESS;
1428
1429 }
1430
1431 /*++
1432
1433 The following functions are a set of helper functions,
1434 which are used to parse sense key returned by the device.
1435
1436 --*/
1437 BOOLEAN
1438 IsNoMedia (
1439 IN REQUEST_SENSE_DATA *SenseData,
1440 IN UINTN SenseCounts
1441 )
1442 {
1443 REQUEST_SENSE_DATA *SensePtr;
1444 UINTN Index;
1445 BOOLEAN NoMedia;
1446
1447 NoMedia = FALSE;
1448
1449 SensePtr = SenseData;
1450
1451 for (Index = 0; Index < SenseCounts; Index++) {
1452
1453 if ((SensePtr->sense_key == SK_NOT_READY) &&
1454 (SensePtr->addnl_sense_code == ASC_NO_MEDIA)) {
1455
1456 NoMedia = TRUE;
1457 }
1458
1459 SensePtr++;
1460 }
1461
1462 return NoMedia;
1463 }
1464
1465
1466 BOOLEAN
1467 IsMediaError (
1468 IN REQUEST_SENSE_DATA *SenseData,
1469 IN UINTN SenseCounts
1470 )
1471 {
1472 REQUEST_SENSE_DATA *SensePtr;
1473 UINTN Index;
1474 BOOLEAN IsError;
1475
1476 IsError = FALSE;
1477 SensePtr = SenseData;
1478
1479 for (Index = 0; Index < SenseCounts; Index++) {
1480
1481 switch (SensePtr->sense_key) {
1482
1483 //
1484 // Medium error case
1485 //
1486 case SK_MEDIUM_ERROR:
1487 switch (SensePtr->addnl_sense_code) {
1488
1489 case ASC_MEDIA_ERR1:
1490 case ASC_MEDIA_ERR2:
1491 case ASC_MEDIA_ERR3:
1492 case ASC_MEDIA_ERR4:
1493 IsError = TRUE;
1494 break;
1495
1496 default:
1497 break;
1498 }
1499
1500 break;
1501
1502 //
1503 // Medium upside-down case
1504 //
1505 case SK_NOT_READY:
1506 switch (SensePtr->addnl_sense_code) {
1507 case ASC_MEDIA_UPSIDE_DOWN:
1508 IsError = TRUE;
1509 break;
1510
1511 default:
1512 break;
1513 }
1514 break;
1515
1516 default:
1517 break;
1518 }
1519
1520 SensePtr++;
1521 }
1522
1523 return IsError;
1524 }
1525
1526 BOOLEAN
1527 IsMediaChange (
1528 IN REQUEST_SENSE_DATA *SenseData,
1529 IN UINTN SenseCounts
1530 )
1531 {
1532 REQUEST_SENSE_DATA *SensePtr;
1533 UINTN Index;
1534 BOOLEAN MediaChanged;
1535
1536 MediaChanged = FALSE;
1537 SensePtr = SenseData;
1538
1539 for (Index = 0; Index < SenseCounts; Index++) {
1540
1541 if ((SensePtr->sense_key == SK_UNIT_ATTENTION) &&
1542 (SensePtr->addnl_sense_code == ASC_MEDIA_CHANGE)) {
1543
1544 MediaChanged = TRUE;
1545 }
1546
1547 SensePtr++;
1548 }
1549
1550 return MediaChanged;
1551 }
1552
1553 BOOLEAN
1554 IsDriveReady (
1555 IN REQUEST_SENSE_DATA *SenseData,
1556 IN UINTN SenseCounts,
1557 OUT BOOLEAN *NeedRetry
1558 )
1559 {
1560 REQUEST_SENSE_DATA *SensePtr;
1561 UINTN Index;
1562 BOOLEAN IsReady;
1563
1564 IsReady = TRUE;
1565 *NeedRetry = FALSE;
1566 SensePtr = SenseData;
1567
1568 for (Index = 0; Index < SenseCounts; Index++) {
1569
1570 if ((SensePtr->sense_key == SK_NOT_READY) &&
1571 (SensePtr->addnl_sense_code == ASC_NOT_READY)) {
1572
1573 switch (SensePtr->addnl_sense_code_qualifier) {
1574
1575 case ASCQ_IN_PROGRESS:
1576 case ASCQ_DEVICE_BUSY:
1577 IsReady = FALSE;
1578 *NeedRetry = TRUE;
1579 break;
1580
1581 default:
1582 //
1583 // Drive is in error condition,
1584 // no need to retry.
1585 //
1586 IsReady = FALSE;
1587 *NeedRetry = FALSE;
1588 break;
1589 }
1590 }
1591
1592 SensePtr++;
1593 }
1594
1595 return IsReady;
1596 }
1597
1598 BOOLEAN
1599 IsMediaWriteProtected (
1600 IN REQUEST_SENSE_DATA *SenseData,
1601 IN UINTN SenseCounts
1602 )
1603 {
1604 REQUEST_SENSE_DATA *SensePtr;
1605 UINTN Index;
1606 BOOLEAN IsWriteProtected;
1607
1608 IsWriteProtected = FALSE;
1609 SensePtr = SenseData;
1610
1611 for (Index = 0; Index < SenseCounts; Index++) {
1612 //
1613 // catch media write-protected condition.
1614 //
1615 if ((SensePtr->sense_key == SK_DATA_PROTECT) &&
1616 (SensePtr->addnl_sense_code == ASC_WRITE_PROTECTED)) {
1617
1618 IsWriteProtected = TRUE;
1619 }
1620
1621 SensePtr++;
1622 }
1623
1624 return IsWriteProtected;
1625 }
1626
1627 BOOLEAN
1628 IsLogicalUnitCommunicationOverRun (
1629 IN REQUEST_SENSE_DATA *SenseData,
1630 IN UINTN SenseCounts
1631 )
1632 {
1633 REQUEST_SENSE_DATA *SensePtr;
1634 UINTN Index;
1635 BOOLEAN IsOverRun;
1636
1637 IsOverRun = FALSE;
1638 SensePtr = SenseData;
1639
1640 for (Index = 0; Index < SenseCounts; Index++) {
1641
1642 if ((SensePtr->sense_key == SK_NOT_READY) &&
1643 (SensePtr->addnl_sense_code == ASC_LOGICAL_UNIT_STATUS) &&
1644 (SensePtr->addnl_sense_code_qualifier == ASCQ_LOGICAL_UNIT_OVERRUN)) {
1645 IsOverRun = TRUE;
1646 }
1647
1648 SensePtr++;
1649 }
1650
1651 return IsOverRun;
1652 }