1 /* ----------------------------------------------------------------------- *
3 * Copyright 2009 Erwan Velu - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * -----------------------------------------------------------------------
39 * ata_id_string - Convert IDENTIFY DEVICE page into string
40 * @id: IDENTIFY DEVICE results we will examine
41 * @s: string into which data is output
42 * @ofs: offset into identify device page
43 * @len: length of string to return. must be an even number.
45 * The strings in the IDENTIFY DEVICE page are broken up into
46 * 16-bit chunks. Run through the string, and output each
47 * 8-bit chunk linearly, regardless of platform.
52 void ata_id_string(const uint16_t * id, unsigned char *s,
53 unsigned int ofs, unsigned int len)
72 * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
73 * @id: IDENTIFY DEVICE results we will examine
74 * @s: string into which data is output
75 * @ofs: offset into identify device page
76 * @len: length of string to return. must be an odd number.
78 * This function is identical to ata_id_string except that it
79 * trims trailing spaces and terminates the resulting string with
80 * null. @len must be actual maximum length (even number) + 1.
85 void ata_id_c_string(const uint16_t * id, unsigned char *s,
86 unsigned int ofs, unsigned int len)
90 //WARN_ON(!(len & 1));
92 ata_id_string(id, s, ofs, len - 1);
94 p = s + strnlen(s, len - 1);
95 while (p > s && p[-1] == ' ')
102 * Call int 13h, but with retry on failure. Especially floppies need this.
104 int int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
106 int retry = 6; /* Number of retries */
113 __intcall(0x13, inreg, outreg);
114 if (!(outreg->eflags.l & EFLAGS_CF))
115 return 0; /* CF=0, OK */
118 return -1; /* Error */
121 /* Display CPU registers for debugging purposes */
122 void printregs(const com32sys_t * r)
124 printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n"
125 "eax = %08x ebx = %08x ecx = %08x edx = %08x\n"
126 "ebp = %08x esi = %08x edi = %08x esp = %08x\n",
127 r->eflags.l, r->ds, r->es, r->fs, r->gs,
128 r->eax.l, r->ebx.l, r->ecx.l, r->edx.l,
129 r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l);
132 /* Try to get information for a given disk */
133 int get_disk_params(int disk, struct diskinfo *disk_info)
135 static com32sys_t getparm, parm, getebios, ebios, inreg, outreg;
136 struct device_parameter dp;
138 struct ata_identify_device aid;
141 memset(&(disk_info[disk]), 0, sizeof(struct diskinfo));
143 disk_info[disk].disk = disk;
144 disk_info[disk].ebios = disk_info[disk].cbios = 0;
146 /* Sending int 13h func 41h to query EBIOS information */
147 memset(&getebios, 0, sizeof(com32sys_t));
148 memset(&ebios, 0, sizeof(com32sys_t));
150 /* Get EBIOS support */
151 getebios.eax.w[0] = 0x4100;
152 getebios.ebx.w[0] = 0x55aa;
153 getebios.edx.b[0] = disk;
154 getebios.eflags.b[0] = 0x3; /* CF set */
156 __intcall(0x13, &getebios, &ebios);
158 /* Detecting EDD support */
159 if (!(ebios.eflags.l & EFLAGS_CF) &&
160 ebios.ebx.w[0] == 0xaa55 && (ebios.ecx.b[0] & 1)) {
161 disk_info[disk].ebios = 1;
162 switch (ebios.eax.b[1]) {
164 strlcpy(disk_info[disk].edd_version, "1.0", 3);
167 strlcpy(disk_info[disk].edd_version, "1.1", 3);
170 strlcpy(disk_info[disk].edd_version, "3.0", 3);
173 strlcpy(disk_info[disk].edd_version, "0", 1);
177 /* Get disk parameters -- really only useful for
178 * hard disks, but if we have a partitioned floppy
179 * it's actually our best chance...
181 memset(&getparm, 0, sizeof(com32sys_t));
182 memset(&parm, 0, sizeof(com32sys_t));
183 getparm.eax.b[1] = 0x08;
184 getparm.edx.b[0] = disk;
186 __intcall(0x13, &getparm, &parm);
188 if (parm.eflags.l & EFLAGS_CF)
189 return disk_info[disk].ebios ? 0 : -1;
191 disk_info[disk].heads = parm.edx.b[1] + 1;
192 disk_info[disk].sectors_per_track = parm.ecx.b[0] & 0x3f;
193 if (disk_info[disk].sectors_per_track == 0) {
194 disk_info[disk].sectors_per_track = 1;
196 disk_info[disk].cbios = 1; /* Valid geometry */
199 /* FIXME: memset to 0 make it fails
200 * memset(__com32.cs_bounce, 0, sizeof(struct device_pairameter)); */
201 memset(&dp, 0, sizeof(struct device_parameter));
202 memset(&inreg, 0, sizeof(com32sys_t));
204 /* Requesting Extended Read Drive Parameters via int13h func 48h */
205 inreg.esi.w[0] = OFFS(__com32.cs_bounce);
206 inreg.ds = SEG(__com32.cs_bounce);
207 inreg.eax.w[0] = 0x4800;
208 inreg.edx.b[0] = disk;
210 __intcall(0x13, &inreg, &outreg);
212 /* Saving bounce buffer before anything corrupt it */
213 memcpy(&dp, __com32.cs_bounce, sizeof(struct device_parameter));
215 if (outreg.eflags.l & EFLAGS_CF) {
216 more_printf("Disk 0x%X doesn't supports EDD 3.0\n", disk);
220 /* Copying result to the disk_info structure
221 * host_bus_type, interface_type, sectors & cylinders */
222 snprintf(disk_info[disk].host_bus_type,
223 sizeof disk_info[disk].host_bus_type, "%c%c%c%c",
224 dp.host_bus_type[0], dp.host_bus_type[1], dp.host_bus_type[2],
225 dp.host_bus_type[3]);
226 snprintf(disk_info[disk].interface_type,
227 sizeof disk_info[disk].interface_type, "%c%c%c%c%c%c%c%c",
228 dp.interface_type[0], dp.interface_type[1],
229 dp.interface_type[2], dp.interface_type[3],
230 dp.interface_type[4], dp.interface_type[5],
231 dp.interface_type[6], dp.interface_type[7]);
232 disk_info[disk].sectors = dp.sectors;
233 disk_info[disk].cylinders = dp.cylinders;
235 /*FIXME: we have to find a way to grab the model & fw
236 * We do put dummy data until we found a solution */
237 snprintf(disk_info[disk].aid.model, sizeof disk_info[disk].aid.model,
239 snprintf(disk_info[disk].aid.fw_rev, sizeof disk_info[disk].aid.fw_rev,
241 snprintf(disk_info[disk].aid.serial_no,
242 sizeof disk_info[disk].aid.serial_no, "%s", "N/A");
244 /* Useless stuff before I figure how to send ata packets */
246 memset(__com32.cs_bounce, 0, sizeof(struct device_parameter));
247 memset(&aid, 0, sizeof(struct ata_identify_device));
248 memset(&inreg, 0, sizeof inreg);
249 inreg.ebx.w[0] = OFFS(__com32.cs_bounce + 1024);
250 inreg.es = SEG(__com32.cs_bounce + 1024);
251 inreg.eax.w[0] = 0x2500;
252 inreg.edx.b[0] = disk;
254 __intcall(0x13, &inreg, &outreg);
256 memcpy(&aid, __com32.cs_bounce, sizeof(struct ata_identify_device));
258 if (outreg.eflags.l & EFLAGS_CF) {
259 more_printf("Disk 0x%X: Failed to Identify Device\n", disk);
263 // ata_id_c_string(aid, disk_info[disk].fwrev, ATA_ID_FW_REV, sizeof(disk_info[disk].fwrev));
264 // ata_id_c_string(aid, disk_info[disk].model, ATA_ID_PROD, sizeof(disk_info[disk].model));
266 char buff[sizeof(struct ata_identify_device)];
267 memcpy(buff, &aid, sizeof(struct ata_identify_device));
268 for (int j = 0; j < sizeof(struct ata_identify_device); j++)
269 more_printf("model=|%c|\n", buff[j]);
270 more_printf("Disk 0x%X : %s %s %s\n", disk, aid.model, aid.fw_rev,