1 /*
2 
3     File: msdos.c
4 
5     Copyright (C) 1998-2008 Christophe GRENIER <grenier@cgsecurity.org>
6 
7     This software is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License along
18     with this program; if not, write the Free Software Foundation, Inc., 51
19     Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 
21  */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #ifdef DJGPP
26 #include <stdio.h>
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30 #include <errno.h>
31 #include "types.h"
32 #include "common.h"
33 #include <go32.h>       /* dosmemget/put */
34 #include <dpmi.h>
35 #include <bios.h>       /* bios_k* */
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>     /* atexit, posix_memalign */
38 #endif
39 #include "msdos.h"
40 #include "fnctdsk.h"
41 #include "log.h"
42 #include "hdaccess.h"
43 #include "alignio.h"
44 
45 #define HD_RW_BUF_SIZ 0x10
46 #define HDPARM_BUF_SIZ 0x1A
47 #define MAX_IO_NBR 3
48 #define MAX_HD_ERR 100
49 
50 extern const arch_fnct_t arch_none;
51 
52 static void free_dos_buffer(void);
53 static int alloc_cmd_dos_buffer(void);
54 static int hd_identify_enh_bios(disk_t *param_disk,const int verbose);
55 static int check_enh_bios(const unsigned int disk, const int verbose);
56 static int hd_report_error(disk_t *disk_car, const uint64_t hd_offset, const unsigned int count, const int rc);
57 static const char *disk_description_short(disk_t *disk_car);
58 static int disk_pread(disk_t *disk_car, void *buf, const unsigned int count, const uint64_t hd_offset);
59 static int disk_pwrite(disk_t *disk_car, const void *buf, const unsigned int count, const uint64_t hd_offset);
60 static int disk_nopwrite(disk_t *disk_car, const void *buf, const unsigned int count, const uint64_t offset);
61 static int disk_sync(disk_t *disk_car);
62 static void disk_clean(disk_t *disk_car);
63 
64 static int cmd_dos_segment = 0;
65 static int cmd_dos_selector = 0;
66 
free_dos_buffer(void)67 static void free_dos_buffer(void)
68 {
69   __dpmi_free_dos_memory(cmd_dos_selector);
70   cmd_dos_segment = cmd_dos_selector = 0;
71 }
72 
alloc_cmd_dos_buffer(void)73 static int alloc_cmd_dos_buffer(void)
74 {
75   if (cmd_dos_segment)
76     return 0;
77   if ((cmd_dos_segment = __dpmi_allocate_dos_memory(18*DEFAULT_SECTOR_SIZE/16, &cmd_dos_selector))== -1)
78   {
79     cmd_dos_segment = 0;
80     return 1;
81   }
82 #ifdef HAVE_ATEXIT
83   atexit(free_dos_buffer);
84 #endif
85   return 0;
86 }
87 
disk_reset_error(disk_t * disk_car)88 static void disk_reset_error(disk_t *disk_car)
89 {
90   struct info_disk_struct *data=(struct info_disk_struct *)disk_car->data;
91   biosdisk(0, data->disk, 0, 0, 1, 1, NULL);
92 }
93 
hd_pread(disk_t * disk_car,void * buf,const unsigned int count,const uint64_t offset)94 static int hd_pread(disk_t *disk_car, void *buf, const unsigned int count, const uint64_t offset)
95 {
96   __dpmi_regs r;
97   unsigned char buf_cmd[HD_RW_BUF_SIZ];
98   int xfer_dos_segment, xfer_dos_selector;
99   int nsects;
100   unsigned long int hd_offset;
101   struct info_disk_struct *data=(struct info_disk_struct *)disk_car->data;
102   nsects=count/disk_car->sector_size;
103   hd_offset=offset/disk_car->sector_size;
104   if(data->mode_enh==0)
105   { /* Limite CHS = 1023,255,63 = 8,064Mo ~= 7.8 Go */
106     int head, track, sector;
107     if(data->geo_phys.sectors_per_head==0)
108     {
109       log_critical("hd_pread: BUG geo_phys.sectors_per_head=0 !\n");
110       return -1;
111     }
112     sector=(hd_offset%data->geo_phys.sectors_per_head)+1;
113     hd_offset/=data->geo_phys.sectors_per_head;
114     head=hd_offset%data->geo_phys.heads_per_cylinder;
115     track=hd_offset/data->geo_phys.heads_per_cylinder;
116     if(track<1024)
117     {
118       const int res=biosdisk(2, data->disk, head, track, sector, nsects, buf);
119       return (res!=0 ? -res: count);
120     }
121     return -1;
122   }
123   if(cmd_dos_segment==0)
124     if(alloc_cmd_dos_buffer())
125       return -1;
126   if ( (xfer_dos_segment=__dpmi_allocate_dos_memory((count + 15) >> 4, &xfer_dos_selector)) == -1 )
127     return -1;
128   *(uint16_t*)&buf_cmd[0]=HD_RW_BUF_SIZ;
129   *(uint16_t*)&buf_cmd[2]=nsects;
130   *(uint32_t*)&buf_cmd[0x4]=xfer_dos_segment<<16;
131   *(uint32_t*)&buf_cmd[0x8]=hd_offset;
132   *(uint32_t*)&buf_cmd[0xC]=0;
133 
134   r.x.ds = cmd_dos_segment;
135   r.x.si = 0;
136   r.h.dl = data->disk;
137   r.h.ah = 0x42;        /* Extended read */
138   dosmemput(&buf_cmd, HD_RW_BUF_SIZ, cmd_dos_segment<<4);
139   __dpmi_int(0x13, &r);
140   dosmemget(xfer_dos_segment<<4, count, buf);
141   __dpmi_free_dos_memory(xfer_dos_selector);
142   return (r.h.ah!=0 ? -r.h.ah : count);
143 }
144 
hd_pwrite(disk_t * disk_car,const void * buf,const unsigned int count,const uint64_t offset)145 static int hd_pwrite(disk_t *disk_car, const void *buf, const unsigned int count, const uint64_t offset)
146 {
147   __dpmi_regs r;
148   unsigned char buf_cmd[HD_RW_BUF_SIZ];
149   int xfer_dos_segment, xfer_dos_selector;
150   int nsects;
151   unsigned long int hd_offset;
152   struct info_disk_struct *data=(struct info_disk_struct *)disk_car->data;
153   nsects=count/disk_car->sector_size;
154   hd_offset=offset/disk_car->sector_size;
155 
156   if(data->mode_enh==0)
157   { /* Limite CHS = 1023,255,63 = 8,064Mo ~= 7.8 Go */
158     int head, track, sector;
159     if(data->geo_phys.sectors_per_head==0)
160     {
161       log_critical("hd_pwrite: BUG geo_phys.sectors_per_head=0 !\n");
162       return -1;
163     }
164     sector=(hd_offset%data->geo_phys.sectors_per_head)+1;
165     hd_offset/=data->geo_phys.sectors_per_head;
166     head=hd_offset%data->geo_phys.heads_per_cylinder;
167     track=hd_offset/data->geo_phys.heads_per_cylinder;
168     if(track<1024)
169     {
170       const int res=biosdisk(3, data->disk, head, track, sector, nsects, buf);
171       return (res!=0 ? -res : count);
172     }
173     return -1;
174   }
175   if(cmd_dos_segment==0)
176     if(alloc_cmd_dos_buffer())
177       return -1;
178   if ( (xfer_dos_segment=__dpmi_allocate_dos_memory((count + 15) >> 4, &xfer_dos_selector)) == -1 )
179     return -1;
180   *(uint16_t*)&buf_cmd[0]=HD_RW_BUF_SIZ;
181   *(uint16_t*)&buf_cmd[2]=nsects;
182   *(uint32_t*)&buf_cmd[0x4]=xfer_dos_segment<<16;
183   *(uint32_t*)&buf_cmd[0x8]=hd_offset;
184   *(uint32_t*)&buf_cmd[0xC]=0;
185 
186   r.x.ds = cmd_dos_segment;
187   r.x.si = 0;
188   r.h.dl = data->disk;
189   r.x.ax = 0x4300;
190   dosmemput(buf, count, xfer_dos_segment<<4);
191   dosmemput(&buf_cmd, HD_RW_BUF_SIZ, cmd_dos_segment<<4);
192   __dpmi_int(0x13, &r);
193   __dpmi_free_dos_memory(xfer_dos_selector);
194   return (r.h.ah!=0 ? -r.h.ah : count);
195 }
196 
check_enh_bios(const unsigned int disk,const int verbose)197 static int check_enh_bios(const unsigned int disk, const int verbose)
198 {
199   __dpmi_regs r;
200   r.h.ah = 0x41;
201   r.x.bx = 0x55AA;
202   r.h.dl = disk;
203   __dpmi_int(0x13, &r);
204   if(r.x.bx != 0xAA55)  /* INT 13 Extensions not installed */
205   {
206     if(verbose>0)
207       log_warning("Disk %02X - INT 13 Extensions not installed\n",disk);
208     return 0;
209   }
210   if(verbose>0)
211   {
212     log_info("Disk %02X ",disk);
213     switch(r.h.ah)
214     {
215       case 0x01:
216 	log_info("Enhanced BIOS 1.x");
217 	break;
218       case 0x20:
219 	log_info("Enhanced BIOS 2.0 / EDD-1.0");
220 	break;
221       case 0x21:
222 	log_info("Enhanced BIOS 2.1 / EDD-1.1");
223 	break;
224       case 0x30:
225 	log_info("Enhanced BIOS EDD-3.0");
226 	break;
227       default:
228 	log_info("Enhanced BIOS unknown %02X",r.h.ah);
229 	break;
230     }
231     if((r.x.cx & 1)!=0)
232       log_info(" - R/W/I");
233     if((r.x.cx & 4)!=0)
234       log_info(" - Identify");
235     log_info("\n");
236   }
237   return ((r.x.cx&1)!=0);
238 }
239 
hd_identify_enh_bios(disk_t * disk_car,const int verbose)240 static int hd_identify_enh_bios(disk_t *disk_car,const int verbose)
241 {
242   uint64_t computed_size;
243   int compute_LBA=0;
244   __dpmi_regs r;
245   unsigned char buf[0x200];	/* Don't change it! */
246   struct info_disk_struct *data=(struct info_disk_struct *)disk_car->data;
247   if(cmd_dos_segment==0)
248     if(alloc_cmd_dos_buffer())
249       return 1;
250   buf[0]=HDPARM_BUF_SIZ;
251   buf[1]=0;
252   r.h.ah = 0x48;
253   r.x.ds = cmd_dos_segment;
254   r.x.si = 0;
255   r.h.dl = data->disk;
256   dosmemput(&buf, HDPARM_BUF_SIZ, cmd_dos_segment<<4);
257   __dpmi_int(0x13, &r);
258   dosmemget(cmd_dos_segment<<4, HDPARM_BUF_SIZ, &buf);
259   if(r.h.ah)
260     return 1;
261   disk_car->geom.cylinders=*(uint16_t*)&buf[0x04];
262   disk_car->geom.heads_per_cylinder=*(uint16_t*)&buf[0x08];
263   disk_car->geom.sectors_per_head=*(uint16_t*)&buf[0x0C];
264   disk_car->disk_size=(*(uint32_t*)&buf[0x10])*(uint64_t)disk_car->sector_size;
265   if(disk_car->disk_size==0)
266   {
267     if(disk_car->geom.cylinders==0 || disk_car->geom.heads_per_cylinder==0 || disk_car->geom.sectors_per_head==0)
268     {
269       if(verbose>0)
270 	log_warning("hd_identify_enh_bios: No size returned by BIOS.\n");
271       return 1;
272     }
273     else
274     {
275       compute_LBA=1;
276       disk_car->disk_size=(uint64_t)disk_car->geom.cylinders*disk_car->geom.heads_per_cylinder*disk_car->geom.sectors_per_head*disk_car->sector_size;
277       if(verbose>0)
278         log_verbose("Computes LBA from CHS\n");
279     }
280   }
281   else
282   {
283     if(disk_car->geom.cylinders>0 && disk_car->geom.heads_per_cylinder>0 && disk_car->geom.sectors_per_head>0)
284     {
285       /* Some bios are buggy */
286       if(disk_car->disk_size>(uint64_t)(disk_car->geom.cylinders+1)*disk_car->geom.heads_per_cylinder*disk_car->geom.sectors_per_head*disk_car->sector_size)
287       {
288         disk_car->geom.cylinders=disk_car->disk_size /
289 	  disk_car->geom.heads_per_cylinder /
290 	  disk_car->geom.sectors_per_head /
291 	  disk_car->sector_size;
292         if(verbose>0)
293           log_verbose("Computes C from number of sectors\n");
294       }
295     }
296     else
297     {
298       if(verbose>0)
299         log_verbose("Computes CHS from number of sectors\n");
300       disk_car->geom.heads_per_cylinder=255;
301       disk_car->geom.sectors_per_head=63;
302       disk_car->geom.cylinders=disk_car->disk_size /
303 	disk_car->geom.heads_per_cylinder /
304 	disk_car->geom.sectors_per_head /
305 	disk_car->sector_size;
306     }
307   }
308   if(disk_car->geom.sectors_per_head==0)
309   {
310     data->bad_geometry=1;
311     disk_car->geom.sectors_per_head=1;
312     log_critical("Incorrect number of sectors\n");
313   }
314   if(disk_car->geom.sectors_per_head>63)
315   {
316 /*    data->bad_geometry=1; */
317     log_critical("Incorrect number of sectors\n");
318   }
319   if(disk_car->geom.heads_per_cylinder>255)
320   {
321     data->bad_geometry=1;
322     log_critical("Incorrect number of heads\n");
323   }
324   computed_size=(uint64_t)disk_car->geom.cylinders*disk_car->geom.heads_per_cylinder*disk_car->geom.sectors_per_head*disk_car->sector_size;
325   if(verbose>0 || data->bad_geometry!=0)
326     log_info("LBA %lu, computed %lu (CHS=%lu,%u,%u)\n",
327 	(long unsigned)(disk_car->disk_size/disk_car->sector_size),
328 	(long unsigned)(computed_size/disk_car->sector_size),
329 	disk_car->geom.cylinders,
330 	disk_car->geom.heads_per_cylinder,
331 	disk_car->geom.sectors_per_head);
332   if(compute_LBA)
333     disk_car->disk_size=computed_size;
334   else
335   {
336     if(disk_car->disk_size < computed_size)
337     {
338       log_info("Computes LBA from CHS, previous value may be false.\n");
339       disk_car->disk_size=computed_size;
340     }
341   }
342   disk_car->disk_real_size=disk_car->disk_size;
343   data->geo_phys.cylinders=disk_car->geom.cylinders;
344   data->geo_phys.heads_per_cylinder=disk_car->geom.heads_per_cylinder;
345   data->geo_phys.sectors_per_head=disk_car->geom.sectors_per_head;
346   if(verbose>0)
347   {
348     log_info("hd_identify_enh_bios\n");
349     log_info("%s\n",disk_description(disk_car));
350     log_info("LBA size=%lu\n",(long unsigned)(disk_car->disk_size/disk_car->sector_size));
351   }
352   return 0;
353 }
354 
hd_identify(const int verbose,const unsigned int disk,const int testdisk_mode)355 disk_t *hd_identify(const int verbose, const unsigned int disk, const int testdisk_mode)
356 {
357   unsigned char buf[0x200];
358   memset(buf,0,sizeof(buf));
359   /* standard BIOS access */
360   if(biosdisk(8,disk,0,0,1,1,buf))
361     return NULL;
362   if(verbose>1)
363     log_verbose("Disk %02X %u max %02X\n",disk,buf[2],(0x80+buf[2]-1));
364   if(disk>(unsigned int)(0x80+buf[2]-1))
365     return NULL;
366   {
367     char device[100];
368     struct info_disk_struct*data=(struct info_disk_struct*)MALLOC(sizeof(*data));
369     disk_t *disk_car=(disk_t *)MALLOC(sizeof(*disk_car));
370     data->disk=disk;
371     data->bad_geometry=0;
372     data->mode_enh=0;
373     disk_car->arch=&arch_none;
374     snprintf(device,sizeof(device),"/dev/sda%u",disk);
375     disk_car->device=strdup(device);
376     disk_car->model=NULL;
377     disk_car->write_used=0;
378     disk_car->autodetect=0;
379     disk_car->sector_size=DEFAULT_SECTOR_SIZE;
380     disk_car->description=disk_description;
381     disk_car->description_short=disk_description_short;
382     disk_car->pread=disk_pread;
383     disk_car->pwrite=((testdisk_mode&TESTDISK_O_RDWR)==TESTDISK_O_RDWR?disk_pwrite:disk_nopwrite);
384     disk_car->sync=disk_sync;
385     disk_car->access_mode=testdisk_mode;
386     disk_car->clean=disk_clean;
387     disk_car->data=data;
388     disk_car->geom.cylinders=1+(((buf[0] & 0x0C0)<<2)|buf[1]);
389     disk_car->geom.heads_per_cylinder=1+buf[3];
390     disk_car->geom.sectors_per_head=buf[0] & 0x3F;
391     if(disk_car->geom.heads_per_cylinder>255)
392     { /* Problem found by G Rowe */
393       log_critical("BIOS reports an invalid heads number\n");
394       data->bad_geometry=1;
395       disk_car->geom.heads_per_cylinder=255;
396     }
397     if(disk_car->geom.sectors_per_head==0)
398     { /* Problem found by Brian Barrett */
399       log_critical("BIOS reports an invalid number of sectors per head\n");
400       data->bad_geometry=1;
401       disk_car->geom.sectors_per_head=1;
402     }
403     disk_car->disk_size=(uint64_t)disk_car->geom.cylinders*disk_car->geom.heads_per_cylinder*disk_car->geom.sectors_per_head*disk_car->sector_size;
404     disk_car->disk_real_size=disk_car->disk_size;
405     data->geo_phys.cylinders=disk_car->geom.cylinders;
406     data->geo_phys.heads_per_cylinder=disk_car->geom.heads_per_cylinder;
407     data->geo_phys.sectors_per_head=disk_car->geom.sectors_per_head;
408     if(verbose>0)
409       log_info("%s\n",disk_description(disk_car));
410     if(check_enh_bios(disk,verbose))
411     {
412       /* enhanced BIOS access */
413       disk_t *param_disk_enh=(disk_t*)MALLOC(sizeof(*param_disk_enh));
414       param_disk_enh->write_used=0;
415       param_disk_enh->sector_size=disk_car->sector_size;
416       param_disk_enh->data=data;
417       data->mode_enh=1;
418       if(!hd_identify_enh_bios(param_disk_enh,verbose))
419       {
420 	/* standard geometry H,S, compute C from LBA */
421 	disk_car->disk_size=param_disk_enh->disk_size;
422 	disk_car->disk_real_size=disk_car->disk_size;
423 	disk_car->geom.cylinders=(disk_car->disk_size/disk_car->geom.heads_per_cylinder)/disk_car->geom.sectors_per_head/disk_car->sector_size;
424       }
425       else
426 	data->mode_enh=0;
427       free(param_disk_enh);
428     }
429     disk_car->unit=UNIT_CHS;
430     return disk_car;
431   }
432 }
433 
disk_description(disk_t * disk_car)434 const char *disk_description(disk_t *disk_car)
435 {
436   struct info_disk_struct *data=(struct info_disk_struct *)disk_car->data;
437   char buffer_disk_size[100];
438   size_to_unit(disk_car->disk_size, buffer_disk_size),
439   snprintf(disk_car->description_txt, sizeof(disk_car->description_txt),"Disk %2x - %s - CHS %lu %u %u%s",
440       data->disk, buffer_disk_size,
441       disk_car->geom.cylinders, disk_car->geom.heads_per_cylinder, disk_car->geom.sectors_per_head,
442       data->bad_geometry!=0?" (Buggy BIOS)":"");
443   return disk_car->description_txt;
444 }
445 
disk_description_short(disk_t * disk_car)446 static const char *disk_description_short(disk_t *disk_car)
447 {
448   struct info_disk_struct *data=(struct info_disk_struct *)disk_car->data;
449   char buffer_disk_size[100];
450   size_to_unit(disk_car->disk_size, buffer_disk_size);
451   snprintf(disk_car->description_short_txt, sizeof(disk_car->description_txt),"Disk %2x - %s",
452       data->disk, buffer_disk_size);
453   return disk_car->description_short_txt;
454 }
455 
disk_pread_aux(disk_t * disk_car,void * buf,const unsigned int count,const uint64_t offset)456 static int disk_pread_aux(disk_t *disk_car, void *buf, const unsigned int count, const uint64_t offset)
457 {
458   struct info_disk_struct *data=(struct info_disk_struct *)disk_car->data;
459   if(data->geo_phys.cylinders>0 && offset+count>disk_car->disk_size)
460   {
461     log_error("disk_pread_aux: Don't read after the end of the disk\n");
462     return -1;
463   }
464   {
465     uint64_t read_offset=0;
466     do
467     {
468       int i=0;
469       int rc;
470       unsigned int read_size;
471       read_size=count-read_offset>16*512?16*512:count-read_offset;
472       do
473       {
474         rc=hd_pread(disk_car, (char*)buf+read_offset, read_size, offset+read_offset);
475         if(rc < 0)
476           disk_reset_error(disk_car);
477       } while(rc!=read_size && rc!=-1 && ++i<MAX_IO_NBR);
478       // <0 invalid function in AH or invalid parameter
479       if(rc < 0)
480       {
481         log_error("disk_pread_aux failed ");
482         hd_report_error(disk_car, offset, count, -rc);
483       }
484       if(rc != read_size)
485 	return (read_offset==0 ? rc : read_offset);
486       read_offset+=read_size;
487     } while(read_offset<count);
488   }
489   return count;
490 }
491 
disk_pread(disk_t * disk_car,void * buf,const unsigned int count,const uint64_t offset)492 static int disk_pread(disk_t *disk_car, void *buf, const unsigned int count, const uint64_t offset)
493 {
494   return align_pread(&disk_pread_aux, disk_car, buf, count, offset);
495 }
496 
disk_pwrite_aux(disk_t * disk_car,const void * buf,const unsigned int count,const uint64_t hd_offset)497 static int disk_pwrite_aux(disk_t *disk_car, const void *buf, const unsigned int count, const uint64_t hd_offset)
498 {
499   int i=0;
500   int rc;
501   disk_car->write_used=1;
502   {
503     rc=hd_pwrite(disk_car, buf, count, hd_offset);
504     if(rc < 0)
505       disk_reset_error(disk_car);
506   } while(rc==-4 && ++i<MAX_IO_NBR);
507   /* 4=sector not found/read error */
508   if(rc < 0)
509   {
510     log_error("disk_pwrite error\n");
511     hd_report_error(disk_car, hd_offset, count, -rc);
512   }
513   return rc;
514 }
515 
disk_pwrite(disk_t * disk_car,const void * buf,const unsigned int count,const uint64_t offset)516 static int disk_pwrite(disk_t *disk_car, const void *buf, const unsigned int count, const uint64_t offset)
517 {
518   return align_pwrite(&disk_pread_aux, &disk_pwrite_aux, disk_car, buf, count, offset);
519 }
520 
disk_nopwrite(disk_t * disk_car,const void * buf,const unsigned int count,const uint64_t offset)521 static int disk_nopwrite(disk_t *disk_car, const void *buf, const unsigned int count, const uint64_t offset)
522 {
523   struct info_disk_struct *data=(struct info_disk_struct *)disk_car->data;
524   log_warning("disk_nopwrite(%d,%u,buffer,%lu(%u/%u/%u)) write refused\n", data->disk,
525       (unsigned)(count/disk_car->sector_size),(long unsigned)(offset/disk_car->sector_size),
526       offset2cylinder(disk_car,offset),offset2head(disk_car,offset),offset2sector(disk_car,offset));
527   return -1;
528 }
529 
disk_sync(disk_t * disk_car)530 static int disk_sync(disk_t *disk_car)
531 {
532   errno=EINVAL;
533   return -1;
534 }
535 
disk_clean(disk_t * disk_car)536 static void disk_clean(disk_t *disk_car)
537 {
538   /*
539   if(disk_car->data!=NULL)
540   {
541     struct info_disk_struct *data=disk_car->data;
542   }
543   */
544   generic_clean(disk_car);
545 }
546 
hd_report_error(disk_t * disk_car,const uint64_t hd_offset,const unsigned int count,const int rc)547 static int hd_report_error(disk_t *disk_car, const uint64_t hd_offset, const unsigned int count, const int rc)
548 {
549   log_error(" lba=%lu(%u/%u/%u) nbr_sector=%u, rc=%d\n",(long unsigned int)(hd_offset/disk_car->sector_size),
550       offset2cylinder(disk_car,hd_offset),offset2head(disk_car,hd_offset),offset2sector(disk_car,hd_offset),
551       count/disk_car->sector_size,rc);
552   switch(rc)
553   {
554     case 0x00: log_error("successful completion"); break;
555     case 0x01: log_error("invalid function in AH or invalid parameter"); break;
556     case 0x02: log_error("address mark not found"); break;
557     case 0x03: log_error("disk write-protected"); break;
558     case 0x04: log_error("sector not found/read error"); break;
559     case 0x05: log_error("reset failed (hard disk)"); break;
560     case 0x06: log_error("disk changed (floppy)"); break;
561     case 0x07: log_error("drive parameter activity failed (hard disk)"); break;
562     case 0x08: log_error("DMA overrun"); break;
563     case 0x09: log_error("data boundary error (attempted DMA across 64K boundary or >80h sectors)"); break;
564     case 0x0A: log_error("bad sector detected (hard disk)"); break;
565     case 0x0B: log_error("bad track detected (hard disk)"); break;
566     case 0x0C: log_error("unsupported track or invalid media"); break;
567     case 0x0D: log_error("invalid number of sectors on format (PS/2 hard disk)"); break;
568     case 0x0E: log_error("control data address mark detected (hard disk)"); break;
569     case 0x0F: log_error("DMA arbitration level out of range (hard disk)"); break;
570     case 0x10: log_error("uncorrectable CRC or ECC error on read"); break;
571     case 0x11: log_error("data ECC corrected (hard disk)"); break;
572     case 0x20: log_error("controller failure"); break;
573     case 0x31: log_error("no media in drive (IBM/MS INT 13 extensions)"); break;
574     case 0x32: log_error("incorrect drive type stored in CMOS (Compaq)"); break;
575     case 0x40: log_error("seek failed"); break;
576     case 0x80: log_error("timeout (not ready)"); break;
577     case 0xAA: log_error("drive not ready (hard disk)"); break;
578     case 0xB0: log_error("volume not locked in drive (INT 13 extensions)"); break;
579     case 0xB1: log_error("volume locked in drive (INT 13 extensions)"); break;
580     case 0xB2: log_error("volume not removable (INT 13 extensions)"); break;
581     case 0xB3: log_error("volume in use (INT 13 extensions)"); break;
582     case 0xB4: log_error("lock count exceeded (INT 13 extensions)"); break;
583     case 0xB5: log_error("valid eject request failed (INT 13 extensions)"); break;
584     case 0xB6: log_error("volume present but read protected (INT 13 extensions)"); break;
585     case 0xBB: log_error("undefined error (hard disk)"); break;
586     case 0xCC: log_error("write fault (hard disk)"); break;
587     case 0xE0: log_error("status register error (hard disk)"); break;
588     case 0xFF: log_error("sense operation failed (hard disk)"); break;
589   }
590   log_error("\n");
591   return 0;
592 }
593 #endif
594