1 /** @file
2 Implementation of the EFI Block IO Protocol for ISA Floppy driver
3
4 Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "IsaFloppy.h"
16
17 /**
18 Reset the Block Device.
19
20 @param This Indicates a pointer to the calling context.
21 @param ExtendedVerification Driver may perform diagnostics on reset.
22
23 @retval EFI_SUCCESS The device was reset.
24 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
25 not be reset.
26 **/
27 EFI_STATUS
28 EFIAPI
FdcReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)29 FdcReset (
30 IN EFI_BLOCK_IO_PROTOCOL *This,
31 IN BOOLEAN ExtendedVerification
32 )
33 {
34 FDC_BLK_IO_DEV *FdcDev;
35
36 //
37 // Reset the Floppy Disk Controller
38 //
39 FdcDev = FDD_BLK_IO_FROM_THIS (This);
40
41 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
42 EFI_PROGRESS_CODE,
43 EFI_P_PC_RESET | EFI_PERIPHERAL_REMOVABLE_MEDIA,
44 FdcDev->DevicePath
45 );
46
47 return FddReset (FdcDev);
48 }
49
50 /**
51 Flush the Block Device.
52
53 @param This Indicates a pointer to the calling context.
54
55 @retval EFI_SUCCESS All outstanding data was written to the device
56 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
57 @retval EFI_NO_MEDIA There is no media in the device.
58
59 **/
60 EFI_STATUS
61 EFIAPI
FddFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)62 FddFlushBlocks (
63 IN EFI_BLOCK_IO_PROTOCOL *This
64 )
65 {
66 //
67 // Not supported yet
68 //
69 return EFI_SUCCESS;
70 }
71
72 /**
73 Common report status code interface.
74
75 @param This Pointer of FDC_BLK_IO_DEV instance
76 @param Read Read or write operation when error occurrs
77 **/
78 VOID
FddReportStatus(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN Read)79 FddReportStatus (
80 IN EFI_BLOCK_IO_PROTOCOL *This,
81 IN BOOLEAN Read
82 )
83 {
84 FDC_BLK_IO_DEV *FdcDev;
85
86 FdcDev = FDD_BLK_IO_FROM_THIS (This);
87
88 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
89 EFI_ERROR_CODE,
90 ((Read) ? EFI_P_EC_INPUT_ERROR : EFI_P_EC_OUTPUT_ERROR) | EFI_PERIPHERAL_REMOVABLE_MEDIA,
91 FdcDev->DevicePath
92 );
93 }
94
95 /**
96 Read BufferSize bytes from Lba into Buffer.
97
98 @param This Indicates a pointer to the calling context.
99 @param MediaId Id of the media, changes every time the media is replaced.
100 @param Lba The starting Logical Block Address to read from
101 @param BufferSize Size of Buffer, must be a multiple of device block size.
102 @param Buffer A pointer to the destination buffer for the data. The caller is
103 responsible for either having implicit or explicit ownership of the buffer.
104
105 @retval EFI_SUCCESS The data was read correctly from the device.
106 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
107 @retval EFI_NO_MEDIA There is no media in the device.
108 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
109 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
110 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
111 or the buffer is not on proper alignment.
112
113 **/
114 EFI_STATUS
115 EFIAPI
FddReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,OUT VOID * Buffer)116 FddReadBlocks (
117 IN EFI_BLOCK_IO_PROTOCOL *This,
118 IN UINT32 MediaId,
119 IN EFI_LBA Lba,
120 IN UINTN BufferSize,
121 OUT VOID *Buffer
122 )
123 {
124 EFI_STATUS Status;
125
126 Status = FddReadWriteBlocks (This, MediaId, Lba, BufferSize, READ, Buffer);
127
128 if (EFI_ERROR (Status)) {
129 FddReportStatus (This, TRUE);
130 }
131
132 return Status;
133 }
134
135 /**
136 Write BufferSize bytes from Lba into Buffer.
137
138 @param This Indicates a pointer to the calling context.
139 @param MediaId The media ID that the write request is for.
140 @param Lba The starting logical block address to be written. The caller is
141 responsible for writing to only legitimate locations.
142 @param BufferSize Size of Buffer, must be a multiple of device block size.
143 @param Buffer A pointer to the source buffer for the data.
144
145 @retval EFI_SUCCESS The data was written correctly to the device.
146 @retval EFI_WRITE_PROTECTED The device can not be written to.
147 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
148 @retval EFI_NO_MEDIA There is no media in the device.
149 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
150 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
151 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
152 or the buffer is not on proper alignment.
153
154 **/
155 EFI_STATUS
156 EFIAPI
FddWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer)157 FddWriteBlocks (
158 IN EFI_BLOCK_IO_PROTOCOL *This,
159 IN UINT32 MediaId,
160 IN EFI_LBA Lba,
161 IN UINTN BufferSize,
162 IN VOID *Buffer
163 )
164 {
165 EFI_STATUS Status;
166
167 Status = FddReadWriteBlocks (This, MediaId, Lba, BufferSize, WRITE, Buffer);
168
169 if (EFI_ERROR (Status)) {
170 FddReportStatus (This, FALSE);
171 }
172
173 return Status;
174 }
175
176 /**
177 Read or Write a number of blocks to floppy disk
178
179 @param This Indicates a pointer to the calling context.
180 @param MediaId Id of the media, changes every time the media is replaced.
181 @param Lba The starting Logical Block Address to read from
182 @param BufferSize Size of Buffer, must be a multiple of device block size.
183 @param Operation Specifies the read or write operation.
184 @param Buffer A pointer to the destination buffer for the data. The caller is
185 responsible for either having implicit or explicit ownership of the buffer.
186
187 @retval EFI_SUCCESS The data was read correctly from the device.
188 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
189 @retval EFI_NO_MEDIA There is no media in the device.
190 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
191 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
192 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
193 or the buffer is not on proper alignment.
194 @retval EFI_WRITE_PROTECTED The device can not be written to.
195
196 **/
197 EFI_STATUS
FddReadWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN BOOLEAN Operation,OUT VOID * Buffer)198 FddReadWriteBlocks (
199 IN EFI_BLOCK_IO_PROTOCOL *This,
200 IN UINT32 MediaId,
201 IN EFI_LBA Lba,
202 IN UINTN BufferSize,
203 IN BOOLEAN Operation,
204 OUT VOID *Buffer
205 )
206 {
207 EFI_BLOCK_IO_MEDIA *Media;
208 FDC_BLK_IO_DEV *FdcDev;
209 UINTN BlockSize;
210 UINTN NumberOfBlocks;
211 UINTN BlockCount;
212 EFI_STATUS Status;
213 EFI_LBA Lba0;
214 UINT8 *Pointer;
215
216 //
217 // Get the intrinsic block size
218 //
219 Media = This->Media;
220 BlockSize = Media->BlockSize;
221 FdcDev = FDD_BLK_IO_FROM_THIS (This);
222
223 if (Operation == WRITE) {
224 if (Lba == 0) {
225 FdcFreeCache (FdcDev);
226 }
227 }
228
229 //
230 // Set the drive motor on
231 //
232 Status = MotorOn (FdcDev);
233 if (EFI_ERROR (Status)) {
234 return EFI_DEVICE_ERROR;
235 }
236 //
237 // Check to see if media can be detected
238 //
239 Status = DetectMedia (FdcDev);
240 if (EFI_ERROR (Status)) {
241 MotorOff (FdcDev);
242 FdcFreeCache (FdcDev);
243 return EFI_DEVICE_ERROR;
244 }
245 //
246 // Check to see if media is present
247 //
248 if (!(Media->MediaPresent)) {
249 MotorOff (FdcDev);
250 FdcFreeCache (FdcDev);
251 return EFI_NO_MEDIA;
252 }
253 //
254 // Check to see if media has been changed
255 //
256 if (MediaId != Media->MediaId) {
257 MotorOff (FdcDev);
258 FdcFreeCache (FdcDev);
259 return EFI_MEDIA_CHANGED;
260 }
261
262 if (BufferSize == 0) {
263 MotorOff (FdcDev);
264 return EFI_SUCCESS;
265 }
266
267 if (Operation == WRITE) {
268 if (Media->ReadOnly) {
269 MotorOff (FdcDev);
270 return EFI_WRITE_PROTECTED;
271 }
272 }
273 //
274 // Check the parameters for this read/write operation
275 //
276 if (Buffer == NULL) {
277 MotorOff (FdcDev);
278 return EFI_INVALID_PARAMETER;
279 }
280
281 if (BufferSize % BlockSize != 0) {
282 MotorOff (FdcDev);
283 return EFI_BAD_BUFFER_SIZE;
284 }
285
286 if (Lba > Media->LastBlock) {
287 MotorOff (FdcDev);
288 return EFI_INVALID_PARAMETER;
289 }
290
291 if (((BufferSize / BlockSize) + Lba - 1) > Media->LastBlock) {
292 MotorOff (FdcDev);
293 return EFI_INVALID_PARAMETER;
294 }
295
296 if (Operation == READ) {
297 //
298 // See if the data that is being read is already in the cache
299 //
300 if (FdcDev->Cache != NULL) {
301 if (Lba == 0 && BufferSize == BlockSize) {
302 MotorOff (FdcDev);
303 CopyMem ((UINT8 *) Buffer, (UINT8 *) FdcDev->Cache, BlockSize);
304 return EFI_SUCCESS;
305 }
306 }
307 }
308 //
309 // Set up Floppy Disk Controller
310 //
311 Status = Setup (FdcDev);
312 if (EFI_ERROR (Status)) {
313 MotorOff (FdcDev);
314 return EFI_DEVICE_ERROR;
315 }
316
317 NumberOfBlocks = BufferSize / BlockSize;
318 Lba0 = Lba;
319 Pointer = Buffer;
320
321 //
322 // read blocks in the same cylinder.
323 // in a cylinder , there are 18 * 2 = 36 blocks
324 //
325 BlockCount = GetTransferBlockCount (FdcDev, Lba, NumberOfBlocks);
326 while ((BlockCount != 0) && !EFI_ERROR (Status)) {
327 Status = ReadWriteDataSector (FdcDev, Buffer, Lba, BlockCount, Operation);
328 if (EFI_ERROR (Status)) {
329 MotorOff (FdcDev);
330 FddReset (FdcDev);
331 return EFI_DEVICE_ERROR;
332 }
333
334 Lba += BlockCount;
335 NumberOfBlocks -= BlockCount;
336 Buffer = (VOID *) ((UINTN) Buffer + BlockCount * BlockSize);
337 BlockCount = GetTransferBlockCount (FdcDev, Lba, NumberOfBlocks);
338 }
339
340 Buffer = Pointer;
341
342 //
343 // Turn the motor off
344 //
345 MotorOff (FdcDev);
346
347 if (Operation == READ) {
348 //
349 // Cache the data read
350 //
351 if (Lba0 == 0 && FdcDev->Cache == NULL) {
352 FdcDev->Cache = AllocateCopyPool (BlockSize, Buffer);
353 }
354 }
355
356 return EFI_SUCCESS;
357
358 }
359
360 /**
361 Free cache for a floppy disk.
362
363 @param FdcDev A Pointer to FDC_BLK_IO_DEV instance
364
365 **/
366 VOID
FdcFreeCache(IN FDC_BLK_IO_DEV * FdcDev)367 FdcFreeCache (
368 IN FDC_BLK_IO_DEV *FdcDev
369 )
370 {
371 if (FdcDev->Cache != NULL) {
372 FreePool (FdcDev->Cache);
373 FdcDev->Cache = NULL;
374 }
375 }
376