aboutsummaryrefslogtreecommitdiffstats
path: root/com32/hdt/hdt-ata.c
diff options
context:
space:
mode:
Diffstat (limited to 'com32/hdt/hdt-ata.c')
-rw-r--r--com32/hdt/hdt-ata.c254
1 files changed, 254 insertions, 0 deletions
diff --git a/com32/hdt/hdt-ata.c b/com32/hdt/hdt-ata.c
new file mode 100644
index 00000000..a5000609
--- /dev/null
+++ b/com32/hdt/hdt-ata.c
@@ -0,0 +1,254 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Erwan Velu - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+*/
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <console.h>
+#include "com32io.h"
+#include "hdt-ata.h"
+
+#ifdef ATA
+/**
+ * ata_id_string - Convert IDENTIFY DEVICE page into string
+ * @id: IDENTIFY DEVICE results we will examine
+ * @s: string into which data is output
+ * @ofs: offset into identify device page
+ * @len: length of string to return. must be an even number.
+ *
+ * The strings in the IDENTIFY DEVICE page are broken up into
+ * 16-bit chunks. Run through the string, and output each
+ * 8-bit chunk linearly, regardless of platform.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+void ata_id_string(const uint16_t *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned int c;
+
+ while (len > 0) {
+ c = id[ofs] >> 8;
+ *s = c;
+ s++;
+
+ c = id[ofs] & 0xff;
+ *s = c;
+ s++;
+
+ ofs++;
+ len -= 2;
+ }
+}
+
+/**
+ * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
+ * @id: IDENTIFY DEVICE results we will examine
+ * @s: string into which data is output
+ * @ofs: offset into identify device page
+ * @len: length of string to return. must be an odd number.
+ *
+ * This function is identical to ata_id_string except that it
+ * trims trailing spaces and terminates the resulting string with
+ * null. @len must be actual maximum length (even number) + 1.
+ *
+ * LOCKING:
+ * caller.
+ */
+void ata_id_c_string(const uint16_t *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned char *p;
+
+ //WARN_ON(!(len & 1));
+
+ ata_id_string(id, s, ofs, len - 1);
+
+ p = s + strnlen(s, len - 1);
+ while (p > s && p[-1] == ' ')
+ p--;
+ *p = '\0';
+}
+#endif
+
+/*
+ * Call int 13h, but with retry on failure. Especially floppies need this.
+ */
+int int13_retry(const com32sys_t *inreg, com32sys_t *outreg)
+{
+ int retry = 6; /* Number of retries */
+ com32sys_t tmpregs;
+
+ if ( !outreg ) outreg = &tmpregs;
+
+ while ( retry-- ) {
+ __intcall(0x13, inreg, outreg);
+ if ( !(outreg->eflags.l & EFLAGS_CF) )
+ return 0; /* CF=0, OK */
+ }
+
+ return -1; /* Error */
+}
+
+/* Display CPU registers for debugging purposes */
+void printregs(const com32sys_t *r)
+{
+ printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n"
+ "eax = %08x ebx = %08x ecx = %08x edx = %08x\n"
+ "ebp = %08x esi = %08x edi = %08x esp = %08x\n",
+ r->eflags.l, r->ds, r->es, r->fs, r->gs,
+ r->eax.l, r->ebx.l, r->ecx.l, r->edx.l,
+ r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l);
+}
+
+/* Try to get information for a given disk*/
+int get_disk_params(int disk, struct diskinfo *disk_info)
+{
+ static com32sys_t getparm, parm, getebios, ebios, inreg,outreg;
+ struct device_parameter dp;
+#ifdef ATA
+ struct ata_identify_device aid;
+#endif
+
+ memset(&(disk_info[disk]), 0, sizeof(struct diskinfo));
+
+ disk_info[disk].disk = disk;
+ disk_info[disk].ebios = disk_info[disk].cbios = 0;
+
+ /* Sending int 13h func 41h to query EBIOS information*/
+ memset(&getebios, 0, sizeof (com32sys_t));
+ memset(&ebios, 0, sizeof (com32sys_t));
+
+ /* Get EBIOS support */
+ getebios.eax.w[0] = 0x4100;
+ getebios.ebx.w[0] = 0x55aa;
+ getebios.edx.b[0] = disk;
+ getebios.eflags.b[0] = 0x3; /* CF set */
+
+ __intcall(0x13, &getebios, &ebios);
+
+ /* Detecting EDD support */
+ if ( !(ebios.eflags.l & EFLAGS_CF) &&
+ ebios.ebx.w[0] == 0xaa55 &&
+ (ebios.ecx.b[0] & 1) ) {
+ disk_info[disk].ebios = 1;
+ switch(ebios.eax.b[1]) {
+ case 32: strlcpy(disk_info[disk].edd_version,"1.0",3); break;
+ case 33: strlcpy(disk_info[disk].edd_version,"1.1",3); break;
+ case 48: strlcpy(disk_info[disk].edd_version,"3.0",3); break;
+ default: strlcpy(disk_info[disk].edd_version,"0",1); break;
+ }
+ }
+ /* Get disk parameters -- really only useful for
+ hard disks, but if we have a partitioned floppy
+ it's actually our best chance... */
+ memset(&getparm, 0, sizeof (com32sys_t));
+ memset(&parm, 0, sizeof (com32sys_t));
+ getparm.eax.b[1] = 0x08;
+ getparm.edx.b[0] = disk;
+
+ __intcall(0x13, &getparm, &parm);
+
+ if ( parm.eflags.l & EFLAGS_CF )
+ return disk_info[disk].ebios ? 0 : -1;
+
+ disk_info[disk].heads = parm.edx.b[1]+1;
+ disk_info[disk].sectors_per_track = parm.ecx.b[0] & 0x3f;
+ if ( disk_info[disk].sectors_per_track == 0 ) {
+ disk_info[disk].sectors_per_track = 1;
+ } else {
+ disk_info[disk].cbios = 1; /* Valid geometry */
+ }
+
+/* FIXME: memset to 0 make it fails
+ * memset(__com32.cs_bounce, 0, sizeof(struct device_pairameter)); */
+ memset(&dp, 0, sizeof(struct device_parameter));
+ memset(&inreg, 0, sizeof(com32sys_t));
+
+ /* Requesting Extended Read Drive Parameters via int13h func 48h*/
+ inreg.esi.w[0] = OFFS(__com32.cs_bounce);
+ inreg.ds = SEG(__com32.cs_bounce);
+ inreg.eax.w[0] = 0x4800;
+ inreg.edx.b[0] = disk;
+
+ __intcall(0x13, &inreg, &outreg);
+
+ /* Saving bounce buffer before anything corrupt it */
+ memcpy(&dp, __com32.cs_bounce, sizeof (struct device_parameter));
+
+ if ( outreg.eflags.l & EFLAGS_CF) {
+ printf("Disk 0x%X doesn't supports EDD 3.0\n",disk);
+ return -1;
+ }
+
+ /* Copying result to the disk_info structure
+ * host_bus_type, interface_type, sectors & cylinders */
+ snprintf(disk_info[disk].host_bus_type,sizeof disk_info[disk].host_bus_type,"%c%c%c%c",dp.host_bus_type[0],dp.host_bus_type[1],dp.host_bus_type[2],dp.host_bus_type[3]);
+ snprintf(disk_info[disk].interface_type,sizeof disk_info[disk].interface_type,"%c%c%c%c%c%c%c%c",dp.interface_type[0],dp.interface_type[1],dp.interface_type[2],dp.interface_type[3],dp.interface_type[4],dp.interface_type[5],dp.interface_type[6],dp.interface_type[7]);
+ disk_info[disk].sectors=dp.sectors;
+ disk_info[disk].cylinders=dp.cylinders;
+
+ /*FIXME: we have to find a way to grab the model & fw
+ * We do put dummy data until we found a solution */
+ snprintf(disk_info[disk].aid.model,sizeof disk_info[disk].aid.model,"0x%X",disk);
+ snprintf(disk_info[disk].aid.fw_rev,sizeof disk_info[disk].aid.fw_rev,"%s","N/A");
+ snprintf(disk_info[disk].aid.serial_no,sizeof disk_info[disk].aid.serial_no,"%s","N/A");
+
+ /* Useless stuff before I figure how to send ata packets */
+#ifdef ATA
+ memset(__com32.cs_bounce, 0, sizeof(struct device_parameter));
+ memset(&aid, 0, sizeof(struct ata_identify_device));
+ memset(&inreg, 0, sizeof inreg);
+ inreg.ebx.w[0] = OFFS(__com32.cs_bounce+1024);
+ inreg.es = SEG(__com32.cs_bounce+1024);
+ inreg.eax.w[0] = 0x2500;
+ inreg.edx.b[0] = disk;
+
+ __intcall(0x13,&inreg, &outreg);
+
+ memcpy(&aid, __com32.cs_bounce, sizeof (struct ata_identify_device));
+
+ if ( outreg.eflags.l & EFLAGS_CF) {
+ printf("Disk 0x%X: Failed to Identify Device\n",disk);
+ //FIXME
+ return 0;
+ }
+// ata_id_c_string(aid, disk_info[disk].fwrev, ATA_ID_FW_REV, sizeof(disk_info[disk].fwrev));
+// ata_id_c_string(aid, disk_info[disk].model, ATA_ID_PROD, sizeof(disk_info[disk].model));
+
+ char buff[sizeof(struct ata_identify_device)];
+ memcpy(buff,&aid, sizeof (struct ata_identify_device));
+ for (int j=0;j<sizeof(struct ata_identify_device);j++)
+ printf ("model=|%c|\n",buff[j]);
+ printf ("Disk 0x%X : %s %s %s\n",disk, aid.model, aid.fw_rev,aid.serial_no);
+#endif
+
+return 0;
+}
+