]>
Commit | Line | Data |
---|---|---|
ead42efc | 1 | /** @file\r |
630d580d | 2 | This file contains all helper functions on the ATAPI command \r |
3 | \r | |
180a5a35 HT |
4 | Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r |
5 | This program and the accompanying materials \r | |
ead42efc | 6 | are licensed and made available under the terms and conditions of the BSD License \r |
7 | which accompanies this distribution. The full text of the license may be found at \r | |
8 | http://opensource.org/licenses/bsd-license.php \r | |
9 | \r | |
10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r | |
11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r | |
12 | \r | |
13 | **/\r | |
14 | \r | |
03417d8d | 15 | #include "IdeBus.h"\r |
ead42efc | 16 | \r |
17 | /**\r | |
18 | This function is used to get the current status of the media residing\r | |
19 | in the LS-120 drive or ZIP drive. The media status is returned in the \r | |
20 | Error Status.\r | |
21 | \r | |
630d580d | 22 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
23 | to record all the information of the IDE device.\r | |
ead42efc | 24 | \r |
630d580d | 25 | @retval EFI_SUCCESS The media status is achieved successfully and the media\r |
26 | can be read/written.\r | |
27 | @retval EFI_DEVICE_ERROR Get Media Status Command is failed.\r | |
28 | @retval EFI_NO_MEDIA There is no media in the drive.\r | |
29 | @retval EFI_WRITE_PROTECTED The media is writing protected.\r | |
ead42efc | 30 | \r |
630d580d | 31 | @note This function must be called after the LS120EnableMediaStatus() \r |
32 | with second parameter set to TRUE \r | |
33 | (means enable media status notification) is called.\r | |
ead42efc | 34 | **/\r |
ead42efc | 35 | EFI_STATUS\r |
36 | LS120GetMediaStatus (\r | |
37 | IN IDE_BLK_IO_DEV *IdeDev\r | |
38 | )\r | |
39 | {\r | |
40 | UINT8 DeviceSelect;\r | |
41 | UINT8 StatusValue;\r | |
42 | EFI_STATUS EfiStatus;\r | |
43 | //\r | |
44 | // Poll Alternate Register for BSY clear within timeout.\r | |
45 | //\r | |
46 | EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r | |
47 | if (EFI_ERROR (EfiStatus)) {\r | |
48 | return EFI_DEVICE_ERROR;\r | |
49 | }\r | |
50 | \r | |
51 | //\r | |
52 | // Select device via Device/Head Register.\r | |
53 | //\r | |
54 | DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);\r | |
55 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r | |
56 | \r | |
57 | //\r | |
58 | // Poll Alternate Register for DRDY set within timeout.\r | |
59 | // After device is selected, DRDY set indicates the device is ready to\r | |
60 | // accept command.\r | |
61 | //\r | |
62 | EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT);\r | |
63 | if (EFI_ERROR (EfiStatus)) {\r | |
64 | return EFI_DEVICE_ERROR;\r | |
65 | }\r | |
66 | \r | |
67 | //\r | |
68 | // Get Media Status Command is sent\r | |
69 | //\r | |
70 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA);\r | |
71 | \r | |
72 | //\r | |
73 | // BSY bit will clear after command is complete.\r | |
74 | //\r | |
75 | EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r | |
76 | if (EFI_ERROR (EfiStatus)) {\r | |
77 | return EFI_DEVICE_ERROR;\r | |
78 | }\r | |
79 | \r | |
80 | //\r | |
81 | // the media status is returned by the command in the ERROR register\r | |
82 | //\r | |
83 | StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r | |
84 | \r | |
97404058 | 85 | if ((StatusValue & BIT1) != 0) {\r |
ead42efc | 86 | return EFI_NO_MEDIA;\r |
87 | }\r | |
88 | \r | |
97404058 | 89 | if ((StatusValue & BIT6) != 0) {\r |
ead42efc | 90 | return EFI_WRITE_PROTECTED;\r |
91 | } else {\r | |
92 | return EFI_SUCCESS;\r | |
93 | }\r | |
94 | }\r | |
ead42efc | 95 | /**\r |
96 | This function is used to send Enable Media Status Notification Command\r | |
97 | or Disable Media Status Notification Command.\r | |
98 | \r | |
630d580d | 99 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
100 | to record all the information of the IDE device.\r | |
ead42efc | 101 | \r |
630d580d | 102 | @param Enable a flag that indicates whether enable or disable media\r |
103 | status notification.\r | |
104 | @retval EFI_SUCCESS If command completes successfully.\r | |
105 | @retval EFI_DEVICE_ERROR If command failed.\r | |
ead42efc | 106 | **/\r |
ead42efc | 107 | EFI_STATUS\r |
108 | LS120EnableMediaStatus (\r | |
109 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
110 | IN BOOLEAN Enable\r | |
111 | )\r | |
112 | {\r | |
113 | UINT8 DeviceSelect;\r | |
114 | EFI_STATUS Status;\r | |
115 | \r | |
116 | //\r | |
117 | // Poll Alternate Register for BSY clear within timeout.\r | |
118 | //\r | |
119 | Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r | |
120 | if (EFI_ERROR (Status)) {\r | |
121 | return EFI_DEVICE_ERROR;\r | |
122 | }\r | |
123 | \r | |
124 | //\r | |
125 | // Select device via Device/Head Register.\r | |
126 | //\r | |
127 | DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);\r | |
128 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r | |
129 | \r | |
130 | //\r | |
131 | // Poll Alternate Register for DRDY set within timeout.\r | |
132 | // After device is selected, DRDY set indicates the device is ready to\r | |
133 | // accept command.\r | |
134 | //\r | |
135 | Status = DRDYReady2 (IdeDev, ATATIMEOUT);\r | |
136 | if (EFI_ERROR (Status)) {\r | |
137 | return EFI_DEVICE_ERROR;\r | |
138 | }\r | |
139 | \r | |
140 | if (Enable) {\r | |
141 | //\r | |
142 | // 0x95: Enable media status notification\r | |
143 | //\r | |
144 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95);\r | |
145 | } else {\r | |
146 | //\r | |
147 | // 0x31: Disable media status notification\r | |
148 | //\r | |
149 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31);\r | |
150 | }\r | |
151 | //\r | |
152 | // Set Feature Command is sent\r | |
153 | //\r | |
154 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF);\r | |
155 | \r | |
156 | //\r | |
157 | // BSY bit will clear after command is complete.\r | |
158 | //\r | |
159 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r | |
160 | if (EFI_ERROR (Status)) {\r | |
161 | return EFI_DEVICE_ERROR;\r | |
162 | }\r | |
163 | \r | |
164 | return EFI_SUCCESS;\r | |
165 | }\r | |
ead42efc | 166 | /**\r |
630d580d | 167 | This function reads the pending data in the device.\r |
ead42efc | 168 | \r |
630d580d | 169 | @param IdeDev Indicates the calling context.\r |
ead42efc | 170 | \r |
630d580d | 171 | @retval EFI_SUCCESS Successfully read.\r |
172 | @retval EFI_NOT_READY The BSY is set avoiding reading.\r | |
ead42efc | 173 | \r |
630d580d | 174 | **/\r |
175 | EFI_STATUS\r | |
176 | AtapiReadPendingData (\r | |
177 | IN IDE_BLK_IO_DEV *IdeDev\r | |
178 | )\r | |
179 | {\r | |
180 | UINT8 AltRegister;\r | |
181 | UINT16 TempWordBuffer;\r | |
ead42efc | 182 | \r |
630d580d | 183 | AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r |
184 | if ((AltRegister & ATA_STSREG_BSY) == ATA_STSREG_BSY) {\r | |
185 | return EFI_NOT_READY;\r | |
186 | }\r | |
187 | if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r | |
188 | TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r | |
189 | while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r | |
190 | IDEReadPortWMultiple (\r | |
191 | IdeDev->PciIo,\r | |
192 | IdeDev->IoPort->Data, \r | |
193 | 1, \r | |
194 | &TempWordBuffer\r | |
195 | );\r | |
196 | TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r | |
197 | }\r | |
198 | }\r | |
199 | return EFI_SUCCESS;\r | |
200 | }\r | |
ead42efc | 201 | \r |
630d580d | 202 | /**\r |
203 | This function is called by either AtapiPacketCommandIn() or AtapiPacketCommandOut(). \r | |
204 | It is used to transfer data between host and device. The data direction is specified\r | |
205 | by the fourth parameter.\r | |
206 | \r | |
207 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r | |
208 | all the information of the IDE device.\r | |
209 | @param Buffer buffer contained data transferred between host and device.\r | |
210 | @param ByteCount data size in byte unit of the buffer.\r | |
211 | @param Read flag used to determine the data transfer direction.\r | |
212 | Read equals 1, means data transferred from device to host;\r | |
213 | Read equals 0, means data transferred from host to device.\r | |
214 | @param TimeOut timeout value for wait DRQ ready before each data stream's transfer.\r | |
215 | \r | |
216 | @retval EFI_SUCCESS data is transferred successfully.\r | |
217 | @retval EFI_DEVICE_ERROR the device failed to transfer data.\r | |
ead42efc | 218 | **/\r |
219 | EFI_STATUS\r | |
630d580d | 220 | PioReadWriteData (\r |
221 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
222 | IN UINT16 *Buffer,\r | |
223 | IN UINT32 ByteCount,\r | |
224 | IN BOOLEAN Read,\r | |
225 | IN UINTN TimeOut\r | |
ead42efc | 226 | )\r |
227 | {\r | |
ead42efc | 228 | //\r |
630d580d | 229 | // required transfer data in word unit.\r |
ead42efc | 230 | //\r |
630d580d | 231 | UINT32 RequiredWordCount;\r |
ead42efc | 232 | \r |
ead42efc | 233 | //\r |
630d580d | 234 | // actual transfer data in word unit.\r |
ead42efc | 235 | //\r |
630d580d | 236 | UINT32 ActualWordCount;\r |
237 | UINT32 WordCount;\r | |
238 | EFI_STATUS Status;\r | |
239 | UINT16 *PtrBuffer;\r | |
ead42efc | 240 | \r |
241 | //\r | |
630d580d | 242 | // No data transfer is premitted.\r |
ead42efc | 243 | //\r |
630d580d | 244 | if (ByteCount == 0) {\r |
245 | return EFI_SUCCESS;\r | |
ead42efc | 246 | }\r |
247 | //\r | |
630d580d | 248 | // for performance, we assert the ByteCount is an even number\r |
249 | // which is actually a resonable assumption \r | |
250 | ASSERT((ByteCount%2) == 0);\r | |
251 | \r | |
252 | PtrBuffer = Buffer;\r | |
253 | RequiredWordCount = ByteCount / 2;\r | |
ead42efc | 254 | //\r |
630d580d | 255 | // ActuralWordCount means the word count of data really transferred.\r |
ead42efc | 256 | //\r |
630d580d | 257 | ActualWordCount = 0;\r |
ead42efc | 258 | \r |
630d580d | 259 | while (ActualWordCount < RequiredWordCount) {\r |
260 | \r | |
ead42efc | 261 | //\r |
630d580d | 262 | // before each data transfer stream, the host should poll DRQ bit ready,\r |
263 | // to see whether indicates device is ready to transfer data.\r | |
ead42efc | 264 | //\r |
630d580d | 265 | Status = DRQReady2 (IdeDev, TimeOut);\r |
266 | if (EFI_ERROR (Status)) {\r | |
267 | return CheckErrorStatus (IdeDev);\r | |
268 | }\r | |
269 | \r | |
ead42efc | 270 | //\r |
630d580d | 271 | // read Status Register will clear interrupt\r |
ead42efc | 272 | //\r |
630d580d | 273 | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r |
ead42efc | 274 | \r |
ead42efc | 275 | //\r |
630d580d | 276 | // get current data transfer size from Cylinder Registers.\r |
ead42efc | 277 | //\r |
630d580d | 278 | WordCount = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8;\r |
279 | WordCount = WordCount | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r | |
280 | WordCount = WordCount & 0xffff;\r | |
281 | WordCount /= 2;\r | |
ead42efc | 282 | \r |
630d580d | 283 | WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount));\r |
ead42efc | 284 | \r |
630d580d | 285 | if (Read) {\r |
286 | IDEReadPortWMultiple (\r | |
287 | IdeDev->PciIo,\r | |
288 | IdeDev->IoPort->Data,\r | |
289 | WordCount,\r | |
290 | PtrBuffer\r | |
291 | );\r | |
292 | } else {\r | |
293 | IDEWritePortWMultiple (\r | |
294 | IdeDev->PciIo,\r | |
295 | IdeDev->IoPort->Data,\r | |
296 | WordCount,\r | |
297 | PtrBuffer\r | |
298 | );\r | |
299 | }\r | |
ead42efc | 300 | \r |
630d580d | 301 | PtrBuffer += WordCount;\r |
302 | ActualWordCount += WordCount;\r | |
303 | }\r | |
ead42efc | 304 | \r |
630d580d | 305 | if (Read) {\r |
ead42efc | 306 | //\r |
630d580d | 307 | // In the case where the drive wants to send more data than we need to read,\r |
308 | // the DRQ bit will be set and cause delays from DRQClear2().\r | |
309 | // We need to read data from the drive until it clears DRQ so we can move on.\r | |
ead42efc | 310 | //\r |
630d580d | 311 | AtapiReadPendingData (IdeDev);\r |
ead42efc | 312 | }\r |
313 | \r | |
314 | //\r | |
630d580d | 315 | // After data transfer is completed, normally, DRQ bit should clear.\r |
ead42efc | 316 | //\r |
630d580d | 317 | Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r |
318 | if (EFI_ERROR (Status)) {\r | |
319 | return EFI_DEVICE_ERROR;\r | |
ead42efc | 320 | }\r |
321 | \r | |
630d580d | 322 | //\r |
323 | // read status register to check whether error happens.\r | |
324 | //\r | |
325 | return CheckErrorStatus (IdeDev);\r | |
ead42efc | 326 | }\r |
327 | \r | |
328 | /**\r | |
630d580d | 329 | This function is used to send out ATAPI commands conforms to the Packet Command \r |
330 | with PIO Data In Protocol.\r | |
331 | \r | |
332 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r | |
333 | to record all the information of the IDE device.\r | |
334 | @param Packet pointer pointing to ATAPI_PACKET_COMMAND data structure\r | |
335 | which contains the contents of the command. \r | |
336 | @param Buffer buffer contained data transferred from device to host.\r | |
337 | @param ByteCount data size in byte unit of the buffer.\r | |
338 | @param TimeOut this parameter is used to specify the timeout value for the \r | |
339 | PioReadWriteData() function. \r | |
340 | \r | |
341 | @retval EFI_SUCCESS send out the ATAPI packet command successfully\r | |
342 | and device sends data successfully.\r | |
343 | @retval EFI_DEVICE_ERROR the device failed to send data.\r | |
ead42efc | 344 | \r |
345 | **/\r | |
346 | EFI_STATUS\r | |
347 | AtapiPacketCommandIn (\r | |
348 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
349 | IN ATAPI_PACKET_COMMAND *Packet,\r | |
350 | IN UINT16 *Buffer,\r | |
351 | IN UINT32 ByteCount,\r | |
352 | IN UINTN TimeOut\r | |
353 | )\r | |
354 | {\r | |
355 | UINT16 *CommandIndex;\r | |
356 | EFI_STATUS Status;\r | |
357 | UINT32 Count;\r | |
358 | \r | |
359 | //\r | |
360 | // Set all the command parameters by fill related registers.\r | |
361 | // Before write to all the following registers, BSY and DRQ must be 0.\r | |
362 | //\r | |
363 | Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r | |
364 | if (EFI_ERROR (Status)) {\r | |
365 | return Status;\r | |
366 | }\r | |
367 | \r | |
368 | //\r | |
369 | // Select device via Device/Head Register.\r | |
370 | //\r | |
371 | IDEWritePortB (\r | |
372 | IdeDev->PciIo,\r | |
373 | IdeDev->IoPort->Head,\r | |
1e23bd8d | 374 | (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r |
ead42efc | 375 | );\r |
376 | \r | |
377 | //\r | |
378 | // No OVL; No DMA\r | |
379 | //\r | |
380 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);\r | |
381 | \r | |
382 | //\r | |
1e23bd8d | 383 | // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r |
ead42efc | 384 | // determine how many data should be transferred.\r |
385 | //\r | |
386 | IDEWritePortB (\r | |
387 | IdeDev->PciIo,\r | |
388 | IdeDev->IoPort->CylinderLsb,\r | |
1e23bd8d | 389 | (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)\r |
ead42efc | 390 | );\r |
391 | IDEWritePortB (\r | |
392 | IdeDev->PciIo,\r | |
393 | IdeDev->IoPort->CylinderMsb,\r | |
1e23bd8d | 394 | (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)\r |
ead42efc | 395 | );\r |
396 | \r | |
397 | //\r | |
1e23bd8d | 398 | // ATA_DEFAULT_CTL:0x0a (0000,1010)\r |
ead42efc | 399 | // Disable interrupt\r |
400 | //\r | |
1e23bd8d | 401 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);\r |
ead42efc | 402 | \r |
403 | //\r | |
404 | // Send Packet command to inform device\r | |
405 | // that the following data bytes are command packet.\r | |
406 | //\r | |
1e23bd8d | 407 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);\r |
ead42efc | 408 | \r |
409 | Status = DRQReady (IdeDev, ATAPITIMEOUT);\r | |
410 | if (EFI_ERROR (Status)) {\r | |
411 | return Status;\r | |
412 | }\r | |
413 | \r | |
414 | //\r | |
415 | // Send out command packet\r | |
416 | //\r | |
417 | CommandIndex = Packet->Data16;\r | |
418 | for (Count = 0; Count < 6; Count++, CommandIndex++) {\r | |
419 | \r | |
420 | IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);\r | |
421 | gBS->Stall (10);\r | |
422 | }\r | |
423 | \r | |
424 | //\r | |
425 | // call PioReadWriteData() function to get\r | |
426 | // requested transfer data form device.\r | |
427 | //\r | |
428 | return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut);\r | |
429 | }\r | |
ead42efc | 430 | /**\r |
630d580d | 431 | This function is used to send out ATAPI commands conforms to the Packet Command\r |
432 | with PIO Data Out Protocol.\r | |
433 | \r | |
434 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r | |
435 | to record all the information of the IDE device.\r | |
436 | @param Packet pointer pointing to ATAPI_PACKET_COMMAND data structure\r | |
437 | which contains the contents of the command.\r | |
438 | @param Buffer buffer contained data transferred from host to device.\r | |
439 | @param ByteCount data size in byte unit of the buffer.\r | |
440 | @param TimeOut this parameter is used to specify the timeout value \r | |
441 | for the PioReadWriteData() function. \r | |
442 | @retval EFI_SUCCESS send out the ATAPI packet command successfully\r | |
443 | and device received data successfully. \r | |
444 | @retval EFI_DEVICE_ERROR the device failed to send data.\r | |
ead42efc | 445 | \r |
446 | **/\r | |
447 | EFI_STATUS\r | |
448 | AtapiPacketCommandOut (\r | |
449 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
450 | IN ATAPI_PACKET_COMMAND *Packet,\r | |
451 | IN UINT16 *Buffer,\r | |
452 | IN UINT32 ByteCount,\r | |
453 | IN UINTN TimeOut\r | |
454 | )\r | |
455 | {\r | |
456 | UINT16 *CommandIndex;\r | |
457 | EFI_STATUS Status;\r | |
458 | UINT32 Count;\r | |
459 | \r | |
460 | //\r | |
461 | // set all the command parameters\r | |
462 | // Before write to all the following registers, BSY and DRQ must be 0.\r | |
463 | //\r | |
464 | Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r | |
465 | if (EFI_ERROR (Status)) {\r | |
466 | return Status;\r | |
467 | }\r | |
468 | \r | |
469 | //\r | |
470 | // Select device via Device/Head Register.\r | |
471 | //\r | |
472 | IDEWritePortB (\r | |
473 | IdeDev->PciIo,\r | |
474 | IdeDev->IoPort->Head,\r | |
1e23bd8d | 475 | (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // ATA_DEFAULT_CMD: 0xa0 (1010,0000)\r |
ead42efc | 476 | );\r |
477 | \r | |
478 | //\r | |
479 | // No OVL; No DMA\r | |
480 | //\r | |
481 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);\r | |
482 | \r | |
483 | //\r | |
1e23bd8d | 484 | // set the transfersize to ATAPI_MAX_BYTE_COUNT to\r |
ead42efc | 485 | // let the device determine how many data should be transferred.\r |
486 | //\r | |
487 | IDEWritePortB (\r | |
488 | IdeDev->PciIo,\r | |
489 | IdeDev->IoPort->CylinderLsb,\r | |
1e23bd8d | 490 | (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)\r |
ead42efc | 491 | );\r |
492 | IDEWritePortB (\r | |
493 | IdeDev->PciIo,\r | |
494 | IdeDev->IoPort->CylinderMsb,\r | |
1e23bd8d | 495 | (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)\r |
ead42efc | 496 | );\r |
497 | \r | |
498 | //\r | |
499 | // DEFAULT_CTL:0x0a (0000,1010)\r | |
500 | // Disable interrupt\r | |
501 | //\r | |
1e23bd8d | 502 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);\r |
ead42efc | 503 | \r |
504 | //\r | |
505 | // Send Packet command to inform device\r | |
506 | // that the following data bytes are command packet.\r | |
507 | //\r | |
1e23bd8d | 508 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);\r |
ead42efc | 509 | \r |
510 | Status = DRQReady2 (IdeDev, ATAPITIMEOUT);\r | |
511 | if (EFI_ERROR (Status)) {\r | |
512 | return Status;\r | |
513 | }\r | |
514 | \r | |
515 | //\r | |
516 | // Send out command packet\r | |
517 | //\r | |
518 | CommandIndex = Packet->Data16;\r | |
519 | for (Count = 0; Count < 6; Count++, CommandIndex++) {\r | |
520 | IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);\r | |
521 | gBS->Stall (10);\r | |
522 | }\r | |
523 | \r | |
524 | //\r | |
525 | // call PioReadWriteData() function to send requested transfer data to device.\r | |
526 | //\r | |
527 | return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut);\r | |
528 | }\r | |
ead42efc | 529 | /**\r |
630d580d | 530 | Sends out ATAPI Inquiry Packet Command to the specified device. This command will\r |
531 | return INQUIRY data of the device.\r | |
ead42efc | 532 | \r |
630d580d | 533 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
534 | to record all the information of the IDE device.\r | |
ead42efc | 535 | \r |
630d580d | 536 | @retval EFI_SUCCESS Inquiry command completes successfully.\r |
537 | @retval EFI_DEVICE_ERROR Inquiry command failed.\r | |
ead42efc | 538 | \r |
630d580d | 539 | @note Parameter "IdeDev" will be updated in this function.\r |
ead42efc | 540 | \r |
630d580d | 541 | **/\r |
542 | EFI_STATUS\r | |
543 | AtapiInquiry (\r | |
544 | IN IDE_BLK_IO_DEV *IdeDev\r | |
545 | )\r | |
546 | {\r | |
547 | ATAPI_PACKET_COMMAND Packet;\r | |
548 | EFI_STATUS Status;\r | |
549 | ATAPI_INQUIRY_DATA *InquiryData;\r | |
550 | \r | |
551 | //\r | |
552 | // prepare command packet for the ATAPI Inquiry Packet Command.\r | |
553 | //\r | |
554 | ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r | |
555 | Packet.Inquiry.opcode = ATA_CMD_INQUIRY;\r | |
556 | Packet.Inquiry.page_code = 0;\r | |
557 | Packet.Inquiry.allocation_length = sizeof (ATAPI_INQUIRY_DATA);\r | |
558 | \r | |
559 | InquiryData = AllocatePool (sizeof (ATAPI_INQUIRY_DATA));\r | |
560 | if (InquiryData == NULL) {\r | |
561 | return EFI_DEVICE_ERROR;\r | |
562 | }\r | |
563 | \r | |
564 | //\r | |
565 | // Send command packet and get requested Inquiry data.\r | |
566 | //\r | |
567 | Status = AtapiPacketCommandIn (\r | |
568 | IdeDev,\r | |
569 | &Packet,\r | |
570 | (UINT16 *) InquiryData,\r | |
571 | sizeof (ATAPI_INQUIRY_DATA),\r | |
572 | ATAPITIMEOUT\r | |
573 | );\r | |
574 | if (EFI_ERROR (Status)) {\r | |
575 | gBS->FreePool (InquiryData);\r | |
576 | return EFI_DEVICE_ERROR;\r | |
577 | }\r | |
578 | \r | |
579 | IdeDev->InquiryData = InquiryData;\r | |
ead42efc | 580 | \r |
630d580d | 581 | return EFI_SUCCESS;\r |
582 | }\r | |
583 | /**\r | |
584 | This function is called by DiscoverIdeDevice() during its device\r | |
585 | identification.\r | |
586 | Its main purpose is to get enough information for the device media\r | |
587 | to fill in the Media data structure of the Block I/O Protocol interface.\r | |
ead42efc | 588 | \r |
630d580d | 589 | There are 5 steps to reach such objective:\r |
590 | 1. Sends out the ATAPI Identify Command to the specified device. \r | |
591 | Only ATAPI device responses to this command. If the command succeeds,\r | |
592 | it returns the Identify data structure which filled with information \r | |
593 | about the device. Since the ATAPI device contains removable media, \r | |
594 | the only meaningful information is the device module name.\r | |
595 | 2. Sends out ATAPI Inquiry Packet Command to the specified device.\r | |
596 | This command will return inquiry data of the device, which contains\r | |
597 | the device type information.\r | |
598 | 3. Allocate sense data space for future use. We don't detect the media\r | |
599 | presence here to improvement boot performance, especially when CD \r | |
600 | media is present. The media detection will be performed just before\r | |
601 | each BLK_IO read/write\r | |
ead42efc | 602 | \r |
630d580d | 603 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
604 | to record all the information of the IDE device.\r | |
ead42efc | 605 | \r |
630d580d | 606 | @retval EFI_SUCCESS Identify ATAPI device successfully.\r |
607 | @retval EFI_DEVICE_ERROR ATAPI Identify Device Command failed or device type\r | |
608 | is not supported by this IDE driver.\r | |
609 | @retval EFI_OUT_OF_RESOURCES Allocate memory for sense data failed \r | |
610 | \r | |
611 | @note Parameter "IdeDev" will be updated in this function.\r | |
ead42efc | 612 | **/\r |
613 | EFI_STATUS\r | |
630d580d | 614 | ATAPIIdentify (\r |
615 | IN IDE_BLK_IO_DEV *IdeDev\r | |
ead42efc | 616 | )\r |
617 | {\r | |
630d580d | 618 | EFI_IDENTIFY_DATA *AtapiIdentifyPointer;\r |
619 | UINT8 DeviceSelect;\r | |
620 | EFI_STATUS Status;\r | |
621 | \r | |
ead42efc | 622 | //\r |
630d580d | 623 | // device select bit\r |
ead42efc | 624 | //\r |
630d580d | 625 | DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r |
ead42efc | 626 | \r |
630d580d | 627 | AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA));\r |
628 | if (AtapiIdentifyPointer == NULL) {\r | |
629 | return EFI_OUT_OF_RESOURCES;\r | |
630 | }\r | |
ead42efc | 631 | //\r |
630d580d | 632 | // Send ATAPI Identify Command to get IDENTIFY data.\r |
ead42efc | 633 | //\r |
630d580d | 634 | Status = AtaPioDataIn (\r |
635 | IdeDev,\r | |
636 | (VOID *) AtapiIdentifyPointer,\r | |
637 | sizeof (EFI_IDENTIFY_DATA),\r | |
638 | ATA_CMD_IDENTIFY_DEVICE,\r | |
639 | DeviceSelect,\r | |
640 | 0,\r | |
641 | 0,\r | |
642 | 0,\r | |
643 | 0\r | |
644 | );\r | |
645 | \r | |
646 | if (EFI_ERROR (Status)) {\r | |
647 | gBS->FreePool (AtapiIdentifyPointer);\r | |
648 | return EFI_DEVICE_ERROR;\r | |
649 | }\r | |
650 | \r | |
651 | IdeDev->IdData = AtapiIdentifyPointer;\r | |
652 | PrintAtaModuleName (IdeDev);\r | |
ead42efc | 653 | \r |
654 | //\r | |
630d580d | 655 | // Send ATAPI Inquiry Packet Command to get INQUIRY data.\r |
ead42efc | 656 | //\r |
630d580d | 657 | Status = AtapiInquiry (IdeDev);\r |
658 | if (EFI_ERROR (Status)) {\r | |
659 | gBS->FreePool (IdeDev->IdData);\r | |
660 | //\r | |
661 | // Make sure the pIdData will not be freed again.\r | |
662 | //\r | |
663 | IdeDev->IdData = NULL;\r | |
664 | return EFI_DEVICE_ERROR;\r | |
ead42efc | 665 | }\r |
666 | //\r | |
630d580d | 667 | // Get media removable info from INQUIRY data.\r |
ead42efc | 668 | //\r |
630d580d | 669 | IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->InquiryData->RMB & 0x80) == 0x80);\r |
670 | \r | |
ead42efc | 671 | //\r |
630d580d | 672 | // Identify device type via INQUIRY data.\r |
673 | //\r | |
674 | switch (IdeDev->InquiryData->peripheral_type & 0x1f) {\r | |
675 | \r | |
676 | //\r | |
677 | // Magnetic Disk\r | |
678 | //\r | |
679 | case 0x00:\r | |
ead42efc | 680 | \r |
ead42efc | 681 | //\r |
630d580d | 682 | // device is LS120 or ZIP drive.\r |
ead42efc | 683 | //\r |
630d580d | 684 | IdeDev->Type = IdeMagnetic;\r |
ead42efc | 685 | \r |
630d580d | 686 | IdeDev->BlkIo.Media->MediaId = 0;\r |
ead42efc | 687 | //\r |
630d580d | 688 | // Give initial value\r |
ead42efc | 689 | //\r |
630d580d | 690 | IdeDev->BlkIo.Media->MediaPresent = FALSE;\r |
ead42efc | 691 | \r |
630d580d | 692 | IdeDev->BlkIo.Media->LastBlock = 0;\r |
693 | IdeDev->BlkIo.Media->BlockSize = 0x200;\r | |
694 | break;\r | |
ead42efc | 695 | \r |
630d580d | 696 | //\r |
697 | // CD-ROM\r | |
698 | //\r | |
699 | case 0x05:\r | |
ead42efc | 700 | \r |
630d580d | 701 | IdeDev->Type = IdeCdRom;\r |
702 | IdeDev->BlkIo.Media->MediaId = 0;\r | |
ead42efc | 703 | //\r |
630d580d | 704 | // Give initial value\r |
ead42efc | 705 | //\r |
630d580d | 706 | IdeDev->BlkIo.Media->MediaPresent = FALSE;\r |
707 | \r | |
708 | IdeDev->BlkIo.Media->LastBlock = 0;\r | |
709 | IdeDev->BlkIo.Media->BlockSize = 0x800;\r | |
710 | IdeDev->BlkIo.Media->ReadOnly = TRUE;\r | |
711 | break;\r | |
ead42efc | 712 | \r |
713 | //\r | |
630d580d | 714 | // Tape\r |
ead42efc | 715 | //\r |
630d580d | 716 | case 0x01:\r |
ead42efc | 717 | \r |
718 | //\r | |
630d580d | 719 | // WORM\r |
ead42efc | 720 | //\r |
630d580d | 721 | case 0x04:\r |
722 | \r | |
ead42efc | 723 | //\r |
630d580d | 724 | // Optical\r |
ead42efc | 725 | //\r |
630d580d | 726 | case 0x07:\r |
727 | \r | |
728 | default:\r | |
729 | IdeDev->Type = IdeUnknown;\r | |
730 | gBS->FreePool (IdeDev->IdData);\r | |
731 | gBS->FreePool (IdeDev->InquiryData);\r | |
732 | //\r | |
733 | // Make sure the pIdData and pInquiryData will not be freed again.\r | |
734 | //\r | |
735 | IdeDev->IdData = NULL;\r | |
736 | IdeDev->InquiryData = NULL;\r | |
737 | return EFI_DEVICE_ERROR;\r | |
738 | }\r | |
ead42efc | 739 | \r |
740 | //\r | |
630d580d | 741 | // original sense data numbers\r |
ead42efc | 742 | //\r |
630d580d | 743 | IdeDev->SenseDataNumber = 20;\r |
ead42efc | 744 | \r |
630d580d | 745 | IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (ATAPI_REQUEST_SENSE_DATA));\r |
746 | if (IdeDev->SenseData == NULL) {\r | |
747 | gBS->FreePool (IdeDev->IdData);\r | |
748 | gBS->FreePool (IdeDev->InquiryData);\r | |
749 | //\r | |
750 | // Make sure the pIdData and pInquiryData will not be freed again.\r | |
751 | //\r | |
752 | IdeDev->IdData = NULL;\r | |
753 | IdeDev->InquiryData = NULL;\r | |
754 | return EFI_OUT_OF_RESOURCES;\r | |
ead42efc | 755 | }\r |
756 | \r | |
757 | return EFI_SUCCESS;\r | |
758 | }\r | |
ead42efc | 759 | /**\r |
630d580d | 760 | Sends out ATAPI Request Sense Packet Command to the specified device. This command\r |
761 | will return all the current Sense data in the device. This function will pack \r | |
762 | all the Sense data in one single buffer.\r | |
763 | \r | |
764 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r | |
765 | to record all the information of the IDE device.\r | |
766 | @param SenseCounts allocated in this function, and freed by the calling function.\r | |
767 | This buffer is used to accommodate all the sense data returned \r | |
768 | by the device.\r | |
769 | \r | |
770 | @retval EFI_SUCCESS Request Sense command completes successfully.\r | |
771 | @retval EFI_DEVICE_ERROR Request Sense command failed.\r | |
ead42efc | 772 | **/\r |
773 | EFI_STATUS\r | |
774 | AtapiRequestSense (\r | |
775 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
776 | OUT UINTN *SenseCounts\r | |
777 | )\r | |
778 | {\r | |
779 | EFI_STATUS Status;\r | |
1e23bd8d | 780 | ATAPI_REQUEST_SENSE_DATA *Sense;\r |
ead42efc | 781 | UINT16 *Ptr;\r |
782 | BOOLEAN FetchSenseData;\r | |
783 | ATAPI_PACKET_COMMAND Packet;\r | |
784 | \r | |
785 | *SenseCounts = 0;\r | |
786 | \r | |
1e23bd8d | 787 | ZeroMem (IdeDev->SenseData, sizeof (ATAPI_REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));\r |
ead42efc | 788 | //\r |
789 | // fill command packet for Request Sense Packet Command\r | |
790 | //\r | |
791 | ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r | |
1e23bd8d | 792 | Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;\r |
793 | Packet.RequestSence.allocation_length = sizeof (ATAPI_REQUEST_SENSE_DATA);\r | |
ead42efc | 794 | \r |
795 | //\r | |
796 | // initialize pointer\r | |
797 | //\r | |
798 | Ptr = (UINT16 *) IdeDev->SenseData;\r | |
799 | //\r | |
800 | // request sense data from device continuously until no sense data\r | |
801 | // exists in the device.\r | |
802 | //\r | |
803 | for (FetchSenseData = TRUE; FetchSenseData;) {\r | |
804 | \r | |
1e23bd8d | 805 | Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;\r |
ead42efc | 806 | \r |
807 | //\r | |
808 | // send out Request Sense Packet Command and get one Sense data form device\r | |
809 | //\r | |
810 | Status = AtapiPacketCommandIn (\r | |
811 | IdeDev,\r | |
812 | &Packet,\r | |
813 | Ptr,\r | |
1e23bd8d | 814 | sizeof (ATAPI_REQUEST_SENSE_DATA),\r |
ead42efc | 815 | ATAPITIMEOUT\r |
816 | );\r | |
817 | //\r | |
818 | // failed to get Sense data\r | |
819 | //\r | |
820 | if (EFI_ERROR (Status)) {\r | |
821 | if (*SenseCounts == 0) {\r | |
822 | return EFI_DEVICE_ERROR;\r | |
823 | } else {\r | |
824 | return EFI_SUCCESS;\r | |
825 | }\r | |
826 | }\r | |
827 | \r | |
630d580d | 828 | (*SenseCounts)++;\r |
829 | //\r | |
830 | // We limit MAX sense data count to 20 in order to avoid dead loop. Some\r | |
831 | // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.\r | |
832 | // In this case, dead loop occurs if we don't have a gatekeeper. 20 is\r | |
833 | // supposed to be large enough for any ATAPI device.\r | |
834 | //\r | |
835 | if ((Sense->sense_key != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) {\r | |
836 | //\r | |
837 | // Ptr is word-based pointer\r | |
838 | //\r | |
839 | Ptr += (sizeof (ATAPI_REQUEST_SENSE_DATA) + 1) >> 1;\r | |
840 | \r | |
841 | } else {\r | |
842 | //\r | |
843 | // when no sense key, skip out the loop\r | |
844 | //\r | |
845 | FetchSenseData = FALSE;\r | |
846 | }\r | |
847 | }\r | |
848 | \r | |
849 | return EFI_SUCCESS;\r | |
850 | }\r | |
851 | /**\r | |
852 | This function is used to parse sense data. Only the first sense data is honoured\r | |
853 | \r | |
854 | @param IdeDev Indicates the calling context.\r | |
855 | @param SenseCount Count of sense data.\r | |
856 | @param Result The parsed result.\r | |
857 | \r | |
858 | @retval EFI_SUCCESS Successfully parsed.\r | |
859 | @retval EFI_INVALID_PARAMETER Count of sense data is zero.\r | |
860 | \r | |
861 | **/\r | |
862 | EFI_STATUS\r | |
863 | ParseSenseData (\r | |
864 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
865 | IN UINTN SenseCount,\r | |
866 | OUT SENSE_RESULT *Result\r | |
867 | )\r | |
868 | {\r | |
869 | ATAPI_REQUEST_SENSE_DATA *SenseData;\r | |
870 | \r | |
871 | if (SenseCount == 0) {\r | |
872 | return EFI_INVALID_PARAMETER;\r | |
873 | }\r | |
874 | \r | |
875 | //\r | |
876 | // Only use the first sense data\r | |
877 | //\r | |
878 | SenseData = IdeDev->SenseData;\r | |
879 | *Result = SenseOtherSense;\r | |
880 | \r | |
881 | switch (SenseData->sense_key) {\r | |
882 | case ATA_SK_NO_SENSE:\r | |
883 | *Result = SenseNoSenseKey;\r | |
884 | break;\r | |
885 | case ATA_SK_NOT_READY:\r | |
886 | switch (SenseData->addnl_sense_code) {\r | |
887 | case ATA_ASC_NO_MEDIA:\r | |
888 | *Result = SenseNoMedia;\r | |
889 | break;\r | |
890 | case ATA_ASC_MEDIA_UPSIDE_DOWN:\r | |
891 | *Result = SenseMediaError;\r | |
892 | break;\r | |
893 | case ATA_ASC_NOT_READY:\r | |
894 | if (SenseData->addnl_sense_code_qualifier == ATA_ASCQ_IN_PROGRESS) {\r | |
895 | *Result = SenseDeviceNotReadyNeedRetry;\r | |
896 | } else {\r | |
897 | *Result = SenseDeviceNotReadyNoRetry;\r | |
898 | }\r | |
899 | break;\r | |
900 | }\r | |
901 | break;\r | |
902 | case ATA_SK_UNIT_ATTENTION:\r | |
903 | if (SenseData->addnl_sense_code == ATA_ASC_MEDIA_CHANGE) {\r | |
904 | *Result = SenseMediaChange;\r | |
905 | }\r | |
906 | break;\r | |
907 | case ATA_SK_MEDIUM_ERROR:\r | |
908 | switch (SenseData->addnl_sense_code) {\r | |
909 | case ATA_ASC_MEDIA_ERR1:\r | |
910 | case ATA_ASC_MEDIA_ERR2:\r | |
911 | case ATA_ASC_MEDIA_ERR3:\r | |
912 | case ATA_ASC_MEDIA_ERR4:\r | |
913 | *Result = SenseMediaError;\r | |
914 | break;\r | |
915 | }\r | |
916 | break;\r | |
917 | default:\r | |
918 | break;\r | |
919 | }\r | |
920 | \r | |
921 | return EFI_SUCCESS;\r | |
922 | }\r | |
923 | \r | |
924 | /**\r | |
925 | Sends out ATAPI Test Unit Ready Packet Command to the specified device\r | |
926 | to find out whether device is accessible.\r | |
927 | \r | |
928 | @param IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r | |
929 | to record all the information of the IDE device.\r | |
930 | @param SResult Sense result for this packet command.\r | |
931 | \r | |
932 | @retval EFI_SUCCESS Device is accessible.\r | |
933 | @retval EFI_DEVICE_ERROR Device is not accessible.\r | |
934 | \r | |
935 | **/\r | |
936 | EFI_STATUS\r | |
937 | AtapiTestUnitReady (\r | |
938 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
939 | OUT SENSE_RESULT *SResult \r | |
940 | )\r | |
941 | {\r | |
942 | ATAPI_PACKET_COMMAND Packet;\r | |
943 | EFI_STATUS Status;\r | |
944 | UINTN SenseCount;\r | |
945 | \r | |
946 | //\r | |
947 | // fill command packet\r | |
948 | //\r | |
949 | ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r | |
950 | Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;\r | |
951 | \r | |
952 | //\r | |
953 | // send command packet\r | |
954 | //\r | |
955 | Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);\r | |
956 | if (EFI_ERROR (Status)) {\r | |
957 | return Status;\r | |
958 | }\r | |
ead42efc | 959 | \r |
630d580d | 960 | Status = AtapiRequestSense (IdeDev, &SenseCount);\r |
961 | if (EFI_ERROR (Status)) {\r | |
962 | return Status;\r | |
ead42efc | 963 | }\r |
964 | \r | |
630d580d | 965 | ParseSenseData (IdeDev, SenseCount, SResult);\r |
ead42efc | 966 | return EFI_SUCCESS;\r |
967 | }\r | |
968 | \r | |
630d580d | 969 | \r |
ead42efc | 970 | /**\r |
971 | Sends out ATAPI Read Capacity Packet Command to the specified device.\r | |
972 | This command will return the information regarding the capacity of the\r | |
973 | media in the device.\r | |
974 | \r | |
975 | Current device status will impact device's response to the Read Capacity\r | |
976 | Command. For example, if the device once reset, the Read Capacity\r | |
977 | Command will fail. The Sense data record the current device status, so \r | |
978 | if the Read Capacity Command failed, the Sense data must be requested\r | |
979 | and be analyzed to determine if the Read Capacity Command should retry.\r | |
980 | \r | |
630d580d | 981 | @param IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
982 | to record all the information of the IDE device.\r | |
983 | @param SResult Sense result for this packet command\r | |
ead42efc | 984 | \r |
985 | @retval EFI_SUCCESS Read Capacity Command finally completes successfully.\r | |
986 | @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.\r | |
630d580d | 987 | @retval EFI_NOT_READY Operation succeeds but returned capacity is 0\r |
ead42efc | 988 | \r |
989 | @note Parameter "IdeDev" will be updated in this function.\r | |
990 | \r | |
630d580d | 991 | \r |
ead42efc | 992 | **/\r |
993 | EFI_STATUS\r | |
994 | AtapiReadCapacity (\r | |
995 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
9ebae8ae | 996 | OUT SENSE_RESULT *SResult \r |
ead42efc | 997 | )\r |
998 | {\r | |
999 | //\r | |
1000 | // status returned by Read Capacity Packet Command\r | |
1001 | //\r | |
1002 | EFI_STATUS Status;\r | |
1003 | EFI_STATUS SenseStatus;\r | |
1004 | ATAPI_PACKET_COMMAND Packet;\r | |
9ebae8ae | 1005 | UINTN SenseCount;\r |
ead42efc | 1006 | \r |
1007 | //\r | |
1008 | // used for capacity data returned from ATAPI device\r | |
1009 | //\r | |
1e23bd8d | 1010 | ATAPI_READ_CAPACITY_DATA Data;\r |
1011 | ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;\r | |
ead42efc | 1012 | \r |
ead42efc | 1013 | ZeroMem (&Data, sizeof (Data));\r |
1014 | ZeroMem (&FormatData, sizeof (FormatData));\r | |
1015 | \r | |
1016 | if (IdeDev->Type == IdeCdRom) {\r | |
1017 | \r | |
1018 | ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r | |
1e23bd8d | 1019 | Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;\r |
ead42efc | 1020 | Status = AtapiPacketCommandIn (\r |
1021 | IdeDev,\r | |
1022 | &Packet,\r | |
1023 | (UINT16 *) &Data,\r | |
1e23bd8d | 1024 | sizeof (ATAPI_READ_CAPACITY_DATA),\r |
ead42efc | 1025 | ATAPITIMEOUT\r |
1026 | );\r | |
1027 | \r | |
1028 | } else {\r | |
1029 | //\r | |
1030 | // Type == IdeMagnetic\r | |
1031 | //\r | |
1032 | ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r | |
1e23bd8d | 1033 | Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;\r |
ead42efc | 1034 | Packet.ReadFormatCapacity.allocation_length_lo = 12;\r |
1035 | Status = AtapiPacketCommandIn (\r | |
1036 | IdeDev,\r | |
1037 | &Packet,\r | |
1038 | (UINT16 *) &FormatData,\r | |
1e23bd8d | 1039 | sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),\r |
ead42efc | 1040 | ATAPITIMEOUT\r |
1041 | );\r | |
1042 | }\r | |
1043 | \r | |
1044 | if (Status == EFI_TIMEOUT) {\r | |
ead42efc | 1045 | return Status;\r |
1046 | }\r | |
1047 | \r | |
9ebae8ae | 1048 | SenseStatus = AtapiRequestSense (IdeDev, &SenseCount);\r |
ead42efc | 1049 | \r |
1050 | if (!EFI_ERROR (SenseStatus)) {\r | |
9ebae8ae | 1051 | ParseSenseData (IdeDev, SenseCount, SResult); \r |
1052 | \r | |
1053 | if (!EFI_ERROR (Status) && *SResult == SenseNoSenseKey) {\r | |
ead42efc | 1054 | if (IdeDev->Type == IdeCdRom) {\r |
1055 | \r | |
1056 | IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r | |
1057 | (Data.LastLba2 << 16) |\r | |
1058 | (Data.LastLba1 << 8) |\r | |
1059 | Data.LastLba0;\r | |
1060 | \r | |
9b906315 | 1061 | IdeDev->BlkIo.Media->MediaPresent = TRUE;\r |
ead42efc | 1062 | \r |
1063 | IdeDev->BlkIo.Media->ReadOnly = TRUE;\r | |
1064 | \r | |
1065 | //\r | |
1066 | // Because the user data portion in the sector of the Data CD supported\r | |
1067 | // is always 0x800\r | |
1068 | //\r | |
1069 | IdeDev->BlkIo.Media->BlockSize = 0x800;\r | |
1070 | }\r | |
1071 | \r | |
1072 | if (IdeDev->Type == IdeMagnetic) {\r | |
1073 | \r | |
1074 | if (FormatData.DesCode == 3) {\r | |
1075 | IdeDev->BlkIo.Media->MediaPresent = FALSE;\r | |
1076 | IdeDev->BlkIo.Media->LastBlock = 0;\r | |
1077 | } else {\r | |
1078 | \r | |
1079 | IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) |\r | |
1080 | (FormatData.LastLba2 << 16) | \r | |
1081 | (FormatData.LastLba1 << 8) |\r | |
1082 | FormatData.LastLba0;\r | |
1083 | if (IdeDev->BlkIo.Media->LastBlock != 0) {\r | |
1084 | IdeDev->BlkIo.Media->LastBlock--;\r | |
1085 | \r | |
1086 | IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |\r | |
1087 | (FormatData.BlockSize1 << 8) |\r | |
1088 | FormatData.BlockSize0;\r | |
1089 | \r | |
1090 | IdeDev->BlkIo.Media->MediaPresent = TRUE;\r | |
1091 | } else {\r | |
1092 | IdeDev->BlkIo.Media->MediaPresent = FALSE;\r | |
1093 | //\r | |
1094 | // Return EFI_NOT_READY operation succeeds but returned capacity is 0\r | |
1095 | //\r | |
1096 | return EFI_NOT_READY;\r | |
1097 | }\r | |
1098 | \r | |
1099 | IdeDev->BlkIo.Media->BlockSize = 0x200;\r | |
1100 | \r | |
1101 | }\r | |
1102 | }\r | |
1103 | }\r | |
1104 | \r | |
1105 | return EFI_SUCCESS;\r | |
1106 | \r | |
1107 | } else {\r | |
ead42efc | 1108 | return EFI_DEVICE_ERROR;\r |
1109 | }\r | |
1110 | }\r | |
630d580d | 1111 | /**\r |
1112 | This function is used to test the current media write-protected or not residing\r | |
1113 | in the LS-120 drive or ZIP drive. \r | |
1114 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r | |
1115 | to record all the information of the IDE device.\r | |
1116 | @param WriteProtected if True, current media is write protected.\r | |
1117 | if FALSE, current media is writable\r | |
1118 | \r | |
1119 | @retval EFI_SUCCESS The media write-protected status is achieved successfully\r | |
1120 | @retval EFI_DEVICE_ERROR Get Media Status Command is failed.\r | |
1121 | **/\r | |
1122 | EFI_STATUS\r | |
1123 | IsLS120orZipWriteProtected (\r | |
1124 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1125 | OUT BOOLEAN *WriteProtected\r | |
1126 | )\r | |
1127 | {\r | |
1128 | EFI_STATUS Status;\r | |
1129 | \r | |
1130 | *WriteProtected = FALSE;\r | |
1131 | \r | |
1132 | Status = LS120EnableMediaStatus (IdeDev, TRUE);\r | |
1133 | if (EFI_ERROR (Status)) {\r | |
1134 | return EFI_DEVICE_ERROR;\r | |
1135 | }\r | |
1136 | \r | |
1137 | //\r | |
1138 | // the Get Media Status Command is only valid\r | |
1139 | // if a Set Features/Enable Media Status Command has been priviously issued.\r | |
1140 | //\r | |
1141 | if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {\r | |
1142 | \r | |
1143 | *WriteProtected = TRUE;\r | |
1144 | } else {\r | |
1145 | \r | |
1146 | *WriteProtected = FALSE;\r | |
1147 | }\r | |
1148 | \r | |
1149 | //\r | |
1150 | // After Get Media Status Command completes,\r | |
1151 | // Set Features/Disable Media Command should be sent.\r | |
1152 | //\r | |
1153 | Status = LS120EnableMediaStatus (IdeDev, FALSE);\r | |
1154 | if (EFI_ERROR (Status)) {\r | |
1155 | return EFI_DEVICE_ERROR;\r | |
1156 | }\r | |
1157 | \r | |
1158 | return EFI_SUCCESS;\r | |
1159 | }\r | |
ead42efc | 1160 | \r |
1161 | /**\r | |
630d580d | 1162 | Used before read/write blocks from/to ATAPI device media. Since ATAPI device \r |
1163 | media is removable, it is necessary to detect whether media is present and \r | |
1164 | get current present media's information, and if media has been changed, Block\r | |
1165 | I/O Protocol need to be reinstalled.\r | |
1166 | \r | |
1167 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r | |
1168 | to record all the information of the IDE device.\r | |
1169 | @param MediaChange return value that indicates if the media of the device has been\r | |
1170 | changed.\r | |
1171 | \r | |
1172 | @retval EFI_SUCCESS media found successfully.\r | |
1173 | @retval EFI_DEVICE_ERROR any error encounters during media detection.\r | |
1174 | @retval EFI_NO_MEDIA media not found.\r | |
ead42efc | 1175 | \r |
1176 | @note\r | |
1177 | parameter IdeDev may be updated in this function.\r | |
1178 | \r | |
1179 | **/\r | |
1180 | EFI_STATUS\r | |
1181 | AtapiDetectMedia (\r | |
1182 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1183 | OUT BOOLEAN *MediaChange\r | |
1184 | )\r | |
1185 | {\r | |
1186 | EFI_STATUS Status;\r | |
1187 | EFI_STATUS CleanStateStatus;\r | |
1188 | EFI_BLOCK_IO_MEDIA OldMediaInfo;\r | |
1189 | UINTN RetryTimes;\r | |
1190 | UINTN RetryNotReady;\r | |
ead42efc | 1191 | SENSE_RESULT SResult;\r |
1192 | BOOLEAN WriteProtected;\r | |
1193 | \r | |
1194 | CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));\r | |
1195 | *MediaChange = FALSE;\r | |
1196 | //\r | |
1197 | // Retry for SenseDeviceNotReadyNeedRetry.\r | |
1198 | // Each retry takes 1s and we limit the upper boundary to\r | |
1199 | // 120 times about 2 min.\r | |
1200 | //\r | |
1201 | RetryNotReady = 120;\r | |
1202 | \r | |
1203 | //\r | |
1204 | // Do Test Unit Ready\r | |
1205 | //\r | |
1206 | DoTUR:\r | |
1207 | //\r | |
1208 | // Retry 5 times\r | |
1209 | //\r | |
1210 | RetryTimes = 5;\r | |
1211 | while (RetryTimes != 0) {\r | |
1212 | \r | |
9ebae8ae | 1213 | Status = AtapiTestUnitReady (IdeDev, &SResult);\r |
ead42efc | 1214 | \r |
1215 | if (EFI_ERROR (Status)) {\r | |
1216 | //\r | |
1217 | // Test Unit Ready error without sense data.\r | |
1218 | // For some devices, this means there's extra data\r | |
1219 | // that has not been read, so we read these extra\r | |
1220 | // data out before going on.\r | |
1221 | //\r | |
1222 | CleanStateStatus = AtapiReadPendingData (IdeDev);\r | |
1223 | if (EFI_ERROR (CleanStateStatus)) {\r | |
1224 | //\r | |
1225 | // Busy wait failed, try again\r | |
1226 | //\r | |
1227 | RetryTimes--;\r | |
1228 | }\r | |
1229 | //\r | |
1230 | // Try again without counting down RetryTimes\r | |
1231 | //\r | |
1232 | continue;\r | |
1233 | } else {\r | |
ead42efc | 1234 | switch (SResult) {\r |
1235 | case SenseNoSenseKey:\r | |
1236 | if (IdeDev->BlkIo.Media->MediaPresent) {\r | |
1237 | goto Done;\r | |
1238 | } else {\r | |
1239 | //\r | |
1240 | // Media present but the internal structure need refreshed.\r | |
1241 | // Try Read Capacity\r | |
1242 | //\r | |
1243 | goto DoRC;\r | |
1244 | }\r | |
1245 | break;\r | |
1246 | \r | |
1247 | case SenseDeviceNotReadyNeedRetry:\r | |
1248 | if (--RetryNotReady == 0) {\r | |
1249 | return EFI_DEVICE_ERROR;\r | |
1250 | }\r | |
1251 | gBS->Stall (1000 * STALL_1_MILLI_SECOND);\r | |
1252 | continue;\r | |
1253 | break;\r | |
1254 | \r | |
1255 | case SenseNoMedia:\r | |
1256 | IdeDev->BlkIo.Media->MediaPresent = FALSE;\r | |
1257 | IdeDev->BlkIo.Media->LastBlock = 0;\r | |
1258 | goto Done;\r | |
1259 | break;\r | |
1260 | \r | |
1261 | case SenseDeviceNotReadyNoRetry:\r | |
1262 | case SenseMediaError:\r | |
1263 | return EFI_DEVICE_ERROR;\r | |
1264 | \r | |
1265 | case SenseMediaChange:\r | |
1266 | IdeDev->BlkIo.Media->MediaId++;\r | |
1267 | goto DoRC;\r | |
1268 | break;\r | |
1269 | \r | |
1270 | default:\r | |
1271 | RetryTimes--;\r | |
1272 | break;\r | |
1273 | }\r | |
1274 | }\r | |
1275 | }\r | |
1276 | \r | |
1277 | return EFI_DEVICE_ERROR;\r | |
1278 | \r | |
1279 | //\r | |
1280 | // Do Read Capacity\r | |
1281 | //\r | |
1282 | DoRC:\r | |
1283 | RetryTimes = 5;\r | |
1284 | \r | |
1285 | while (RetryTimes != 0) {\r | |
1286 | \r | |
9ebae8ae | 1287 | Status = AtapiReadCapacity (IdeDev, &SResult);\r |
ead42efc | 1288 | \r |
1289 | if (EFI_ERROR (Status)) {\r | |
1290 | RetryTimes--;\r | |
1291 | continue;\r | |
1292 | } else {\r | |
ead42efc | 1293 | switch (SResult) {\r |
1294 | case SenseNoSenseKey:\r | |
1295 | goto Done;\r | |
1296 | break;\r | |
1297 | \r | |
1298 | case SenseDeviceNotReadyNeedRetry:\r | |
1299 | //\r | |
1300 | // We use Test Unit Ready to retry which\r | |
1301 | // is faster.\r | |
1302 | //\r | |
1303 | goto DoTUR;\r | |
1304 | break;\r | |
1305 | \r | |
1306 | case SenseNoMedia:\r | |
1307 | IdeDev->BlkIo.Media->MediaPresent = FALSE;\r | |
1308 | IdeDev->BlkIo.Media->LastBlock = 0;\r | |
1309 | goto Done;\r | |
1310 | break;\r | |
1311 | \r | |
1312 | case SenseDeviceNotReadyNoRetry:\r | |
1313 | case SenseMediaError:\r | |
1314 | return EFI_DEVICE_ERROR;\r | |
1315 | \r | |
1316 | case SenseMediaChange:\r | |
1317 | IdeDev->BlkIo.Media->MediaId++;\r | |
1318 | continue;\r | |
1319 | break;\r | |
1320 | \r | |
1321 | default:\r | |
1322 | RetryTimes--;\r | |
1323 | break;\r | |
1324 | }\r | |
1325 | }\r | |
1326 | }\r | |
1327 | \r | |
1328 | return EFI_DEVICE_ERROR;\r | |
1329 | \r | |
1330 | Done:\r | |
1331 | //\r | |
1332 | // the following code is to check the write-protected for LS120 media\r | |
1333 | //\r | |
1334 | if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {\r | |
1335 | \r | |
1336 | Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);\r | |
1337 | if (!EFI_ERROR (Status)) {\r | |
1338 | \r | |
1339 | if (WriteProtected) {\r | |
1340 | \r | |
1341 | IdeDev->BlkIo.Media->ReadOnly = TRUE;\r | |
1342 | } else {\r | |
1343 | \r | |
1344 | IdeDev->BlkIo.Media->ReadOnly = FALSE;\r | |
1345 | }\r | |
1346 | \r | |
1347 | }\r | |
1348 | }\r | |
1349 | \r | |
1350 | if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {\r | |
1351 | //\r | |
1352 | // Media change information got from the device\r | |
1353 | //\r | |
1354 | *MediaChange = TRUE;\r | |
1355 | }\r | |
1356 | \r | |
1357 | if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {\r | |
1358 | *MediaChange = TRUE;\r | |
1359 | IdeDev->BlkIo.Media->MediaId += 1;\r | |
1360 | }\r | |
1361 | \r | |
1362 | if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {\r | |
1363 | *MediaChange = TRUE;\r | |
1364 | IdeDev->BlkIo.Media->MediaId += 1;\r | |
1365 | }\r | |
1366 | \r | |
1367 | if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {\r | |
1368 | *MediaChange = TRUE;\r | |
1369 | IdeDev->BlkIo.Media->MediaId += 1;\r | |
1370 | }\r | |
1371 | \r | |
1372 | if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {\r | |
1373 | if (IdeDev->BlkIo.Media->MediaPresent) {\r | |
1374 | //\r | |
1375 | // when change from no media to media present, reset the MediaId to 1.\r | |
1376 | //\r | |
1377 | IdeDev->BlkIo.Media->MediaId = 1;\r | |
1378 | } else {\r | |
1379 | //\r | |
1380 | // when no media, reset the MediaId to zero.\r | |
1381 | //\r | |
1382 | IdeDev->BlkIo.Media->MediaId = 0;\r | |
1383 | }\r | |
1384 | \r | |
1385 | *MediaChange = TRUE;\r | |
1386 | }\r | |
1387 | \r | |
1388 | //\r | |
1389 | // if any change on current existing media,\r | |
1390 | // the Block I/O protocol need to be reinstalled.\r | |
1391 | //\r | |
1392 | if (*MediaChange) {\r | |
1393 | gBS->ReinstallProtocolInterface (\r | |
1394 | IdeDev->Handle,\r | |
1395 | &gEfiBlockIoProtocolGuid,\r | |
1396 | &IdeDev->BlkIo,\r | |
1397 | &IdeDev->BlkIo\r | |
1398 | );\r | |
1399 | }\r | |
1400 | \r | |
1401 | if (IdeDev->BlkIo.Media->MediaPresent) {\r | |
1402 | return EFI_SUCCESS;\r | |
1403 | } else {\r | |
1404 | return EFI_NO_MEDIA;\r | |
1405 | }\r | |
1406 | }\r | |
1407 | \r | |
1408 | /**\r | |
1409 | This function is called by the AtapiBlkIoReadBlocks() to perform\r | |
1410 | read from media in block unit.\r | |
1411 | \r | |
1412 | The main command used to access media here is READ(10) Command. \r | |
1413 | READ(10) Command requests that the ATAPI device media transfer \r | |
1414 | specified data to the host. Data is transferred in block(sector) \r | |
1415 | unit. The maximum number of blocks that can be transferred once is\r | |
1416 | 65536. This is the main difference between READ(10) and READ(12) \r | |
1417 | Command. The maximum number of blocks in READ(12) is 2 power 32.\r | |
1418 | \r | |
630d580d | 1419 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
1420 | to record all the information of the IDE device.\r | |
1421 | @param Buffer A pointer to the destination buffer for the data. \r | |
1422 | @param Lba The starting logical block address to read from on the \r | |
1423 | device media.\r | |
1424 | @param NumberOfBlocks The number of transfer data blocks.\r | |
ead42efc | 1425 | \r |
630d580d | 1426 | @return status is fully dependent on the return status of AtapiPacketCommandIn() function.\r |
ead42efc | 1427 | \r |
1428 | **/\r | |
1429 | EFI_STATUS\r | |
1430 | AtapiReadSectors (\r | |
1431 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1432 | IN VOID *Buffer,\r | |
1433 | IN EFI_LBA Lba,\r | |
1434 | IN UINTN NumberOfBlocks\r | |
1435 | )\r | |
1436 | {\r | |
1437 | \r | |
1438 | ATAPI_PACKET_COMMAND Packet;\r | |
1e23bd8d | 1439 | ATAPI_READ10_CMD *Read10Packet;\r |
ead42efc | 1440 | EFI_STATUS Status;\r |
1441 | UINTN BlocksRemaining;\r | |
1442 | UINT32 Lba32;\r | |
1443 | UINT32 BlockSize;\r | |
1444 | UINT32 ByteCount;\r | |
1445 | UINT16 SectorCount;\r | |
1446 | VOID *PtrBuffer;\r | |
1447 | UINT16 MaxBlock;\r | |
1448 | UINTN TimeOut;\r | |
1449 | \r | |
1450 | //\r | |
1451 | // fill command packet for Read(10) command\r | |
1452 | //\r | |
1453 | ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r | |
1454 | Read10Packet = &Packet.Read10;\r | |
1455 | Lba32 = (UINT32) Lba;\r | |
1456 | PtrBuffer = Buffer;\r | |
1457 | \r | |
1458 | BlockSize = IdeDev->BlkIo.Media->BlockSize;\r | |
1459 | \r | |
1460 | //\r | |
1461 | // limit the data bytes that can be transferred by one Read(10) Command\r | |
1462 | //\r | |
1463 | MaxBlock = 65535;\r | |
1464 | \r | |
1465 | BlocksRemaining = NumberOfBlocks;\r | |
1466 | \r | |
1467 | Status = EFI_SUCCESS;\r | |
1468 | while (BlocksRemaining > 0) {\r | |
1469 | \r | |
1470 | if (BlocksRemaining <= MaxBlock) {\r | |
1471 | \r | |
1472 | SectorCount = (UINT16) BlocksRemaining;\r | |
1473 | } else {\r | |
1474 | \r | |
1475 | SectorCount = MaxBlock;\r | |
1476 | }\r | |
1477 | \r | |
1478 | //\r | |
1479 | // fill the Packet data structure\r | |
1480 | //\r | |
1481 | \r | |
1e23bd8d | 1482 | Read10Packet->opcode = ATA_CMD_READ_10;\r |
ead42efc | 1483 | \r |
1484 | //\r | |
1485 | // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r | |
1486 | // Lba0 is MSB, Lba3 is LSB\r | |
1487 | //\r | |
1488 | Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r | |
1489 | Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r | |
1490 | Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r | |
1491 | Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r | |
1492 | \r | |
1493 | //\r | |
1494 | // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r | |
1495 | // TranLen0 is MSB, TranLen is LSB\r | |
1496 | //\r | |
1497 | Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r | |
1498 | Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r | |
1499 | \r | |
1500 | ByteCount = SectorCount * BlockSize;\r | |
1501 | \r | |
1502 | if (IdeDev->Type == IdeCdRom) {\r | |
1503 | TimeOut = CDROMLONGTIMEOUT;\r | |
1504 | } else {\r | |
1505 | TimeOut = ATAPILONGTIMEOUT;\r | |
1506 | }\r | |
1507 | \r | |
1508 | Status = AtapiPacketCommandIn (\r | |
1509 | IdeDev,\r | |
1510 | &Packet,\r | |
1511 | (UINT16 *) PtrBuffer,\r | |
1512 | ByteCount,\r | |
1513 | TimeOut\r | |
1514 | );\r | |
1515 | if (EFI_ERROR (Status)) {\r | |
1516 | return Status;\r | |
1517 | }\r | |
1518 | \r | |
1519 | Lba32 += SectorCount;\r | |
1520 | PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r | |
1521 | BlocksRemaining -= SectorCount;\r | |
1522 | }\r | |
1523 | \r | |
1524 | return Status;\r | |
1525 | }\r | |
1526 | \r | |
1527 | /**\r | |
1528 | This function is called by the AtapiBlkIoWriteBlocks() to perform\r | |
1529 | write onto media in block unit.\r | |
1530 | The main command used to access media here is Write(10) Command. \r | |
1531 | Write(10) Command requests that the ATAPI device media transfer \r | |
1532 | specified data to the host. Data is transferred in block (sector) \r | |
1533 | unit. The maximum number of blocks that can be transferred once is\r | |
1534 | 65536. \r | |
1535 | \r | |
630d580d | 1536 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
1537 | to record all the information of the IDE device.\r | |
1538 | @param Buffer A pointer to the source buffer for the data. \r | |
1539 | @param Lba The starting logical block address to write onto \r | |
1540 | the device media.\r | |
1541 | @param NumberOfBlocks The number of transfer data blocks.\r | |
1542 | \r | |
1543 | @return status is fully dependent on the return status of AtapiPacketCommandOut() function.\r | |
ead42efc | 1544 | \r |
1545 | **/\r | |
1546 | EFI_STATUS\r | |
1547 | AtapiWriteSectors (\r | |
1548 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1549 | IN VOID *Buffer,\r | |
1550 | IN EFI_LBA Lba,\r | |
1551 | IN UINTN NumberOfBlocks\r | |
1552 | )\r | |
1553 | {\r | |
1554 | \r | |
1555 | ATAPI_PACKET_COMMAND Packet;\r | |
1e23bd8d | 1556 | ATAPI_READ10_CMD *Read10Packet;\r |
ead42efc | 1557 | \r |
1558 | EFI_STATUS Status;\r | |
1559 | UINTN BlocksRemaining;\r | |
1560 | UINT32 Lba32;\r | |
1561 | UINT32 BlockSize;\r | |
1562 | UINT32 ByteCount;\r | |
1563 | UINT16 SectorCount;\r | |
1564 | VOID *PtrBuffer;\r | |
1565 | UINT16 MaxBlock;\r | |
1566 | \r | |
1567 | //\r | |
1568 | // fill command packet for Write(10) command\r | |
1569 | // Write(10) command packet has the same data structure as\r | |
1570 | // Read(10) command packet,\r | |
1571 | // so here use the Read10Packet data structure\r | |
1572 | // for the Write(10) command packet.\r | |
1573 | //\r | |
1574 | ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r | |
1575 | Read10Packet = &Packet.Read10;\r | |
1576 | \r | |
1577 | Lba32 = (UINT32) Lba;\r | |
1578 | PtrBuffer = Buffer;\r | |
1579 | \r | |
1580 | BlockSize = IdeDev->BlkIo.Media->BlockSize;\r | |
1581 | \r | |
1582 | //\r | |
1583 | // limit the data bytes that can be transferred by one Read(10) Command\r | |
1584 | //\r | |
1585 | MaxBlock = (UINT16) (65536 / BlockSize);\r | |
1586 | \r | |
1587 | BlocksRemaining = NumberOfBlocks;\r | |
1588 | \r | |
1589 | Status = EFI_SUCCESS;\r | |
1590 | while (BlocksRemaining > 0) {\r | |
1591 | \r | |
1592 | if (BlocksRemaining >= MaxBlock) {\r | |
1593 | SectorCount = MaxBlock;\r | |
1594 | } else {\r | |
1595 | SectorCount = (UINT16) BlocksRemaining;\r | |
1596 | }\r | |
1597 | \r | |
1598 | //\r | |
1599 | // Command code is WRITE_10.\r | |
1600 | //\r | |
1e23bd8d | 1601 | Read10Packet->opcode = ATA_CMD_WRITE_10;\r |
ead42efc | 1602 | \r |
1603 | //\r | |
1604 | // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r | |
1605 | // Lba0 is MSB, Lba3 is LSB\r | |
1606 | //\r | |
1607 | Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r | |
1608 | Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r | |
1609 | Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r | |
1610 | Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r | |
1611 | \r | |
1612 | //\r | |
1613 | // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r | |
1614 | // TranLen0 is MSB, TranLen is LSB\r | |
1615 | //\r | |
1616 | Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r | |
1617 | Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r | |
1618 | \r | |
1619 | ByteCount = SectorCount * BlockSize;\r | |
1620 | \r | |
1621 | Status = AtapiPacketCommandOut (\r | |
1622 | IdeDev,\r | |
1623 | &Packet,\r | |
1624 | (UINT16 *) PtrBuffer,\r | |
1625 | ByteCount,\r | |
1626 | ATAPILONGTIMEOUT\r | |
1627 | );\r | |
1628 | if (EFI_ERROR (Status)) {\r | |
1629 | return Status;\r | |
1630 | }\r | |
1631 | \r | |
1632 | Lba32 += SectorCount;\r | |
1633 | PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);\r | |
1634 | BlocksRemaining -= SectorCount;\r | |
1635 | }\r | |
1636 | \r | |
1637 | return Status;\r | |
1638 | }\r | |
ead42efc | 1639 | /**\r |
1640 | This function is used to implement the Soft Reset on the specified\r | |
1641 | ATAPI device. Different from the AtaSoftReset(), here reset is a ATA\r | |
1642 | Soft Reset Command special for ATAPI device, and it only take effects\r | |
1643 | on the specified ATAPI device, not on the whole IDE bus.\r | |
1644 | Since the ATAPI soft reset is needed when device is in exceptional\r | |
1645 | condition (such as BSY bit is always set ), I think the Soft Reset\r | |
1646 | command should be sent without waiting for the BSY clear and DRDY\r | |
1647 | set.\r | |
1648 | This function is called by IdeBlkIoReset(), \r | |
1649 | a interface function of Block I/O protocol.\r | |
1650 | \r | |
630d580d | 1651 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
1652 | to record all the information of the IDE device.\r | |
ead42efc | 1653 | \r |
630d580d | 1654 | @retval EFI_SUCCESS Soft reset completes successfully.\r |
1655 | @retval EFI_DEVICE_ERROR Any step during the reset process is failed.\r | |
ead42efc | 1656 | \r |
1657 | **/\r | |
1658 | EFI_STATUS\r | |
1659 | AtapiSoftReset (\r | |
1660 | IN IDE_BLK_IO_DEV *IdeDev\r | |
1661 | )\r | |
1662 | {\r | |
1663 | UINT8 Command;\r | |
1664 | UINT8 DeviceSelect;\r | |
1665 | EFI_STATUS Status;\r | |
1666 | \r | |
1667 | //\r | |
1668 | // for ATAPI device, no need to wait DRDY ready after device selecting.\r | |
1669 | // (bit7 and bit5 are both set to 1 for backward compatibility)\r | |
1670 | //\r | |
1e23bd8d | 1671 | DeviceSelect = (UINT8) (((BIT7 | BIT5) | (IdeDev->Device << 4)));\r |
ead42efc | 1672 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r |
1673 | \r | |
1e23bd8d | 1674 | Command = ATA_CMD_SOFT_RESET;\r |
ead42efc | 1675 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);\r |
1676 | \r | |
1677 | //\r | |
1678 | // BSY cleared is the only status return to the host by the device\r | |
1679 | // when reset is completed.\r | |
1680 | // slave device needs at most 31s to clear BSY\r | |
1681 | //\r | |
1682 | Status = WaitForBSYClear (IdeDev, 31000);\r | |
1683 | if (EFI_ERROR (Status)) {\r | |
1684 | return EFI_DEVICE_ERROR;\r | |
1685 | }\r | |
1686 | \r | |
1687 | //\r | |
1688 | // stall 5 seconds to make the device status stable\r | |
1689 | //\r | |
1690 | gBS->Stall (5000000);\r | |
1691 | \r | |
1692 | return EFI_SUCCESS;\r | |
1693 | }\r | |
1694 | \r | |
1695 | /**\r | |
1696 | This function is the ATAPI implementation for ReadBlocks in the\r | |
1697 | Block I/O Protocol interface.\r | |
1698 | \r | |
630d580d | 1699 | @param IdeBlkIoDevice Indicates the calling context.\r |
1700 | @param MediaId The media id that the read request is for.\r | |
cd57e888 | 1701 | @param Lba The starting logical block address to read from on the device.\r |
630d580d | 1702 | @param BufferSize The size of the Buffer in bytes. This must be a multiple\r |
1703 | of the intrinsic block size of the device.\r | |
1704 | @param Buffer A pointer to the destination buffer for the data. The caller\r | |
1705 | is responsible for either having implicit or explicit \r | |
1706 | ownership of the memory that data is read into.\r | |
ead42efc | 1707 | \r |
630d580d | 1708 | @retval EFI_SUCCESS Read Blocks successfully.\r |
1709 | @retval EFI_DEVICE_ERROR Read Blocks failed.\r | |
1710 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
1711 | @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r | |
1712 | @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r | |
1713 | intrinsic block size of the device.\r | |
1714 | @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r | |
1715 | or the data buffer is not valid.\r | |
ead42efc | 1716 | **/\r |
1717 | EFI_STATUS\r | |
1718 | AtapiBlkIoReadBlocks (\r | |
1719 | IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r | |
1720 | IN UINT32 MediaId,\r | |
cd57e888 | 1721 | IN EFI_LBA Lba,\r |
ead42efc | 1722 | IN UINTN BufferSize,\r |
1723 | OUT VOID *Buffer\r | |
1724 | )\r | |
1725 | {\r | |
1726 | EFI_BLOCK_IO_MEDIA *Media;\r | |
1727 | UINTN BlockSize;\r | |
1728 | UINTN NumberOfBlocks;\r | |
1729 | EFI_STATUS Status;\r | |
1730 | \r | |
1731 | BOOLEAN MediaChange;\r | |
1732 | \r | |
1733 | if (Buffer == NULL) {\r | |
1734 | return EFI_INVALID_PARAMETER;\r | |
1735 | }\r | |
1736 | \r | |
1737 | if (BufferSize == 0) {\r | |
1738 | return EFI_SUCCESS;\r | |
1739 | }\r | |
1740 | \r | |
1741 | //\r | |
1742 | // ATAPI device media is removable, so it is a must\r | |
1743 | // to detect media first before read operation\r | |
1744 | //\r | |
1745 | MediaChange = FALSE;\r | |
1746 | Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r | |
1747 | if (EFI_ERROR (Status)) {\r | |
1748 | \r | |
1749 | if (IdeBlkIoDevice->Cache != NULL) {\r | |
1750 | gBS->FreePool (IdeBlkIoDevice->Cache);\r | |
1751 | IdeBlkIoDevice->Cache = NULL;\r | |
1752 | }\r | |
1753 | \r | |
1754 | return Status;\r | |
1755 | }\r | |
1756 | //\r | |
1757 | // Get the intrinsic block size\r | |
1758 | //\r | |
1759 | Media = IdeBlkIoDevice->BlkIo.Media;\r | |
1760 | BlockSize = Media->BlockSize;\r | |
1761 | \r | |
1762 | NumberOfBlocks = BufferSize / BlockSize;\r | |
1763 | \r | |
1764 | if (!(Media->MediaPresent)) {\r | |
1765 | \r | |
1766 | if (IdeBlkIoDevice->Cache != NULL) {\r | |
1767 | gBS->FreePool (IdeBlkIoDevice->Cache);\r | |
1768 | IdeBlkIoDevice->Cache = NULL;\r | |
1769 | }\r | |
1770 | return EFI_NO_MEDIA;\r | |
1771 | \r | |
1772 | }\r | |
1773 | \r | |
1774 | if ((MediaId != Media->MediaId) || MediaChange) {\r | |
1775 | \r | |
1776 | if (IdeBlkIoDevice->Cache != NULL) {\r | |
1777 | gBS->FreePool (IdeBlkIoDevice->Cache);\r | |
1778 | IdeBlkIoDevice->Cache = NULL;\r | |
1779 | }\r | |
1780 | return EFI_MEDIA_CHANGED;\r | |
1781 | }\r | |
1782 | \r | |
1783 | if (BufferSize % BlockSize != 0) {\r | |
1784 | return EFI_BAD_BUFFER_SIZE;\r | |
1785 | }\r | |
1786 | \r | |
cd57e888 | 1787 | if (Lba > Media->LastBlock) {\r |
ead42efc | 1788 | return EFI_INVALID_PARAMETER;\r |
1789 | }\r | |
1790 | \r | |
cd57e888 | 1791 | if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r |
ead42efc | 1792 | return EFI_INVALID_PARAMETER;\r |
1793 | }\r | |
1794 | \r | |
1795 | if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r | |
1796 | return EFI_INVALID_PARAMETER;\r | |
1797 | }\r | |
1798 | \r | |
1799 | //\r | |
1800 | // if all the parameters are valid, then perform read sectors command\r | |
1801 | // to transfer data from device to host.\r | |
1802 | //\r | |
cd57e888 | 1803 | Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
ead42efc | 1804 | if (EFI_ERROR (Status)) {\r |
1805 | return EFI_DEVICE_ERROR;\r | |
1806 | }\r | |
1807 | \r | |
1808 | //\r | |
1809 | // Read blocks succeeded\r | |
1810 | //\r | |
1811 | \r | |
1812 | //\r | |
1813 | // save the first block to the cache for performance\r | |
1814 | //\r | |
cd57e888 | 1815 | if (Lba == 0 && (IdeBlkIoDevice->Cache == NULL)) {\r |
ead42efc | 1816 | IdeBlkIoDevice->Cache = AllocatePool (BlockSize);\r |
261136bc | 1817 | if (IdeBlkIoDevice->Cache!= NULL) {\r |
ead42efc | 1818 | CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);\r |
1819 | }\r | |
1820 | }\r | |
1821 | \r | |
1822 | return EFI_SUCCESS;\r | |
1823 | \r | |
1824 | }\r | |
ead42efc | 1825 | /**\r |
1826 | This function is the ATAPI implementation for WriteBlocks in the\r | |
1827 | Block I/O Protocol interface.\r | |
1828 | \r | |
630d580d | 1829 | @param IdeBlkIoDevice Indicates the calling context.\r |
1830 | @param MediaId The media id that the write request is for.\r | |
cd57e888 | 1831 | @param Lba The starting logical block address to write onto the device.\r |
630d580d | 1832 | @param BufferSize The size of the Buffer in bytes. This must be a multiple\r |
1833 | of the intrinsic block size of the device.\r | |
1834 | @param Buffer A pointer to the source buffer for the data. The caller\r | |
1835 | is responsible for either having implicit or explicit ownership\r | |
1836 | of the memory that data is written from.\r | |
1837 | \r | |
1838 | @retval EFI_SUCCESS Write Blocks successfully.\r | |
1839 | @retval EFI_DEVICE_ERROR Write Blocks failed.\r | |
1840 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
1841 | @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r | |
1842 | @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r | |
1843 | intrinsic block size of the device. \r | |
1844 | @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r | |
1845 | or the data buffer is not valid.\r | |
1846 | \r | |
1847 | @retval EFI_WRITE_PROTECTED The write protected is enabled or the media does not support write\r | |
ead42efc | 1848 | **/\r |
1849 | EFI_STATUS\r | |
1850 | AtapiBlkIoWriteBlocks (\r | |
1851 | IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r | |
1852 | IN UINT32 MediaId,\r | |
cd57e888 | 1853 | IN EFI_LBA Lba,\r |
ead42efc | 1854 | IN UINTN BufferSize,\r |
1855 | OUT VOID *Buffer\r | |
1856 | )\r | |
1857 | {\r | |
1858 | \r | |
1859 | EFI_BLOCK_IO_MEDIA *Media;\r | |
1860 | UINTN BlockSize;\r | |
1861 | UINTN NumberOfBlocks;\r | |
1862 | EFI_STATUS Status;\r | |
1863 | BOOLEAN MediaChange;\r | |
1864 | \r | |
cd57e888 | 1865 | if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {\r |
ead42efc | 1866 | gBS->FreePool (IdeBlkIoDevice->Cache);\r |
1867 | IdeBlkIoDevice->Cache = NULL;\r | |
1868 | }\r | |
1869 | \r | |
1870 | if (Buffer == NULL) {\r | |
1871 | return EFI_INVALID_PARAMETER;\r | |
1872 | }\r | |
1873 | \r | |
1874 | if (BufferSize == 0) {\r | |
1875 | return EFI_SUCCESS;\r | |
1876 | }\r | |
1877 | \r | |
1878 | //\r | |
1879 | // ATAPI device media is removable,\r | |
1880 | // so it is a must to detect media first before write operation\r | |
1881 | //\r | |
1882 | MediaChange = FALSE;\r | |
1883 | Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r | |
1884 | if (EFI_ERROR (Status)) {\r | |
1885 | \r | |
cd57e888 | 1886 | if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {\r |
ead42efc | 1887 | gBS->FreePool (IdeBlkIoDevice->Cache);\r |
1888 | IdeBlkIoDevice->Cache = NULL;\r | |
1889 | }\r | |
1890 | return Status;\r | |
1891 | }\r | |
1892 | \r | |
1893 | //\r | |
1894 | // Get the intrinsic block size\r | |
1895 | //\r | |
1896 | Media = IdeBlkIoDevice->BlkIo.Media;\r | |
1897 | BlockSize = Media->BlockSize;\r | |
1898 | NumberOfBlocks = BufferSize / BlockSize;\r | |
1899 | \r | |
1900 | if (!(Media->MediaPresent)) {\r | |
1901 | \r | |
cd57e888 | 1902 | if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {\r |
ead42efc | 1903 | gBS->FreePool (IdeBlkIoDevice->Cache);\r |
1904 | IdeBlkIoDevice->Cache = NULL;\r | |
1905 | }\r | |
1906 | return EFI_NO_MEDIA;\r | |
1907 | }\r | |
1908 | \r | |
1909 | if ((MediaId != Media->MediaId) || MediaChange) {\r | |
1910 | \r | |
cd57e888 | 1911 | if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {\r |
ead42efc | 1912 | gBS->FreePool (IdeBlkIoDevice->Cache);\r |
1913 | IdeBlkIoDevice->Cache = NULL;\r | |
1914 | }\r | |
1915 | return EFI_MEDIA_CHANGED;\r | |
1916 | }\r | |
1917 | \r | |
1918 | if (Media->ReadOnly) {\r | |
1919 | return EFI_WRITE_PROTECTED;\r | |
1920 | }\r | |
1921 | \r | |
1922 | if (BufferSize % BlockSize != 0) {\r | |
1923 | return EFI_BAD_BUFFER_SIZE;\r | |
1924 | }\r | |
1925 | \r | |
cd57e888 | 1926 | if (Lba > Media->LastBlock) {\r |
ead42efc | 1927 | return EFI_INVALID_PARAMETER;\r |
1928 | }\r | |
1929 | \r | |
cd57e888 | 1930 | if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r |
ead42efc | 1931 | return EFI_INVALID_PARAMETER;\r |
1932 | }\r | |
1933 | \r | |
1934 | if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r | |
1935 | return EFI_INVALID_PARAMETER;\r | |
1936 | }\r | |
1937 | \r | |
1938 | //\r | |
1939 | // if all the parameters are valid,\r | |
1940 | // then perform write sectors command to transfer data from host to device.\r | |
1941 | //\r | |
cd57e888 | 1942 | Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
ead42efc | 1943 | if (EFI_ERROR (Status)) {\r |
1944 | return EFI_DEVICE_ERROR;\r | |
1945 | }\r | |
1946 | \r | |
1947 | return EFI_SUCCESS;\r | |
1948 | \r | |
1949 | }\r | |
1950 | \r | |
ead42efc | 1951 | \r |
ead42efc | 1952 | \r |