17c478bd9Sstevel@tonic-gate /* bios.c - implement C part of low-level BIOS disk input and output */
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  *  GRUB  --  GRand Unified Bootloader
47c478bd9Sstevel@tonic-gate  *  Copyright (C) 1999,2000,2003,2004  Free Software Foundation, Inc.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate  *  it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate  *  the Free Software Foundation; either version 2 of the License, or
97c478bd9Sstevel@tonic-gate  *  (at your option) any later version.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  *  This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate  *  GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  *  You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate  *  along with this program; if not, write to the Free Software
187c478bd9Sstevel@tonic-gate  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197c478bd9Sstevel@tonic-gate  */
209890706eSHans Rosenfeld /*
219890706eSHans Rosenfeld  * Copyright 2016 Nexenta Systems, Inc.
229890706eSHans Rosenfeld  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #include "shared.h"
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /* These are defined in asm.S, and never be used elsewhere, so declare the
287c478bd9Sstevel@tonic-gate    prototypes here.  */
297c478bd9Sstevel@tonic-gate extern int biosdisk_int13_extensions (int ax, int drive, void *dap);
307c478bd9Sstevel@tonic-gate extern int biosdisk_standard (int ah, int drive,
317c478bd9Sstevel@tonic-gate 			      int coff, int hoff, int soff,
327c478bd9Sstevel@tonic-gate 			      int nsec, int segment);
337c478bd9Sstevel@tonic-gate extern int check_int13_extensions (int drive);
347c478bd9Sstevel@tonic-gate extern int get_diskinfo_standard (int drive,
357c478bd9Sstevel@tonic-gate 				  unsigned long *cylinders,
367c478bd9Sstevel@tonic-gate 				  unsigned long *heads,
377c478bd9Sstevel@tonic-gate 				  unsigned long *sectors);
387c478bd9Sstevel@tonic-gate #if 0
397c478bd9Sstevel@tonic-gate extern int get_diskinfo_floppy (int drive,
407c478bd9Sstevel@tonic-gate 				unsigned long *cylinders,
417c478bd9Sstevel@tonic-gate 				unsigned long *heads,
427c478bd9Sstevel@tonic-gate 				unsigned long *sectors);
437c478bd9Sstevel@tonic-gate #endif
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /* Read/write NSEC sectors starting from SECTOR in DRIVE disk with GEOMETRY
477c478bd9Sstevel@tonic-gate    from/into SEGMENT segment. If READ is BIOSDISK_READ, then read it,
487c478bd9Sstevel@tonic-gate    else if READ is BIOSDISK_WRITE, then write it. If an geometry error
497c478bd9Sstevel@tonic-gate    occurs, return BIOSDISK_ERROR_GEOMETRY, and if other error occurs, then
507c478bd9Sstevel@tonic-gate    return the error number. Otherwise, return 0.  */
517c478bd9Sstevel@tonic-gate int
biosdisk(int read,int drive,struct geometry * geometry,unsigned long long sector,int nsec,int segment)527c478bd9Sstevel@tonic-gate biosdisk (int read, int drive, struct geometry *geometry,
539890706eSHans Rosenfeld 	  unsigned long long sector, int nsec, int segment)
547c478bd9Sstevel@tonic-gate {
55342440ecSPrasad Singamsetty 
567c478bd9Sstevel@tonic-gate   int err;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate   if (geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION)
597c478bd9Sstevel@tonic-gate     {
607c478bd9Sstevel@tonic-gate       struct disk_address_packet
617c478bd9Sstevel@tonic-gate       {
627c478bd9Sstevel@tonic-gate 	unsigned char length;
637c478bd9Sstevel@tonic-gate 	unsigned char reserved;
647c478bd9Sstevel@tonic-gate 	unsigned short blocks;
657c478bd9Sstevel@tonic-gate 	unsigned long buffer;
667c478bd9Sstevel@tonic-gate 	unsigned long long block;
677c478bd9Sstevel@tonic-gate       } __attribute__ ((packed)) dap;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate       /* XXX: Don't check the geometry by default, because some buggy
707c478bd9Sstevel@tonic-gate 	 BIOSes don't return the number of total sectors correctly,
717c478bd9Sstevel@tonic-gate 	 even if they have working LBA support. Hell.  */
727c478bd9Sstevel@tonic-gate #ifdef NO_BUGGY_BIOS_IN_THE_WORLD
737c478bd9Sstevel@tonic-gate       if (sector >= geometry->total_sectors)
747c478bd9Sstevel@tonic-gate 	return BIOSDISK_ERROR_GEOMETRY;
757c478bd9Sstevel@tonic-gate #endif /* NO_BUGGY_BIOS_IN_THE_WORLD */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate       /* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler
787c478bd9Sstevel@tonic-gate 	 can't add any padding.  */
797c478bd9Sstevel@tonic-gate       dap.length = sizeof (dap);
807c478bd9Sstevel@tonic-gate       dap.block = sector;
817c478bd9Sstevel@tonic-gate       dap.blocks = nsec;
827c478bd9Sstevel@tonic-gate       dap.reserved = 0;
837c478bd9Sstevel@tonic-gate       /* This is undocumented part. The address is formated in
847c478bd9Sstevel@tonic-gate 	 SEGMENT:ADDRESS.  */
857c478bd9Sstevel@tonic-gate       dap.buffer = segment << 16;
867c478bd9Sstevel@tonic-gate       err = biosdisk_int13_extensions ((read + 0x42) << 8, drive, &dap);
879caa1482Sszhou       /*
889caa1482Sszhou        * Try to report errors upwards when the bios has read only part of
899caa1482Sszhou        * the requested buffer, but didn't return an error code.
909caa1482Sszhou        */
919caa1482Sszhou       if (err == 0 && dap.blocks != nsec)
929caa1482Sszhou 	err = BIOSDISK_ERROR_SHORT_IO;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /* #undef NO_INT13_FALLBACK */
957c478bd9Sstevel@tonic-gate #ifndef NO_INT13_FALLBACK
967c478bd9Sstevel@tonic-gate       if (err)
977c478bd9Sstevel@tonic-gate 	{
987c478bd9Sstevel@tonic-gate 	  if (geometry->flags & BIOSDISK_FLAG_CDROM)
997c478bd9Sstevel@tonic-gate 	    return err;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	  geometry->flags &= ~BIOSDISK_FLAG_LBA_EXTENSION;
102828d47c1SShidokht Yadegari 	  geometry->total_sectors = ((unsigned long long)geometry->cylinders
1037c478bd9Sstevel@tonic-gate 				     * geometry->heads
1047c478bd9Sstevel@tonic-gate 				     * geometry->sectors);
1057c478bd9Sstevel@tonic-gate 	  return biosdisk (read, drive, geometry, sector, nsec, segment);
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate #endif /* ! NO_INT13_FALLBACK */
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate     }
1107c478bd9Sstevel@tonic-gate   else
1117c478bd9Sstevel@tonic-gate     {
1127c478bd9Sstevel@tonic-gate       int cylinder_offset, head_offset, sector_offset;
1137c478bd9Sstevel@tonic-gate       int head;
1147c478bd9Sstevel@tonic-gate       /* SECTOR_OFFSET is counted from one, while HEAD_OFFSET and
1157c478bd9Sstevel@tonic-gate 	 CYLINDER_OFFSET are counted from zero.  */
1167c478bd9Sstevel@tonic-gate       sector_offset = sector % geometry->sectors + 1;
1177c478bd9Sstevel@tonic-gate       head = sector / geometry->sectors;
1187c478bd9Sstevel@tonic-gate       head_offset = head % geometry->heads;
1197c478bd9Sstevel@tonic-gate       cylinder_offset = head / geometry->heads;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate       if (cylinder_offset >= geometry->cylinders)
1227c478bd9Sstevel@tonic-gate 	return BIOSDISK_ERROR_GEOMETRY;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate       err = biosdisk_standard (read + 0x02, drive,
1257c478bd9Sstevel@tonic-gate 			       cylinder_offset, head_offset, sector_offset,
1267c478bd9Sstevel@tonic-gate 			       nsec, segment);
1277c478bd9Sstevel@tonic-gate     }
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate   return err;
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /* Check bootable CD-ROM emulation status.  */
1337c478bd9Sstevel@tonic-gate static int
get_cdinfo(int drive,struct geometry * geometry)1347c478bd9Sstevel@tonic-gate get_cdinfo (int drive, struct geometry *geometry)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate   int err;
1377c478bd9Sstevel@tonic-gate   struct iso_spec_packet
1387c478bd9Sstevel@tonic-gate   {
1397c478bd9Sstevel@tonic-gate     unsigned char size;
1407c478bd9Sstevel@tonic-gate     unsigned char media_type;
1417c478bd9Sstevel@tonic-gate     unsigned char drive_no;
1427c478bd9Sstevel@tonic-gate     unsigned char controller_no;
1437c478bd9Sstevel@tonic-gate     unsigned long image_lba;
1447c478bd9Sstevel@tonic-gate     unsigned short device_spec;
1457c478bd9Sstevel@tonic-gate     unsigned short cache_seg;
1467c478bd9Sstevel@tonic-gate     unsigned short load_seg;
1477c478bd9Sstevel@tonic-gate     unsigned short length_sec512;
1487c478bd9Sstevel@tonic-gate     unsigned char cylinders;
1497c478bd9Sstevel@tonic-gate     unsigned char sectors;
1507c478bd9Sstevel@tonic-gate     unsigned char heads;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate     unsigned char dummy[16];
1537c478bd9Sstevel@tonic-gate   } __attribute__ ((packed)) cdrp;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate   grub_memset (&cdrp, 0, sizeof (cdrp));
1567c478bd9Sstevel@tonic-gate   cdrp.size = sizeof (cdrp) - sizeof (cdrp.dummy);
1577c478bd9Sstevel@tonic-gate   err = biosdisk_int13_extensions (0x4B01, drive, &cdrp);
1587c478bd9Sstevel@tonic-gate   if (! err && cdrp.drive_no == drive)
1597c478bd9Sstevel@tonic-gate     {
1607c478bd9Sstevel@tonic-gate       if ((cdrp.media_type & 0x0F) == 0)
1617c478bd9Sstevel@tonic-gate         {
1627c478bd9Sstevel@tonic-gate           /* No emulation bootable CD-ROM */
1637c478bd9Sstevel@tonic-gate           geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION | BIOSDISK_FLAG_CDROM;
1647c478bd9Sstevel@tonic-gate           geometry->cylinders = 0;
1657c478bd9Sstevel@tonic-gate           geometry->heads = 1;
1667c478bd9Sstevel@tonic-gate           geometry->sectors = 15;
1677c478bd9Sstevel@tonic-gate           geometry->sector_size = 2048;
16898c507c4SJan Setje-Eilers           geometry->total_sectors = MAXUINT;
1697c478bd9Sstevel@tonic-gate           return 1;
1707c478bd9Sstevel@tonic-gate         }
1717c478bd9Sstevel@tonic-gate       else
1727c478bd9Sstevel@tonic-gate         {
1737c478bd9Sstevel@tonic-gate 	  /* Floppy or hard-disk emulation */
1747c478bd9Sstevel@tonic-gate           geometry->cylinders
1757c478bd9Sstevel@tonic-gate 	    = ((unsigned int) cdrp.cylinders
1767c478bd9Sstevel@tonic-gate 	       + (((unsigned int) (cdrp.sectors & 0xC0)) << 2));
1777c478bd9Sstevel@tonic-gate           geometry->heads = cdrp.heads;
1787c478bd9Sstevel@tonic-gate           geometry->sectors = cdrp.sectors & 0x3F;
1797c478bd9Sstevel@tonic-gate           geometry->sector_size = SECTOR_SIZE;
180828d47c1SShidokht Yadegari           geometry->total_sectors = ((unsigned long long)geometry->cylinders
1817c478bd9Sstevel@tonic-gate 				     * geometry->heads
1827c478bd9Sstevel@tonic-gate 				     * geometry->sectors);
1837c478bd9Sstevel@tonic-gate           return -1;
1847c478bd9Sstevel@tonic-gate         }
1857c478bd9Sstevel@tonic-gate     }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate   /*
1887c478bd9Sstevel@tonic-gate    * If this is the boot_drive, default to non-emulation bootable CD-ROM.
1897c478bd9Sstevel@tonic-gate    *
1907c478bd9Sstevel@tonic-gate    * Some BIOS (Tecra S1) fails the int13 call above. If we return
1917c478bd9Sstevel@tonic-gate    * failure here, GRUB will run, but cannot see the boot drive,
1927c478bd9Sstevel@tonic-gate    * not a very good situation. Defaulting to non-emulation mode
1937c478bd9Sstevel@tonic-gate    * is a last-ditch effort.
1947c478bd9Sstevel@tonic-gate    */
1957c478bd9Sstevel@tonic-gate   if (drive >= 0x88 && drive == boot_drive)
1967c478bd9Sstevel@tonic-gate     {
1977c478bd9Sstevel@tonic-gate       geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION | BIOSDISK_FLAG_CDROM;
1987c478bd9Sstevel@tonic-gate       geometry->cylinders = 0;
1997c478bd9Sstevel@tonic-gate       geometry->heads = 1;
2007c478bd9Sstevel@tonic-gate       geometry->sectors = 15;
2017c478bd9Sstevel@tonic-gate       geometry->sector_size = 2048;
20298c507c4SJan Setje-Eilers       geometry->total_sectors = MAXUINT;
2037c478bd9Sstevel@tonic-gate       return 1;
2047c478bd9Sstevel@tonic-gate     }
2057c478bd9Sstevel@tonic-gate   return 0;
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate /* Return the geometry of DRIVE in GEOMETRY. If an error occurs, return
2097c478bd9Sstevel@tonic-gate    non-zero, otherwise zero.  */
2107c478bd9Sstevel@tonic-gate int
get_diskinfo(int drive,struct geometry * geometry)2117c478bd9Sstevel@tonic-gate get_diskinfo (int drive, struct geometry *geometry)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate   int err;
214*2f7f7a62SAlex Wilson   int gotchs = 0;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate   /* Clear the flags.  */
2177c478bd9Sstevel@tonic-gate   geometry->flags = 0;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate   if (drive & 0x80)
2207c478bd9Sstevel@tonic-gate     {
2217c478bd9Sstevel@tonic-gate       /* hard disk or CD-ROM */
2227c478bd9Sstevel@tonic-gate       int version;
223828d47c1SShidokht Yadegari       unsigned long long total_sectors = 0;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate       version = check_int13_extensions (drive);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate       if (drive >= 0x88 || version)
2287c478bd9Sstevel@tonic-gate 	{
2297c478bd9Sstevel@tonic-gate 	  /* Possible CD-ROM - check the status.  */
2307c478bd9Sstevel@tonic-gate 	  if (get_cdinfo (drive, geometry))
2317c478bd9Sstevel@tonic-gate 	    return 0;
2327c478bd9Sstevel@tonic-gate 	}
233*2f7f7a62SAlex Wilson 
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;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate       if (version)
2497c478bd9Sstevel@tonic-gate 	{
2507c478bd9Sstevel@tonic-gate 	  struct drive_parameters
2517c478bd9Sstevel@tonic-gate 	  {
2527c478bd9Sstevel@tonic-gate 	    unsigned short size;
2537c478bd9Sstevel@tonic-gate 	    unsigned short flags;
2547c478bd9Sstevel@tonic-gate 	    unsigned long cylinders;
2557c478bd9Sstevel@tonic-gate 	    unsigned long heads;
2567c478bd9Sstevel@tonic-gate 	    unsigned long sectors;
2577c478bd9Sstevel@tonic-gate 	    unsigned long long total_sectors;
2587c478bd9Sstevel@tonic-gate 	    unsigned short bytes_per_sector;
2597c478bd9Sstevel@tonic-gate 	    /* ver 2.0 or higher */
2607c478bd9Sstevel@tonic-gate 	    unsigned long EDD_configuration_parameters;
2617c478bd9Sstevel@tonic-gate 	    /* ver 3.0 or higher */
2627c478bd9Sstevel@tonic-gate 	    unsigned short signature_dpi;
2637c478bd9Sstevel@tonic-gate 	    unsigned char length_dpi;
2647c478bd9Sstevel@tonic-gate 	    unsigned char reserved[3];
2657c478bd9Sstevel@tonic-gate 	    unsigned char name_of_host_bus[4];
2667c478bd9Sstevel@tonic-gate 	    unsigned char name_of_interface_type[8];
2677c478bd9Sstevel@tonic-gate 	    unsigned char interface_path[8];
2687c478bd9Sstevel@tonic-gate 	    unsigned char device_path[8];
2697c478bd9Sstevel@tonic-gate 	    unsigned char reserved2;
2707c478bd9Sstevel@tonic-gate 	    unsigned char checksum;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	    /* XXX: This is necessary, because the BIOS of Thinkpad X20
2737c478bd9Sstevel@tonic-gate 	       writes a garbage to the tail of drive parameters,
2747c478bd9Sstevel@tonic-gate 	       regardless of a size specified in a caller.  */
2757c478bd9Sstevel@tonic-gate 	    unsigned char dummy[16];
2767c478bd9Sstevel@tonic-gate 	  } __attribute__ ((packed)) drp;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	  /* It is safe to clear out DRP.  */
2797c478bd9Sstevel@tonic-gate 	  grub_memset (&drp, 0, sizeof (drp));
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	  /* PhoenixBIOS 4.0 Revision 6.0 for ZF Micro might understand
2827c478bd9Sstevel@tonic-gate 	     the greater buffer size for the "get drive parameters" int
2837c478bd9Sstevel@tonic-gate 	     0x13 call in its own way.  Supposedly the BIOS assumes even
2847c478bd9Sstevel@tonic-gate 	     bigger space is available and thus corrupts the stack.
2857c478bd9Sstevel@tonic-gate 	     This is why we specify the exactly necessary size of 0x42
2867c478bd9Sstevel@tonic-gate 	     bytes. */
2877c478bd9Sstevel@tonic-gate 	  drp.size = sizeof (drp) - sizeof (drp.dummy);
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	  err = biosdisk_int13_extensions (0x4800, drive, &drp);
2907c478bd9Sstevel@tonic-gate 	  if (! err)
2917c478bd9Sstevel@tonic-gate 	    {
2927c478bd9Sstevel@tonic-gate 	      /* Set the LBA flag.  */
2937c478bd9Sstevel@tonic-gate 	      geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	      /* I'm not sure if GRUB should check the bit 1 of DRP.FLAGS,
2967c478bd9Sstevel@tonic-gate 		 so I omit the check for now. - okuji  */
2977c478bd9Sstevel@tonic-gate 	      /* if (drp.flags & (1 << 1)) */
298*2f7f7a62SAlex Wilson 
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 		}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	      if (drp.total_sectors)
324828d47c1SShidokht Yadegari 		total_sectors = drp.total_sectors;
3257c478bd9Sstevel@tonic-gate 	      else
3267c478bd9Sstevel@tonic-gate 		/* Some buggy BIOSes doesn't return the total sectors
3277c478bd9Sstevel@tonic-gate 		   correctly but returns zero. So if it is zero, compute
3287c478bd9Sstevel@tonic-gate 		   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;
3317c478bd9Sstevel@tonic-gate 	    }
3327c478bd9Sstevel@tonic-gate 	}
3337c478bd9Sstevel@tonic-gate 
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;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate       if (! total_sectors)
3407c478bd9Sstevel@tonic-gate 	{
341828d47c1SShidokht Yadegari 	  total_sectors = ((unsigned long long)geometry->cylinders
3427c478bd9Sstevel@tonic-gate 			   * geometry->heads
3437c478bd9Sstevel@tonic-gate 			   * geometry->sectors);
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate       geometry->total_sectors = total_sectors;
3467c478bd9Sstevel@tonic-gate       geometry->sector_size = SECTOR_SIZE;
3477c478bd9Sstevel@tonic-gate     }
3487c478bd9Sstevel@tonic-gate   else
3497c478bd9Sstevel@tonic-gate     {
3507c478bd9Sstevel@tonic-gate       /* floppy disk */
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate       /* First, try INT 13 AH=8h call.  */
3537c478bd9Sstevel@tonic-gate       err = get_diskinfo_standard (drive,
3547c478bd9Sstevel@tonic-gate 				   &geometry->cylinders,
3557c478bd9Sstevel@tonic-gate 				   &geometry->heads,
3567c478bd9Sstevel@tonic-gate 				   &geometry->sectors);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate #if 0
3597c478bd9Sstevel@tonic-gate       /* If fails, then try floppy-specific probe routine.  */
3607c478bd9Sstevel@tonic-gate       if (err)
3617c478bd9Sstevel@tonic-gate 	err = get_diskinfo_floppy (drive,
3627c478bd9Sstevel@tonic-gate 				   &geometry->cylinders,
3637c478bd9Sstevel@tonic-gate 				   &geometry->heads,
3647c478bd9Sstevel@tonic-gate 				   &geometry->sectors);
3657c478bd9Sstevel@tonic-gate #endif
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate       if (err)
3687c478bd9Sstevel@tonic-gate 	return err;
3697c478bd9Sstevel@tonic-gate 
370828d47c1SShidokht Yadegari       geometry->total_sectors = ((unsigned long long)geometry->cylinders
3717c478bd9Sstevel@tonic-gate 				 * geometry->heads
3727c478bd9Sstevel@tonic-gate 				 * geometry->sectors);
3737c478bd9Sstevel@tonic-gate       geometry->sector_size = SECTOR_SIZE;
3747c478bd9Sstevel@tonic-gate     }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate   return 0;
3777c478bd9Sstevel@tonic-gate }
378