]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c
For USB mass storage, READ_FORMAT_CAPACITIES command returns wrong value for USB2...
[mirror_edk2.git] / EdkModulePkg / Bus / Usb / UsbMassStorage / Dxe / UsbMassStorageHelper.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 UsbMassStorageHelper.c\r
15 \r
16Abstract:\r
17\r
18 Helper functions for USB Mass Storage Driver\r
19\r
20Revision History\r
21\r
22--*/\r
23\r
24#include "UsbMassStorageHelper.h"\r
25\r
26STATIC\r
27BOOLEAN\r
28IsNoMedia (\r
29 IN REQUEST_SENSE_DATA *SenseData,\r
30 IN UINTN SenseCounts\r
31 );\r
32\r
33STATIC\r
34BOOLEAN\r
35IsMediaError (\r
36 IN REQUEST_SENSE_DATA *SenseData,\r
37 IN UINTN SenseCounts\r
38 );\r
39\r
40STATIC\r
41BOOLEAN\r
42IsMediaChange (\r
43 IN REQUEST_SENSE_DATA *SenseData,\r
44 IN UINTN SenseCounts\r
45 );\r
46\r
47STATIC\r
48BOOLEAN\r
49IsDriveReady (\r
50 IN REQUEST_SENSE_DATA *SenseData,\r
51 IN UINTN SenseCounts,\r
52 OUT BOOLEAN *NeedRetry\r
53 );\r
54\r
55STATIC\r
56BOOLEAN\r
57IsMediaWriteProtected (\r
58 IN REQUEST_SENSE_DATA *SenseData,\r
59 IN UINTN SenseCounts\r
60 );\r
61\r
62STATIC\r
63BOOLEAN\r
64IsLogicalUnitCommunicationOverRun (\r
65 IN REQUEST_SENSE_DATA *SenseData,\r
66 IN UINTN SenseCounts\r
67 );\r
68\r
69EFI_STATUS\r
70USBFloppyPacketCommand (\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
118EFI_STATUS\r
119USBFloppyIdentify (\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
215EFI_STATUS\r
216USBFloppyInquiry (\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
273EFI_STATUS\r
274USBFloppyRead10 (\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
416EFI_STATUS\r
417USBFloppyReadCapacity (\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
479EFI_STATUS\r
480USBFloppyReadFormatCapacity (\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
560EFI_STATUS\r
561UsbFloppyRequestSense (\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
682EFI_STATUS\r
683UsbFloppyTestUnitReady (\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
738EFI_STATUS\r
739USBFloppyWrite10 (\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
882EFI_STATUS\r
883UsbFloppyDetectMedia (\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
878ddf1f 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
ea78388e 1002 case USBFLOPPY2:\r
878ddf1f 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
ea78388e 1009 UsbFloppyDevice->DeviceType = USBFLOPPY;\r
878ddf1f 1010 Status = EFI_DEVICE_ERROR;\r
1011 }\r
1012 break;\r
1013\r
ea78388e 1014 case USBFLOPPY:\r
878ddf1f 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
ea78388e 1021 UsbFloppyDevice->DeviceType = USBFLOPPY2;\r
878ddf1f 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
1156EFI_STATUS\r
1157UsbFloppyModeSense5APage5 (\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
1242EFI_STATUS\r
1243UsbFloppyModeSense5APage1C (\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
1305EFI_STATUS\r
1306UsbMassStorageModeSense (\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
1317EFI_STATUS\r
1318UsbFloppyModeSense5APage3F (\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
1375EFI_STATUS\r
1376UsbSCSIModeSense1APage3F (\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
1437BOOLEAN\r
1438IsNoMedia (\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
1466BOOLEAN\r
1467IsMediaError (\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
1526BOOLEAN\r
1527IsMediaChange (\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
1553BOOLEAN\r
1554IsDriveReady (\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
1598BOOLEAN\r
1599IsMediaWriteProtected (\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
1627BOOLEAN\r
1628IsLogicalUnitCommunicationOverRun (\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