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