xref: /illumos-gate/usr/src/grub/grub-0.97/stage2/bios.c (revision 2f7f7a62d7a3e8a2e75eb88b95bc65871b6b90cb)
11b8adde7SWilliam Kucharski /* bios.c - implement C part of low-level BIOS disk input and output */
21b8adde7SWilliam Kucharski /*
31b8adde7SWilliam Kucharski  *  GRUB  --  GRand Unified Bootloader
41b8adde7SWilliam Kucharski  *  Copyright (C) 1999,2000,2003,2004  Free Software Foundation, Inc.
51b8adde7SWilliam Kucharski  *
61b8adde7SWilliam Kucharski  *  This program is free software; you can redistribute it and/or modify
71b8adde7SWilliam Kucharski  *  it under the terms of the GNU General Public License as published by
81b8adde7SWilliam Kucharski  *  the Free Software Foundation; either version 2 of the License, or
91b8adde7SWilliam Kucharski  *  (at your option) any later version.
101b8adde7SWilliam Kucharski  *
111b8adde7SWilliam Kucharski  *  This program is distributed in the hope that it will be useful,
121b8adde7SWilliam Kucharski  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
131b8adde7SWilliam Kucharski  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141b8adde7SWilliam Kucharski  *  GNU General Public License for more details.
151b8adde7SWilliam Kucharski  *
161b8adde7SWilliam Kucharski  *  You should have received a copy of the GNU General Public License
171b8adde7SWilliam Kucharski  *  along with this program; if not, write to the Free Software
181b8adde7SWilliam Kucharski  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
191b8adde7SWilliam Kucharski  */
209890706eSHans Rosenfeld /*
219890706eSHans Rosenfeld  * Copyright 2016 Nexenta Systems, Inc.
229890706eSHans Rosenfeld  */
231b8adde7SWilliam Kucharski 
241b8adde7SWilliam Kucharski #include "shared.h"
251b8adde7SWilliam Kucharski 
261b8adde7SWilliam Kucharski 
271b8adde7SWilliam Kucharski /* These are defined in asm.S, and never be used elsewhere, so declare the
281b8adde7SWilliam Kucharski    prototypes here.  */
291b8adde7SWilliam Kucharski extern int biosdisk_int13_extensions (int ax, int drive, void *dap);
301b8adde7SWilliam Kucharski extern int biosdisk_standard (int ah, int drive,
311b8adde7SWilliam Kucharski 			      int coff, int hoff, int soff,
321b8adde7SWilliam Kucharski 			      int nsec, int segment);
331b8adde7SWilliam Kucharski extern int check_int13_extensions (int drive);
341b8adde7SWilliam Kucharski extern int get_diskinfo_standard (int drive,
351b8adde7SWilliam Kucharski 				  unsigned long *cylinders,
361b8adde7SWilliam Kucharski 				  unsigned long *heads,
371b8adde7SWilliam Kucharski 				  unsigned long *sectors);
381b8adde7SWilliam Kucharski #if 0
391b8adde7SWilliam Kucharski extern int get_diskinfo_floppy (int drive,
401b8adde7SWilliam Kucharski 				unsigned long *cylinders,
411b8adde7SWilliam Kucharski 				unsigned long *heads,
421b8adde7SWilliam Kucharski 				unsigned long *sectors);
431b8adde7SWilliam Kucharski #endif
441b8adde7SWilliam Kucharski 
451b8adde7SWilliam Kucharski 
461b8adde7SWilliam Kucharski /* Read/write NSEC sectors starting from SECTOR in DRIVE disk with GEOMETRY
471b8adde7SWilliam Kucharski    from/into SEGMENT segment. If READ is BIOSDISK_READ, then read it,
481b8adde7SWilliam Kucharski    else if READ is BIOSDISK_WRITE, then write it. If an geometry error
491b8adde7SWilliam Kucharski    occurs, return BIOSDISK_ERROR_GEOMETRY, and if other error occurs, then
501b8adde7SWilliam Kucharski    return the error number. Otherwise, return 0.  */
511b8adde7SWilliam Kucharski int
biosdisk(int read,int drive,struct geometry * geometry,unsigned long long sector,int nsec,int segment)521b8adde7SWilliam Kucharski biosdisk (int read, int drive, struct geometry *geometry,
539890706eSHans Rosenfeld 	  unsigned long long sector, int nsec, int segment)
541b8adde7SWilliam Kucharski {
551b8adde7SWilliam Kucharski 
561b8adde7SWilliam Kucharski   int err;
571b8adde7SWilliam Kucharski 
581b8adde7SWilliam Kucharski   if (geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION)
591b8adde7SWilliam Kucharski     {
601b8adde7SWilliam Kucharski       struct disk_address_packet
611b8adde7SWilliam Kucharski       {
621b8adde7SWilliam Kucharski 	unsigned char length;
631b8adde7SWilliam Kucharski 	unsigned char reserved;
641b8adde7SWilliam Kucharski 	unsigned short blocks;
651b8adde7SWilliam Kucharski 	unsigned long buffer;
661b8adde7SWilliam Kucharski 	unsigned long long block;
671b8adde7SWilliam Kucharski       } __attribute__ ((packed)) dap;
681b8adde7SWilliam Kucharski 
691b8adde7SWilliam Kucharski       /* XXX: Don't check the geometry by default, because some buggy
701b8adde7SWilliam Kucharski 	 BIOSes don't return the number of total sectors correctly,
711b8adde7SWilliam Kucharski 	 even if they have working LBA support. Hell.  */
721b8adde7SWilliam Kucharski #ifdef NO_BUGGY_BIOS_IN_THE_WORLD
731b8adde7SWilliam Kucharski       if (sector >= geometry->total_sectors)
741b8adde7SWilliam Kucharski 	return BIOSDISK_ERROR_GEOMETRY;
751b8adde7SWilliam Kucharski #endif /* NO_BUGGY_BIOS_IN_THE_WORLD */
761b8adde7SWilliam Kucharski 
771b8adde7SWilliam Kucharski       /* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler
781b8adde7SWilliam Kucharski 	 can't add any padding.  */
791b8adde7SWilliam Kucharski       dap.length = sizeof (dap);
801b8adde7SWilliam Kucharski       dap.block = sector;
811b8adde7SWilliam Kucharski       dap.blocks = nsec;
821b8adde7SWilliam Kucharski       dap.reserved = 0;
831b8adde7SWilliam Kucharski       /* This is undocumented part. The address is formated in
841b8adde7SWilliam Kucharski 	 SEGMENT:ADDRESS.  */
851b8adde7SWilliam Kucharski       dap.buffer = segment << 16;
861b8adde7SWilliam Kucharski       err = biosdisk_int13_extensions ((read + 0x42) << 8, drive, &dap);
871b8adde7SWilliam Kucharski       /*
881b8adde7SWilliam Kucharski        * Try to report errors upwards when the bios has read only part of
891b8adde7SWilliam Kucharski        * the requested buffer, but didn't return an error code.
901b8adde7SWilliam Kucharski        */
911b8adde7SWilliam Kucharski       if (err == 0 && dap.blocks != nsec)
921b8adde7SWilliam Kucharski 	err = BIOSDISK_ERROR_SHORT_IO;
931b8adde7SWilliam Kucharski 
941b8adde7SWilliam Kucharski /* #undef NO_INT13_FALLBACK */
951b8adde7SWilliam Kucharski #ifndef NO_INT13_FALLBACK
961b8adde7SWilliam Kucharski       if (err)
971b8adde7SWilliam Kucharski 	{
981b8adde7SWilliam Kucharski 	  if (geometry->flags & BIOSDISK_FLAG_CDROM)
991b8adde7SWilliam Kucharski 	    return err;
1001b8adde7SWilliam Kucharski 
1011b8adde7SWilliam Kucharski 	  geometry->flags &= ~BIOSDISK_FLAG_LBA_EXTENSION;
102828d47c1SShidokht Yadegari 	  geometry->total_sectors = ((unsigned long long)geometry->cylinders
1031b8adde7SWilliam Kucharski 				     * geometry->heads
1041b8adde7SWilliam Kucharski 				     * geometry->sectors);
1051b8adde7SWilliam Kucharski 	  return biosdisk (read, drive, geometry, sector, nsec, segment);
1061b8adde7SWilliam Kucharski 	}
1071b8adde7SWilliam Kucharski #endif /* ! NO_INT13_FALLBACK */
1081b8adde7SWilliam Kucharski 
1091b8adde7SWilliam Kucharski     }
1101b8adde7SWilliam Kucharski   else
1111b8adde7SWilliam Kucharski     {
1121b8adde7SWilliam Kucharski       int cylinder_offset, head_offset, sector_offset;
1131b8adde7SWilliam Kucharski       int head;
1141b8adde7SWilliam Kucharski       /* SECTOR_OFFSET is counted from one, while HEAD_OFFSET and
1151b8adde7SWilliam Kucharski 	 CYLINDER_OFFSET are counted from zero.  */
1161b8adde7SWilliam Kucharski       sector_offset = sector % geometry->sectors + 1;
1171b8adde7SWilliam Kucharski       head = sector / geometry->sectors;
1181b8adde7SWilliam Kucharski       head_offset = head % geometry->heads;
1191b8adde7SWilliam Kucharski       cylinder_offset = head / geometry->heads;
1201b8adde7SWilliam Kucharski 
1211b8adde7SWilliam Kucharski       if (cylinder_offset >= geometry->cylinders)
1221b8adde7SWilliam Kucharski 	return BIOSDISK_ERROR_GEOMETRY;
1231b8adde7SWilliam Kucharski 
1241b8adde7SWilliam Kucharski       err = biosdisk_standard (read + 0x02, drive,
1251b8adde7SWilliam Kucharski 			       cylinder_offset, head_offset, sector_offset,
1261b8adde7SWilliam Kucharski 			       nsec, segment);
1271b8adde7SWilliam Kucharski     }
1281b8adde7SWilliam Kucharski 
1291b8adde7SWilliam Kucharski   return err;
1301b8adde7SWilliam Kucharski }
1311b8adde7SWilliam Kucharski 
1321b8adde7SWilliam Kucharski /* Check bootable CD-ROM emulation status.  */
1331b8adde7SWilliam Kucharski static int
get_cdinfo(int drive,struct geometry * geometry)1341b8adde7SWilliam Kucharski get_cdinfo (int drive, struct geometry *geometry)
1351b8adde7SWilliam Kucharski {
1361b8adde7SWilliam Kucharski   int err;
1371b8adde7SWilliam Kucharski   struct iso_spec_packet
1381b8adde7SWilliam Kucharski   {
1391b8adde7SWilliam Kucharski     unsigned char size;
1401b8adde7SWilliam Kucharski     unsigned char media_type;
1411b8adde7SWilliam Kucharski     unsigned char drive_no;
1421b8adde7SWilliam Kucharski     unsigned char controller_no;
1431b8adde7SWilliam Kucharski     unsigned long image_lba;
1441b8adde7SWilliam Kucharski     unsigned short device_spec;
1451b8adde7SWilliam Kucharski     unsigned short cache_seg;
1461b8adde7SWilliam Kucharski     unsigned short load_seg;
1471b8adde7SWilliam Kucharski     unsigned short length_sec512;
1481b8adde7SWilliam Kucharski     unsigned char cylinders;
1491b8adde7SWilliam Kucharski     unsigned char sectors;
1501b8adde7SWilliam Kucharski     unsigned char heads;
1511b8adde7SWilliam Kucharski 
1521b8adde7SWilliam Kucharski     unsigned char dummy[16];
1531b8adde7SWilliam Kucharski   } __attribute__ ((packed)) cdrp;
1541b8adde7SWilliam Kucharski 
1551b8adde7SWilliam Kucharski   grub_memset (&cdrp, 0, sizeof (cdrp));
1561b8adde7SWilliam Kucharski   cdrp.size = sizeof (cdrp) - sizeof (cdrp.dummy);
1571b8adde7SWilliam Kucharski   err = biosdisk_int13_extensions (0x4B01, drive, &cdrp);
1581b8adde7SWilliam Kucharski   if (! err && cdrp.drive_no == drive)
1591b8adde7SWilliam Kucharski     {
1601b8adde7SWilliam Kucharski       if ((cdrp.media_type & 0x0F) == 0)
1611b8adde7SWilliam Kucharski         {
1621b8adde7SWilliam Kucharski           /* No emulation bootable CD-ROM */
1631b8adde7SWilliam Kucharski           geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION | BIOSDISK_FLAG_CDROM;
1641b8adde7SWilliam Kucharski           geometry->cylinders = 0;
1651b8adde7SWilliam Kucharski           geometry->heads = 1;
1661b8adde7SWilliam Kucharski           geometry->sectors = 15;
1671b8adde7SWilliam Kucharski           geometry->sector_size = 2048;
16898c507c4SJan Setje-Eilers           geometry->total_sectors = MAXUINT;
1691b8adde7SWilliam Kucharski           return 1;
1701b8adde7SWilliam Kucharski         }
1711b8adde7SWilliam Kucharski       else
1721b8adde7SWilliam Kucharski         {
1731b8adde7SWilliam Kucharski 	  /* Floppy or hard-disk emulation */
1741b8adde7SWilliam Kucharski           geometry->cylinders
1751b8adde7SWilliam Kucharski 	    = ((unsigned int) cdrp.cylinders
1761b8adde7SWilliam Kucharski 	       + (((unsigned int) (cdrp.sectors & 0xC0)) << 2));
1771b8adde7SWilliam Kucharski           geometry->heads = cdrp.heads;
1781b8adde7SWilliam Kucharski           geometry->sectors = cdrp.sectors & 0x3F;
1791b8adde7SWilliam Kucharski           geometry->sector_size = SECTOR_SIZE;
180828d47c1SShidokht Yadegari           geometry->total_sectors = ((unsigned long long)geometry->cylinders
1811b8adde7SWilliam Kucharski 				     * geometry->heads
1821b8adde7SWilliam Kucharski 				     * geometry->sectors);
1831b8adde7SWilliam Kucharski           return -1;
1841b8adde7SWilliam Kucharski         }
1851b8adde7SWilliam Kucharski     }
1861b8adde7SWilliam Kucharski 
1871b8adde7SWilliam Kucharski   /*
1881b8adde7SWilliam Kucharski    * If this is the boot_drive, default to non-emulation bootable CD-ROM.
1891b8adde7SWilliam Kucharski    *
1901b8adde7SWilliam Kucharski    * Some BIOS (Tecra S1) fails the int13 call above. If we return
1911b8adde7SWilliam Kucharski    * failure here, GRUB will run, but cannot see the boot drive,
1921b8adde7SWilliam Kucharski    * not a very good situation. Defaulting to non-emulation mode
1931b8adde7SWilliam Kucharski    * is a last-ditch effort.
1941b8adde7SWilliam Kucharski    */
1951b8adde7SWilliam Kucharski   if (drive >= 0x88 && drive == boot_drive)
1961b8adde7SWilliam Kucharski     {
1971b8adde7SWilliam Kucharski       geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION | BIOSDISK_FLAG_CDROM;
1981b8adde7SWilliam Kucharski       geometry->cylinders = 0;
1991b8adde7SWilliam Kucharski       geometry->heads = 1;
2001b8adde7SWilliam Kucharski       geometry->sectors = 15;
2011b8adde7SWilliam Kucharski       geometry->sector_size = 2048;
20298c507c4SJan Setje-Eilers       geometry->total_sectors = MAXUINT;
2031b8adde7SWilliam Kucharski       return 1;
2041b8adde7SWilliam Kucharski     }
2051b8adde7SWilliam Kucharski   return 0;
2061b8adde7SWilliam Kucharski }
2071b8adde7SWilliam Kucharski 
2081b8adde7SWilliam Kucharski /* Return the geometry of DRIVE in GEOMETRY. If an error occurs, return
2091b8adde7SWilliam Kucharski    non-zero, otherwise zero.  */
2101b8adde7SWilliam Kucharski int
get_diskinfo(int drive,struct geometry * geometry)2111b8adde7SWilliam Kucharski get_diskinfo (int drive, struct geometry *geometry)
2121b8adde7SWilliam Kucharski {
2131b8adde7SWilliam Kucharski   int err;
214*2f7f7a62SAlex Wilson   int gotchs = 0;
2151b8adde7SWilliam Kucharski 
2161b8adde7SWilliam Kucharski   /* Clear the flags.  */
2171b8adde7SWilliam Kucharski   geometry->flags = 0;
2181b8adde7SWilliam Kucharski 
2191b8adde7SWilliam Kucharski   if (drive & 0x80)
2201b8adde7SWilliam Kucharski     {
2211b8adde7SWilliam Kucharski       /* hard disk or CD-ROM */
2221b8adde7SWilliam Kucharski       int version;
223828d47c1SShidokht Yadegari       unsigned long long total_sectors = 0;
2241b8adde7SWilliam Kucharski 
2251b8adde7SWilliam Kucharski       version = check_int13_extensions (drive);
2261b8adde7SWilliam Kucharski 
2271b8adde7SWilliam Kucharski       if (drive >= 0x88 || version)
2281b8adde7SWilliam Kucharski 	{
2291b8adde7SWilliam Kucharski 	  /* Possible CD-ROM - check the status.  */
2301b8adde7SWilliam Kucharski 	  if (get_cdinfo (drive, geometry))
2311b8adde7SWilliam Kucharski 	    return 0;
2321b8adde7SWilliam Kucharski 	}
2331b8adde7SWilliam Kucharski 
234*2f7f7a62SAlex Wilson       /* Don't pass GEOMETRY directly, but pass each element instead,
235*2f7f7a62SAlex Wilson 	 so that we can change the structure easily.  */
236*2f7f7a62SAlex Wilson       err = get_diskinfo_standard (drive,
237*2f7f7a62SAlex Wilson 				   &geometry->cylinders,
238*2f7f7a62SAlex Wilson 				   &geometry->heads,
239*2f7f7a62SAlex Wilson 				   &geometry->sectors);
240*2f7f7a62SAlex Wilson       if (err == 0)
241*2f7f7a62SAlex Wilson 	gotchs = 1;
242*2f7f7a62SAlex Wilson       /* get_diskinfo_standard returns 0x60 if the BIOS call actually
243*2f7f7a62SAlex Wilson 	 succeeded but returned 0 sectors -- in this case don't
244*2f7f7a62SAlex Wilson 	 return yet but continue to check the LBA geom */
245*2f7f7a62SAlex Wilson       else if (err != 0x60)
246*2f7f7a62SAlex Wilson 	return err;
247*2f7f7a62SAlex Wilson 
2481b8adde7SWilliam Kucharski       if (version)
2491b8adde7SWilliam Kucharski 	{
2501b8adde7SWilliam Kucharski 	  struct drive_parameters
2511b8adde7SWilliam Kucharski 	  {
2521b8adde7SWilliam Kucharski 	    unsigned short size;
2531b8adde7SWilliam Kucharski 	    unsigned short flags;
2541b8adde7SWilliam Kucharski 	    unsigned long cylinders;
2551b8adde7SWilliam Kucharski 	    unsigned long heads;
2561b8adde7SWilliam Kucharski 	    unsigned long sectors;
2571b8adde7SWilliam Kucharski 	    unsigned long long total_sectors;
2581b8adde7SWilliam Kucharski 	    unsigned short bytes_per_sector;
2591b8adde7SWilliam Kucharski 	    /* ver 2.0 or higher */
2601b8adde7SWilliam Kucharski 	    unsigned long EDD_configuration_parameters;
2611b8adde7SWilliam Kucharski 	    /* ver 3.0 or higher */
2621b8adde7SWilliam Kucharski 	    unsigned short signature_dpi;
2631b8adde7SWilliam Kucharski 	    unsigned char length_dpi;
2641b8adde7SWilliam Kucharski 	    unsigned char reserved[3];
2651b8adde7SWilliam Kucharski 	    unsigned char name_of_host_bus[4];
2661b8adde7SWilliam Kucharski 	    unsigned char name_of_interface_type[8];
2671b8adde7SWilliam Kucharski 	    unsigned char interface_path[8];
2681b8adde7SWilliam Kucharski 	    unsigned char device_path[8];
2691b8adde7SWilliam Kucharski 	    unsigned char reserved2;
2701b8adde7SWilliam Kucharski 	    unsigned char checksum;
2711b8adde7SWilliam Kucharski 
2721b8adde7SWilliam Kucharski 	    /* XXX: This is necessary, because the BIOS of Thinkpad X20
2731b8adde7SWilliam Kucharski 	       writes a garbage to the tail of drive parameters,
2741b8adde7SWilliam Kucharski 	       regardless of a size specified in a caller.  */
2751b8adde7SWilliam Kucharski 	    unsigned char dummy[16];
2761b8adde7SWilliam Kucharski 	  } __attribute__ ((packed)) drp;
2771b8adde7SWilliam Kucharski 
2781b8adde7SWilliam Kucharski 	  /* It is safe to clear out DRP.  */
2791b8adde7SWilliam Kucharski 	  grub_memset (&drp, 0, sizeof (drp));
2801b8adde7SWilliam Kucharski 
2811b8adde7SWilliam Kucharski 	  /* PhoenixBIOS 4.0 Revision 6.0 for ZF Micro might understand
2821b8adde7SWilliam Kucharski 	     the greater buffer size for the "get drive parameters" int
2831b8adde7SWilliam Kucharski 	     0x13 call in its own way.  Supposedly the BIOS assumes even
2841b8adde7SWilliam Kucharski 	     bigger space is available and thus corrupts the stack.
2851b8adde7SWilliam Kucharski 	     This is why we specify the exactly necessary size of 0x42
2861b8adde7SWilliam Kucharski 	     bytes. */
2871b8adde7SWilliam Kucharski 	  drp.size = sizeof (drp) - sizeof (drp.dummy);
2881b8adde7SWilliam Kucharski 
2891b8adde7SWilliam Kucharski 	  err = biosdisk_int13_extensions (0x4800, drive, &drp);
2901b8adde7SWilliam Kucharski 	  if (! err)
2911b8adde7SWilliam Kucharski 	    {
2921b8adde7SWilliam Kucharski 	      /* Set the LBA flag.  */
2931b8adde7SWilliam Kucharski 	      geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
2941b8adde7SWilliam Kucharski 
2951b8adde7SWilliam Kucharski 	      /* I'm not sure if GRUB should check the bit 1 of DRP.FLAGS,
2961b8adde7SWilliam Kucharski 		 so I omit the check for now. - okuji  */
2971b8adde7SWilliam Kucharski 	      /* if (drp.flags & (1 << 1)) */
2981b8adde7SWilliam Kucharski 
299*2f7f7a62SAlex Wilson 	      /* If we didn't get valid CHS info from the standard call,
300*2f7f7a62SAlex Wilson 		 then we should fill it out here */
301*2f7f7a62SAlex Wilson 	      if (! gotchs)
302*2f7f7a62SAlex Wilson 		{
303*2f7f7a62SAlex Wilson 		  geometry->cylinders = drp.cylinders;
304*2f7f7a62SAlex Wilson 
305*2f7f7a62SAlex Wilson 		  if (drp.sectors > 0 && drp.heads > 0)
306*2f7f7a62SAlex Wilson 		    {
307*2f7f7a62SAlex Wilson 		      geometry->heads = drp.heads;
308*2f7f7a62SAlex Wilson 		      geometry->sectors = drp.sectors;
309*2f7f7a62SAlex Wilson 		    }
310*2f7f7a62SAlex Wilson 		  else
311*2f7f7a62SAlex Wilson 		    {
312*2f7f7a62SAlex Wilson 		      /* Return fake geometry. This disk reports that it
313*2f7f7a62SAlex Wilson 			 supports LBA, so all the other routines will use LBA
314*2f7f7a62SAlex Wilson 			 to talk to it and not look at this geometry. However,
315*2f7f7a62SAlex Wilson 			 some of the partition-finding routines still need
316*2f7f7a62SAlex Wilson 			 non-zero values in these fields. */
317*2f7f7a62SAlex Wilson 		      geometry->heads = 16;
318*2f7f7a62SAlex Wilson 		      geometry->sectors = 63;
319*2f7f7a62SAlex Wilson 		    }
320*2f7f7a62SAlex Wilson 		  gotchs = 1;
321*2f7f7a62SAlex Wilson 		}
322*2f7f7a62SAlex Wilson 
3231b8adde7SWilliam Kucharski 	      if (drp.total_sectors)
324828d47c1SShidokht Yadegari 		total_sectors = drp.total_sectors;
3251b8adde7SWilliam Kucharski 	      else
3261b8adde7SWilliam Kucharski 		/* Some buggy BIOSes doesn't return the total sectors
3271b8adde7SWilliam Kucharski 		   correctly but returns zero. So if it is zero, compute
3281b8adde7SWilliam Kucharski 		   it by C/H/S returned by the LBA BIOS call.  */
329828d47c1SShidokht Yadegari 		total_sectors = (unsigned long long)drp.cylinders *
330828d47c1SShidokht Yadegari 		    drp.heads * drp.sectors;
3311b8adde7SWilliam Kucharski 	    }
3321b8adde7SWilliam Kucharski 	}
3331b8adde7SWilliam Kucharski 
334*2f7f7a62SAlex Wilson       /* In case we got the 0x60 return code from _standard on a disk that
335*2f7f7a62SAlex Wilson 	 didn't support LBA (or was somehow invalid), return that error now */
336*2f7f7a62SAlex Wilson       if (! gotchs)
337*2f7f7a62SAlex Wilson 	return 0x60;
3381b8adde7SWilliam Kucharski 
3391b8adde7SWilliam Kucharski       if (! total_sectors)
3401b8adde7SWilliam Kucharski 	{
341828d47c1SShidokht Yadegari 	  total_sectors = ((unsigned long long)geometry->cylinders
3421b8adde7SWilliam Kucharski 			   * geometry->heads
3431b8adde7SWilliam Kucharski 			   * geometry->sectors);
3441b8adde7SWilliam Kucharski 	}
3451b8adde7SWilliam Kucharski       geometry->total_sectors = total_sectors;
3461b8adde7SWilliam Kucharski       geometry->sector_size = SECTOR_SIZE;
3471b8adde7SWilliam Kucharski     }
3481b8adde7SWilliam Kucharski   else
3491b8adde7SWilliam Kucharski     {
3501b8adde7SWilliam Kucharski       /* floppy disk */
3511b8adde7SWilliam Kucharski 
3521b8adde7SWilliam Kucharski       /* First, try INT 13 AH=8h call.  */
3531b8adde7SWilliam Kucharski       err = get_diskinfo_standard (drive,
3541b8adde7SWilliam Kucharski 				   &geometry->cylinders,
3551b8adde7SWilliam Kucharski 				   &geometry->heads,
3561b8adde7SWilliam Kucharski 				   &geometry->sectors);
3571b8adde7SWilliam Kucharski 
3581b8adde7SWilliam Kucharski #if 0
3591b8adde7SWilliam Kucharski       /* If fails, then try floppy-specific probe routine.  */
3601b8adde7SWilliam Kucharski       if (err)
3611b8adde7SWilliam Kucharski 	err = get_diskinfo_floppy (drive,
3621b8adde7SWilliam Kucharski 				   &geometry->cylinders,
3631b8adde7SWilliam Kucharski 				   &geometry->heads,
3641b8adde7SWilliam Kucharski 				   &geometry->sectors);
3651b8adde7SWilliam Kucharski #endif
3661b8adde7SWilliam Kucharski 
3671b8adde7SWilliam Kucharski       if (err)
3681b8adde7SWilliam Kucharski 	return err;
3691b8adde7SWilliam Kucharski 
370828d47c1SShidokht Yadegari       geometry->total_sectors = ((unsigned long long)geometry->cylinders
3711b8adde7SWilliam Kucharski 				 * geometry->heads
3721b8adde7SWilliam Kucharski 				 * geometry->sectors);
3731b8adde7SWilliam Kucharski       geometry->sector_size = SECTOR_SIZE;
3741b8adde7SWilliam Kucharski     }
3751b8adde7SWilliam Kucharski 
3761b8adde7SWilliam Kucharski   return 0;
3771b8adde7SWilliam Kucharski }
378