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 * -----------------------------------------------------------------------
36 #include "hdt-common.h"
41 * ata_id_string - Convert IDENTIFY DEVICE page into string
42 * @id: IDENTIFY DEVICE results we will examine
43 * @s: string into which data is output
44 * @ofs: offset into identify device page
45 * @len: length of string to return. must be an even number.
47 * The strings in the IDENTIFY DEVICE page are broken up into
48 * 16-bit chunks. Run through the string, and output each
49 * 8-bit chunk linearly, regardless of platform.
54 void ata_id_string(const uint16_t * id, unsigned char *s,
55 unsigned int ofs, unsigned int len)
74 * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
75 * @id: IDENTIFY DEVICE results we will examine
76 * @s: string into which data is output
77 * @ofs: offset into identify device page
78 * @len: length of string to return. must be an odd number.
80 * This function is identical to ata_id_string except that it
81 * trims trailing spaces and terminates the resulting string with
82 * null. @len must be actual maximum length (even number) + 1.
87 void ata_id_c_string(const uint16_t * id, unsigned char *s,
88 unsigned int ofs, unsigned int len)
92 //WARN_ON(!(len & 1));
94 ata_id_string(id, s, ofs, len - 1);
96 p = s + strnlen(s, len - 1);
97 while (p > s && p[-1] == ' ')
104 * Call int 13h, but with retry on failure. Especially floppies need this.
106 int int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
108 int retry = 6; /* Number of retries */
115 __intcall(0x13, inreg, outreg);
116 if (!(outreg->eflags.l & EFLAGS_CF))
117 return 0; /* CF=0, OK */
120 return -1; /* Error */
123 /* Display CPU registers for debugging purposes */
124 void printregs(const com32sys_t * r)
126 printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n"
127 "eax = %08x ebx = %08x ecx = %08x edx = %08x\n"
128 "ebp = %08x esi = %08x edi = %08x esp = %08x\n",
129 r->eflags.l, r->ds, r->es, r->fs, r->gs,
130 r->eax.l, r->ebx.l, r->ecx.l, r->edx.l,
131 r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l);
134 /* Try to get information for a given disk */
135 int get_disk_params(int disk, struct diskinfo *disk_info)
137 static com32sys_t getparm, parm, getebios, ebios, inreg, outreg;
138 struct device_parameter dp;
140 struct ata_identify_device aid;
143 memset(&(disk_info[disk]), 0, sizeof(struct diskinfo));
145 disk_info[disk].disk = disk;
146 disk_info[disk].ebios = disk_info[disk].cbios = 0;
148 /* Sending int 13h func 41h to query EBIOS information */
149 memset(&getebios, 0, sizeof(com32sys_t));
150 memset(&ebios, 0, sizeof(com32sys_t));
152 /* Get EBIOS support */
153 getebios.eax.w[0] = 0x4100;
154 getebios.ebx.w[0] = 0x55aa;
155 getebios.edx.b[0] = disk;
156 getebios.eflags.b[0] = 0x3; /* CF set */
158 __intcall(0x13, &getebios, &ebios);
160 /* Detecting EDD support */
161 if (!(ebios.eflags.l & EFLAGS_CF) &&
162 ebios.ebx.w[0] == 0xaa55 && (ebios.ecx.b[0] & 1)) {
163 disk_info[disk].ebios = 1;
164 switch (ebios.eax.b[1]) {
166 strlcpy(disk_info[disk].edd_version, "1.0", 3);
169 strlcpy(disk_info[disk].edd_version, "1.1", 3);
172 strlcpy(disk_info[disk].edd_version, "3.0", 3);
175 strlcpy(disk_info[disk].edd_version, "0", 1);
179 /* Get disk parameters -- really only useful for
180 * hard disks, but if we have a partitioned floppy
181 * it's actually our best chance...
183 memset(&getparm, 0, sizeof(com32sys_t));
184 memset(&parm, 0, sizeof(com32sys_t));
185 getparm.eax.b[1] = 0x08;
186 getparm.edx.b[0] = disk;
188 __intcall(0x13, &getparm, &parm);
190 if (parm.eflags.l & EFLAGS_CF)
191 return disk_info[disk].ebios ? 0 : -1;
193 disk_info[disk].heads = parm.edx.b[1] + 1;
194 disk_info[disk].sectors_per_track = parm.ecx.b[0] & 0x3f;
195 if (disk_info[disk].sectors_per_track == 0) {
196 disk_info[disk].sectors_per_track = 1;
198 disk_info[disk].cbios = 1; /* Valid geometry */
201 /* FIXME: memset to 0 make it fails
202 * memset(__com32.cs_bounce, 0, sizeof(struct device_pairameter)); */
203 memset(&dp, 0, sizeof(struct device_parameter));
204 memset(&inreg, 0, sizeof(com32sys_t));
206 /* Requesting Extended Read Drive Parameters via int13h func 48h */
207 inreg.esi.w[0] = OFFS(__com32.cs_bounce);
208 inreg.ds = SEG(__com32.cs_bounce);
209 inreg.eax.w[0] = 0x4800;
210 inreg.edx.b[0] = disk;
212 __intcall(0x13, &inreg, &outreg);
214 /* Saving bounce buffer before anything corrupt it */
215 memcpy(&dp, __com32.cs_bounce, sizeof(struct device_parameter));
217 if (outreg.eflags.l & EFLAGS_CF) {
218 more_printf("Disk 0x%X doesn't supports EDD 3.0\n", disk);
222 /* Copying result to the disk_info structure
223 * host_bus_type, interface_type, sectors & cylinders */
224 snprintf(disk_info[disk].host_bus_type,
225 sizeof disk_info[disk].host_bus_type, "%c%c%c%c",
226 dp.host_bus_type[0], dp.host_bus_type[1], dp.host_bus_type[2],
227 dp.host_bus_type[3]);
228 snprintf(disk_info[disk].interface_type,
229 sizeof disk_info[disk].interface_type, "%c%c%c%c%c%c%c%c",
230 dp.interface_type[0], dp.interface_type[1],
231 dp.interface_type[2], dp.interface_type[3],
232 dp.interface_type[4], dp.interface_type[5],
233 dp.interface_type[6], dp.interface_type[7]);
234 disk_info[disk].sectors = dp.sectors;
235 disk_info[disk].cylinders = dp.cylinders;
237 /*FIXME: we have to find a way to grab the model & fw
238 * We do put dummy data until we found a solution */
239 snprintf(disk_info[disk].aid.model, sizeof disk_info[disk].aid.model,
241 snprintf(disk_info[disk].aid.fw_rev, sizeof disk_info[disk].aid.fw_rev,
243 snprintf(disk_info[disk].aid.serial_no,
244 sizeof disk_info[disk].aid.serial_no, "%s", "N/A");
246 /* Useless stuff before I figure how to send ata packets */
248 memset(__com32.cs_bounce, 0, sizeof(struct device_parameter));
249 memset(&aid, 0, sizeof(struct ata_identify_device));
250 memset(&inreg, 0, sizeof inreg);
251 inreg.ebx.w[0] = OFFS(__com32.cs_bounce + 1024);
252 inreg.es = SEG(__com32.cs_bounce + 1024);
253 inreg.eax.w[0] = 0x2500;
254 inreg.edx.b[0] = disk;
256 __intcall(0x13, &inreg, &outreg);
258 memcpy(&aid, __com32.cs_bounce, sizeof(struct ata_identify_device));
260 if (outreg.eflags.l & EFLAGS_CF) {
261 more_printf("Disk 0x%X: Failed to Identify Device\n", disk);
265 // ata_id_c_string(aid, disk_info[disk].fwrev, ATA_ID_FW_REV, sizeof(disk_info[disk].fwrev));
266 // ata_id_c_string(aid, disk_info[disk].model, ATA_ID_PROD, sizeof(disk_info[disk].model));
268 char buff[sizeof(struct ata_identify_device)];
269 memcpy(buff, &aid, sizeof(struct ata_identify_device));
270 for (int j = 0; j < sizeof(struct ata_identify_device); j++)
271 more_printf("model=|%c|\n", buff[j]);
272 more_printf("Disk 0x%X : %s %s %s\n", disk, aid.model, aid.fw_rev,