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