Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 1 | // Disk setup and access |
| 2 | // |
| 3 | // Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net> |
| 4 | // Copyright (C) 2002 MandrakeSoft S.A. |
| 5 | // |
| 6 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
| 7 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 8 | #include "biosvar.h" // GET_GLOBAL |
Kevin O'Connor | 135f3f6 | 2013-09-14 23:57:26 -0400 | [diff] [blame] | 9 | #include "block.h" // process_op |
Kevin O'Connor | 5d369d8 | 2013-09-02 20:48:46 -0400 | [diff] [blame] | 10 | #include "hw/ata.h" // process_ata_op |
| 11 | #include "hw/ahci.h" // process_ahci_op |
Kevin O'Connor | 5d369d8 | 2013-09-02 20:48:46 -0400 | [diff] [blame] | 12 | #include "hw/blockcmd.h" // cdb_* |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 13 | #include "hw/pci.h" // pci_bdf_to_bus |
Kevin O'Connor | 8b7861c | 2013-09-15 02:29:06 -0400 | [diff] [blame] | 14 | #include "hw/rtc.h" // rtc_read |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 15 | #include "hw/virtio-blk.h" // process_virtio_blk_op |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 16 | #include "malloc.h" // malloc_low |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 17 | #include "output.h" // dprintf |
Kevin O'Connor | 3df600b | 2013-09-14 19:28:55 -0400 | [diff] [blame] | 18 | #include "stacks.h" // stack_hop |
Kevin O'Connor | 135f3f6 | 2013-09-14 23:57:26 -0400 | [diff] [blame] | 19 | #include "std/disk.h" // struct dpte_s |
Kevin O'Connor | fa9c66a | 2013-09-14 19:10:40 -0400 | [diff] [blame] | 20 | #include "string.h" // checksum |
Kevin O'Connor | 135f3f6 | 2013-09-14 23:57:26 -0400 | [diff] [blame] | 21 | #include "util.h" // process_floppy_op |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 22 | |
Kevin O'Connor | 89a2f96 | 2013-02-18 23:36:03 -0500 | [diff] [blame] | 23 | u8 FloppyCount VARFSEG; |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 24 | u8 CDCount; |
Kevin O'Connor | e52ad39 | 2013-02-20 23:48:22 -0500 | [diff] [blame] | 25 | struct drive_s *IDMap[3][BUILD_MAX_EXTDRIVE] VARFSEG; |
Kevin O'Connor | 89a2f96 | 2013-02-18 23:36:03 -0500 | [diff] [blame] | 26 | u8 *bounce_buf_fl VARFSEG; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 27 | |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 28 | struct drive_s * |
| 29 | getDrive(u8 exttype, u8 extdriveoffset) |
| 30 | { |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 31 | if (extdriveoffset >= ARRAY_SIZE(IDMap[0])) |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 32 | return NULL; |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 33 | return GET_GLOBAL(IDMap[exttype][extdriveoffset]); |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 34 | } |
| 35 | |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 36 | int getDriveId(u8 exttype, struct drive_s *drive) |
Gleb Natapov | 4c90a20 | 2010-12-07 13:50:54 +0200 | [diff] [blame] | 37 | { |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 38 | ASSERT32FLAT(); |
Gleb Natapov | 4c90a20 | 2010-12-07 13:50:54 +0200 | [diff] [blame] | 39 | int i; |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 40 | for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++) |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 41 | if (getDrive(exttype, i) == drive) |
Gleb Natapov | 4c90a20 | 2010-12-07 13:50:54 +0200 | [diff] [blame] | 42 | return i; |
Gleb Natapov | 4c90a20 | 2010-12-07 13:50:54 +0200 | [diff] [blame] | 43 | return -1; |
| 44 | } |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 45 | |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 46 | int create_bounce_buf(void) |
Gerd Hoffmann | d7a7cf3 | 2011-08-04 19:36:27 +0200 | [diff] [blame] | 47 | { |
| 48 | if (bounce_buf_fl) |
| 49 | return 0; |
| 50 | |
| 51 | u8 *buf = malloc_low(CDROM_SECTOR_SIZE); |
| 52 | if (!buf) { |
| 53 | warn_noalloc(); |
| 54 | return -1; |
| 55 | } |
| 56 | bounce_buf_fl = buf; |
| 57 | return 0; |
| 58 | } |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 59 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 60 | /**************************************************************** |
| 61 | * Disk geometry translation |
| 62 | ****************************************************************/ |
| 63 | |
| 64 | static u8 |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 65 | get_translation(struct drive_s *drive) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 66 | { |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 67 | u8 type = drive->type; |
Kevin O'Connor | 897fb11 | 2013-02-07 23:32:48 -0500 | [diff] [blame] | 68 | if (CONFIG_QEMU && type == DTYPE_ATA) { |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 69 | // Emulators pass in the translation info via nvram. |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 70 | u8 ataid = drive->cntl_id; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 71 | u8 channel = ataid / 2; |
Kevin O'Connor | 8b7861c | 2013-09-15 02:29:06 -0400 | [diff] [blame] | 72 | u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + channel/2); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 73 | translation >>= 2 * (ataid % 4); |
| 74 | translation &= 0x03; |
| 75 | return translation; |
| 76 | } |
| 77 | |
Kevin O'Connor | d2d1de0 | 2010-02-17 01:07:36 -0500 | [diff] [blame] | 78 | // Otherwise use a heuristic to determine translation type. |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 79 | u16 heads = drive->pchs.head; |
| 80 | u16 cylinders = drive->pchs.cylinder; |
| 81 | u16 spt = drive->pchs.sector; |
| 82 | u64 sectors = drive->sectors; |
Kevin O'Connor | d2d1de0 | 2010-02-17 01:07:36 -0500 | [diff] [blame] | 83 | u64 psectors = (u64)heads * cylinders * spt; |
| 84 | if (!heads || !cylinders || !spt || psectors > sectors) |
| 85 | // pchs doesn't look valid - use LBA. |
| 86 | return TRANSLATION_LBA; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 87 | |
| 88 | if (cylinders <= 1024 && heads <= 16 && spt <= 63) |
| 89 | return TRANSLATION_NONE; |
| 90 | if (cylinders * heads <= 131072) |
| 91 | return TRANSLATION_LARGE; |
| 92 | return TRANSLATION_LBA; |
| 93 | } |
| 94 | |
Kevin O'Connor | 697e63c | 2010-12-27 21:08:53 -0500 | [diff] [blame] | 95 | static void |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 96 | setup_translation(struct drive_s *drive) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 97 | { |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 98 | u8 translation = get_translation(drive); |
| 99 | drive->translation = translation; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 100 | |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 101 | u16 heads = drive->pchs.head ; |
| 102 | u16 cylinders = drive->pchs.cylinder; |
| 103 | u16 spt = drive->pchs.sector; |
| 104 | u64 sectors = drive->sectors; |
Kevin O'Connor | 6f6a74d | 2009-11-09 19:15:50 -0500 | [diff] [blame] | 105 | const char *desc = NULL; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 106 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 107 | switch (translation) { |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 108 | default: |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 109 | case TRANSLATION_NONE: |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 110 | desc = "none"; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 111 | break; |
| 112 | case TRANSLATION_LBA: |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 113 | desc = "lba"; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 114 | spt = 63; |
| 115 | if (sectors > 63*255*1024) { |
| 116 | heads = 255; |
| 117 | cylinders = 1024; |
| 118 | break; |
| 119 | } |
| 120 | u32 sect = (u32)sectors / 63; |
| 121 | heads = sect / 1024; |
| 122 | if (heads>128) |
| 123 | heads = 255; |
| 124 | else if (heads>64) |
| 125 | heads = 128; |
| 126 | else if (heads>32) |
| 127 | heads = 64; |
| 128 | else if (heads>16) |
| 129 | heads = 32; |
| 130 | else |
| 131 | heads = 16; |
| 132 | cylinders = sect / heads; |
| 133 | break; |
| 134 | case TRANSLATION_RECHS: |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 135 | desc = "r-echs"; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 136 | // Take care not to overflow |
| 137 | if (heads==16) { |
| 138 | if (cylinders>61439) |
| 139 | cylinders=61439; |
| 140 | heads=15; |
| 141 | cylinders = (u16)((u32)(cylinders)*16/15); |
| 142 | } |
| 143 | // then go through the large bitshift process |
| 144 | case TRANSLATION_LARGE: |
| 145 | if (translation == TRANSLATION_LARGE) |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 146 | desc = "large"; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 147 | while (cylinders > 1024) { |
| 148 | cylinders >>= 1; |
| 149 | heads <<= 1; |
| 150 | |
| 151 | // If we max out the head count |
| 152 | if (heads > 127) |
| 153 | break; |
| 154 | } |
| 155 | break; |
| 156 | } |
| 157 | // clip to 1024 cylinders in lchs |
| 158 | if (cylinders > 1024) |
| 159 | cylinders = 1024; |
Kevin O'Connor | d2d1de0 | 2010-02-17 01:07:36 -0500 | [diff] [blame] | 160 | dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n" |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 161 | , drive |
| 162 | , drive->pchs.cylinder, drive->pchs.head, drive->pchs.sector |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 163 | , desc |
Kevin O'Connor | d2d1de0 | 2010-02-17 01:07:36 -0500 | [diff] [blame] | 164 | , cylinders, heads, spt |
| 165 | , (u32)sectors); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 166 | |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 167 | drive->lchs.head = heads; |
| 168 | drive->lchs.cylinder = cylinders; |
| 169 | drive->lchs.sector = spt; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | |
| 173 | /**************************************************************** |
| 174 | * Drive mapping |
| 175 | ****************************************************************/ |
| 176 | |
| 177 | // Fill in Fixed Disk Parameter Table (located in ebda). |
| 178 | static void |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 179 | fill_fdpt(struct drive_s *drive, int hdid) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 180 | { |
Kevin O'Connor | 34ec7b0 | 2009-09-20 20:04:06 -0400 | [diff] [blame] | 181 | if (hdid > 1) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 182 | return; |
| 183 | |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 184 | u16 nlc = drive->lchs.cylinder; |
| 185 | u16 nlh = drive->lchs.head; |
| 186 | u16 nls = drive->lchs.sector; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 187 | |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 188 | u16 npc = drive->pchs.cylinder; |
| 189 | u16 nph = drive->pchs.head; |
| 190 | u16 nps = drive->pchs.sector; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 191 | |
Kevin O'Connor | 34ec7b0 | 2009-09-20 20:04:06 -0400 | [diff] [blame] | 192 | struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid]; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 193 | fdpt->precompensation = 0xffff; |
| 194 | fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3); |
| 195 | fdpt->landing_zone = npc; |
| 196 | fdpt->cylinders = nlc; |
| 197 | fdpt->heads = nlh; |
Kevin O'Connor | 8ab9a34 | 2013-09-28 23:34:49 -0400 | [diff] [blame] | 198 | fdpt->sectors = nls; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 199 | |
Kevin O'Connor | 8ab9a34 | 2013-09-28 23:34:49 -0400 | [diff] [blame] | 200 | if (nlc != npc || nlh != nph || nls != nps) { |
Kevin O'Connor | 085debd | 2010-01-03 22:24:18 -0500 | [diff] [blame] | 201 | // Logical mapping present - use extended structure. |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 202 | |
Kevin O'Connor | 085debd | 2010-01-03 22:24:18 -0500 | [diff] [blame] | 203 | // complies with Phoenix style Translated Fixed Disk Parameter |
| 204 | // Table (FDPT) |
| 205 | fdpt->phys_cylinders = npc; |
| 206 | fdpt->phys_heads = nph; |
Kevin O'Connor | 8ab9a34 | 2013-09-28 23:34:49 -0400 | [diff] [blame] | 207 | fdpt->phys_sectors = nps; |
Kevin O'Connor | 085debd | 2010-01-03 22:24:18 -0500 | [diff] [blame] | 208 | fdpt->a0h_signature = 0xa0; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 209 | |
Kevin O'Connor | 085debd | 2010-01-03 22:24:18 -0500 | [diff] [blame] | 210 | // Checksum structure. |
| 211 | fdpt->checksum -= checksum(fdpt, sizeof(*fdpt)); |
| 212 | } |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 213 | |
Kevin O'Connor | 34ec7b0 | 2009-09-20 20:04:06 -0400 | [diff] [blame] | 214 | if (hdid == 0) |
Kevin O'Connor | 9f98542 | 2009-09-09 11:34:39 -0400 | [diff] [blame] | 215 | SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof( |
| 216 | struct extended_bios_data_area_s, fdpt[0]))); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 217 | else |
Kevin O'Connor | 9f98542 | 2009-09-09 11:34:39 -0400 | [diff] [blame] | 218 | SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof( |
| 219 | struct extended_bios_data_area_s, fdpt[1]))); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 220 | } |
| 221 | |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 222 | // Find spot to add a drive |
| 223 | static void |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 224 | add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive) |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 225 | { |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 226 | if (*count >= ARRAY_SIZE(IDMap[0])) { |
Kevin O'Connor | cfdc13f | 2010-02-14 13:07:54 -0500 | [diff] [blame] | 227 | warn_noalloc(); |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 228 | return; |
| 229 | } |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 230 | idmap[*count] = drive; |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 231 | *count = *count + 1; |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 232 | } |
| 233 | |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 234 | // Map a hard drive |
| 235 | void |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 236 | map_hd_drive(struct drive_s *drive) |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 237 | { |
| 238 | ASSERT32FLAT(); |
| 239 | struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); |
| 240 | int hdid = bda->hdcount; |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 241 | dprintf(3, "Mapping hd drive %p to %d\n", drive, hdid); |
| 242 | add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive); |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 243 | |
Kevin O'Connor | 697e63c | 2010-12-27 21:08:53 -0500 | [diff] [blame] | 244 | // Setup disk geometry translation. |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 245 | setup_translation(drive); |
Kevin O'Connor | 697e63c | 2010-12-27 21:08:53 -0500 | [diff] [blame] | 246 | |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 247 | // Fill "fdpt" structure. |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 248 | fill_fdpt(drive, hdid); |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 249 | } |
| 250 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 251 | // Map a cd |
| 252 | void |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 253 | map_cd_drive(struct drive_s *drive) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 254 | { |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 255 | ASSERT32FLAT(); |
| 256 | dprintf(3, "Mapping cd drive %p\n", drive); |
| 257 | add_drive(IDMap[EXTTYPE_CD], &CDCount, drive); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 258 | } |
| 259 | |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 260 | // Map a floppy |
| 261 | void |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 262 | map_floppy_drive(struct drive_s *drive) |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 263 | { |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 264 | ASSERT32FLAT(); |
| 265 | dprintf(3, "Mapping floppy drive %p\n", drive); |
| 266 | add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 267 | |
| 268 | // Update equipment word bits for floppy |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 269 | if (FloppyCount == 1) { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 270 | // 1 drive, ready for boot |
Kevin O'Connor | e51316d | 2012-06-10 09:09:22 -0400 | [diff] [blame] | 271 | set_equipment_flags(0x41, 0x01); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 272 | SET_BDA(floppy_harddisk_info, 0x07); |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 273 | } else if (FloppyCount >= 2) { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 274 | // 2 drives, ready for boot |
Kevin O'Connor | e51316d | 2012-06-10 09:09:22 -0400 | [diff] [blame] | 275 | set_equipment_flags(0x41, 0x41); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 276 | SET_BDA(floppy_harddisk_info, 0x77); |
| 277 | } |
| 278 | } |
| 279 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 280 | |
| 281 | /**************************************************************** |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 282 | * Extended Disk Drive (EDD) get drive parameters |
| 283 | ****************************************************************/ |
| 284 | |
Kevin O'Connor | 9e735bb | 2014-05-10 12:46:57 -0400 | [diff] [blame] | 285 | static int |
| 286 | fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf |
| 287 | , u32 dpte_so, char *iface_type |
| 288 | , int bdf, u8 channel, u16 iobase, u64 device_path) |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 289 | { |
| 290 | u16 size = GET_FARVAR(seg, param_far->size); |
| 291 | u16 t13 = size == 74; |
| 292 | |
| 293 | // Buffer is too small |
| 294 | if (size < 26) |
| 295 | return DISK_RET_EPARAM; |
| 296 | |
| 297 | // EDD 1.x |
| 298 | |
| 299 | u8 type = GET_GLOBALFLAT(drive_gf->type); |
| 300 | u16 npc = GET_GLOBALFLAT(drive_gf->pchs.cylinder); |
| 301 | u16 nph = GET_GLOBALFLAT(drive_gf->pchs.head); |
| 302 | u16 nps = GET_GLOBALFLAT(drive_gf->pchs.sector); |
| 303 | u64 lba = GET_GLOBALFLAT(drive_gf->sectors); |
| 304 | u16 blksize = GET_GLOBALFLAT(drive_gf->blksize); |
| 305 | |
| 306 | dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n" |
| 307 | , size, type, npc, nph, nps, (u32)lba, blksize); |
| 308 | |
| 309 | SET_FARVAR(seg, param_far->size, 26); |
Kevin O'Connor | f8387e2 | 2014-05-10 11:54:48 -0400 | [diff] [blame] | 310 | if (lba == (u64)-1) { |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 311 | // 0x74 = removable, media change, lockable, max values |
| 312 | SET_FARVAR(seg, param_far->infos, 0x74); |
| 313 | SET_FARVAR(seg, param_far->cylinders, 0xffffffff); |
| 314 | SET_FARVAR(seg, param_far->heads, 0xffffffff); |
| 315 | SET_FARVAR(seg, param_far->spt, 0xffffffff); |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 316 | } else { |
| 317 | if (lba > (u64)nps*nph*0x3fff) { |
| 318 | SET_FARVAR(seg, param_far->infos, 0x00); // geometry is invalid |
| 319 | SET_FARVAR(seg, param_far->cylinders, 0x3fff); |
| 320 | } else { |
| 321 | SET_FARVAR(seg, param_far->infos, 0x02); // geometry is valid |
| 322 | SET_FARVAR(seg, param_far->cylinders, (u32)npc); |
| 323 | } |
| 324 | SET_FARVAR(seg, param_far->heads, (u32)nph); |
| 325 | SET_FARVAR(seg, param_far->spt, (u32)nps); |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 326 | } |
Kevin O'Connor | f8387e2 | 2014-05-10 11:54:48 -0400 | [diff] [blame] | 327 | SET_FARVAR(seg, param_far->sector_count, lba); |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 328 | SET_FARVAR(seg, param_far->blksize, blksize); |
| 329 | |
Kevin O'Connor | 9e735bb | 2014-05-10 12:46:57 -0400 | [diff] [blame] | 330 | if (size < 30 || !dpte_so) |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 331 | return DISK_RET_SUCCESS; |
| 332 | |
| 333 | // EDD 2.x |
| 334 | |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 335 | SET_FARVAR(seg, param_far->size, 30); |
Kevin O'Connor | 9e735bb | 2014-05-10 12:46:57 -0400 | [diff] [blame] | 336 | SET_FARVAR(seg, param_far->dpte.segoff, dpte_so); |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 337 | |
Kevin O'Connor | 9e735bb | 2014-05-10 12:46:57 -0400 | [diff] [blame] | 338 | if (size < 66 || !iface_type) |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 339 | return DISK_RET_SUCCESS; |
| 340 | |
| 341 | // EDD 3.x |
| 342 | SET_FARVAR(seg, param_far->key, 0xbedd); |
| 343 | SET_FARVAR(seg, param_far->dpi_length, t13 ? 44 : 36); |
| 344 | SET_FARVAR(seg, param_far->reserved1, 0); |
| 345 | SET_FARVAR(seg, param_far->reserved2, 0); |
| 346 | |
Kevin O'Connor | 9e735bb | 2014-05-10 12:46:57 -0400 | [diff] [blame] | 347 | int i; |
| 348 | for (i=0; i<sizeof(param_far->iface_type); i++) |
| 349 | SET_FARVAR(seg, param_far->iface_type[i], GET_GLOBAL(iface_type[i])); |
| 350 | |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 351 | if (bdf != -1) { |
| 352 | SET_FARVAR(seg, param_far->host_bus[0], 'P'); |
| 353 | SET_FARVAR(seg, param_far->host_bus[1], 'C'); |
| 354 | SET_FARVAR(seg, param_far->host_bus[2], 'I'); |
| 355 | SET_FARVAR(seg, param_far->host_bus[3], ' '); |
| 356 | |
| 357 | u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8) |
| 358 | | (pci_bdf_to_fn(bdf) << 16)); |
| 359 | if (t13) |
| 360 | path |= channel << 24; |
| 361 | |
| 362 | SET_FARVAR(seg, param_far->iface_path, path); |
| 363 | } else { |
| 364 | // ISA |
| 365 | SET_FARVAR(seg, param_far->host_bus[0], 'I'); |
| 366 | SET_FARVAR(seg, param_far->host_bus[1], 'S'); |
| 367 | SET_FARVAR(seg, param_far->host_bus[2], 'A'); |
| 368 | SET_FARVAR(seg, param_far->host_bus[3], ' '); |
| 369 | |
Kevin O'Connor | 9e735bb | 2014-05-10 12:46:57 -0400 | [diff] [blame] | 370 | SET_FARVAR(seg, param_far->iface_path, iobase); |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 371 | } |
| 372 | |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 373 | if (t13) { |
| 374 | SET_FARVAR(seg, param_far->t13.device_path[0], device_path); |
| 375 | SET_FARVAR(seg, param_far->t13.device_path[1], 0); |
| 376 | |
| 377 | SET_FARVAR(seg, param_far->t13.checksum |
| 378 | , -checksum_far(seg, (void*)param_far+30, 43)); |
| 379 | } else { |
| 380 | SET_FARVAR(seg, param_far->phoenix.device_path, device_path); |
| 381 | |
| 382 | SET_FARVAR(seg, param_far->phoenix.checksum |
| 383 | , -checksum_far(seg, (void*)param_far+30, 35)); |
| 384 | } |
| 385 | |
| 386 | return DISK_RET_SUCCESS; |
| 387 | } |
| 388 | |
Kevin O'Connor | 9e735bb | 2014-05-10 12:46:57 -0400 | [diff] [blame] | 389 | struct dpte_s DefaultDPTE VARLOW; |
| 390 | |
| 391 | static int |
| 392 | fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf) |
| 393 | { |
| 394 | if (!CONFIG_ATA) |
| 395 | return DISK_RET_EPARAM; |
| 396 | |
| 397 | // Fill in dpte |
| 398 | struct atadrive_s *adrive_gf = container_of( |
| 399 | drive_gf, struct atadrive_s, drive); |
| 400 | struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); |
| 401 | u8 slave = GET_GLOBALFLAT(adrive_gf->slave); |
| 402 | u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); |
| 403 | u8 irq = GET_GLOBALFLAT(chan_gf->irq); |
| 404 | u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); |
| 405 | int bdf = GET_GLOBALFLAT(chan_gf->pci_bdf); |
| 406 | u8 channel = GET_GLOBALFLAT(chan_gf->chanid); |
| 407 | |
| 408 | u16 options = 0; |
| 409 | if (GET_GLOBALFLAT(drive_gf->type) == DTYPE_ATA) { |
| 410 | u8 translation = GET_GLOBALFLAT(drive_gf->translation); |
| 411 | if (translation != TRANSLATION_NONE) { |
| 412 | options |= 1<<3; // CHS translation |
| 413 | if (translation == TRANSLATION_LBA) |
| 414 | options |= 1<<9; |
| 415 | if (translation == TRANSLATION_RECHS) |
| 416 | options |= 3<<9; |
| 417 | } |
| 418 | } else { |
| 419 | // ATAPI |
| 420 | options |= 1<<5; // removable device |
| 421 | options |= 1<<6; // atapi device |
| 422 | } |
| 423 | options |= 1<<4; // lba translation |
| 424 | if (CONFIG_ATA_PIO32) |
| 425 | options |= 1<<7; |
| 426 | |
| 427 | SET_LOW(DefaultDPTE.iobase1, iobase1); |
| 428 | SET_LOW(DefaultDPTE.iobase2, iobase2 + ATA_CB_DC); |
| 429 | SET_LOW(DefaultDPTE.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) |
| 430 | | ATA_CB_DH_LBA)); |
| 431 | SET_LOW(DefaultDPTE.unused, 0xcb); |
| 432 | SET_LOW(DefaultDPTE.irq, irq); |
| 433 | SET_LOW(DefaultDPTE.blkcount, 1); |
| 434 | SET_LOW(DefaultDPTE.dma, 0); |
| 435 | SET_LOW(DefaultDPTE.pio, 0); |
| 436 | SET_LOW(DefaultDPTE.options, options); |
| 437 | SET_LOW(DefaultDPTE.reserved, 0); |
| 438 | SET_LOW(DefaultDPTE.revision, 0x11); |
| 439 | |
| 440 | u8 sum = checksum_far(SEG_LOW, &DefaultDPTE, 15); |
| 441 | SET_LOW(DefaultDPTE.checksum, -sum); |
| 442 | |
| 443 | return fill_generic_edd( |
| 444 | seg, param_far, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff |
| 445 | , "ATA ", bdf, channel, iobase1, slave); |
| 446 | } |
| 447 | |
| 448 | int noinline |
| 449 | fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf) |
| 450 | { |
| 451 | switch (GET_GLOBALFLAT(drive_gf->type)) { |
| 452 | case DTYPE_ATA: |
| 453 | case DTYPE_ATA_ATAPI: |
| 454 | return fill_ata_edd(seg, param_far, drive_gf); |
| 455 | case DTYPE_VIRTIO_BLK: |
| 456 | case DTYPE_VIRTIO_SCSI: |
| 457 | return fill_generic_edd( |
| 458 | seg, param_far, drive_gf, 0xffffffff |
| 459 | , "SCSI ", GET_GLOBALFLAT(drive_gf->cntl_id), 0, 0, 0); |
| 460 | default: |
| 461 | return fill_generic_edd(seg, param_far, drive_gf, 0, NULL, 0, 0, 0, 0); |
| 462 | } |
| 463 | } |
| 464 | |
Kevin O'Connor | 39ca498 | 2014-05-10 11:42:22 -0400 | [diff] [blame] | 465 | |
| 466 | /**************************************************************** |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 467 | * 16bit calling interface |
| 468 | ****************************************************************/ |
| 469 | |
Kevin O'Connor | 4b400a1 | 2013-12-24 00:46:15 -0500 | [diff] [blame] | 470 | int VISIBLE32FLAT |
Paolo Bonzini | 1e749c8 | 2011-11-16 13:02:53 +0100 | [diff] [blame] | 471 | process_scsi_op(struct disk_op_s *op) |
| 472 | { |
Paolo Bonzini | 1e749c8 | 2011-11-16 13:02:53 +0100 | [diff] [blame] | 473 | switch (op->command) { |
| 474 | case CMD_READ: |
| 475 | return cdb_read(op); |
| 476 | case CMD_WRITE: |
| 477 | return cdb_write(op); |
| 478 | case CMD_FORMAT: |
| 479 | case CMD_RESET: |
| 480 | case CMD_ISREADY: |
| 481 | case CMD_VERIFY: |
| 482 | case CMD_SEEK: |
| 483 | return DISK_RET_SUCCESS; |
| 484 | default: |
Paolo Bonzini | 1e749c8 | 2011-11-16 13:02:53 +0100 | [diff] [blame] | 485 | return DISK_RET_EPARAM; |
| 486 | } |
| 487 | } |
| 488 | |
Kevin O'Connor | 7c80bb8 | 2013-10-02 21:28:08 -0400 | [diff] [blame] | 489 | int VISIBLE32FLAT |
Kevin O'Connor | bd6afe5 | 2012-07-21 12:01:12 -0400 | [diff] [blame] | 490 | process_atapi_op(struct disk_op_s *op) |
| 491 | { |
| 492 | switch (op->command) { |
| 493 | case CMD_WRITE: |
| 494 | case CMD_FORMAT: |
| 495 | return DISK_RET_EWRITEPROTECT; |
| 496 | default: |
| 497 | return process_scsi_op(op); |
| 498 | } |
| 499 | } |
| 500 | |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 501 | // Execute a disk_op request. |
Kevin O'Connor | 36c93a5 | 2009-09-12 19:35:04 -0400 | [diff] [blame] | 502 | int |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 503 | process_op(struct disk_op_s *op) |
| 504 | { |
Kevin O'Connor | d7e998f | 2010-02-15 22:48:28 -0500 | [diff] [blame] | 505 | ASSERT16(); |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 506 | int ret, origcount = op->count; |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 507 | u8 type = GET_GLOBALFLAT(op->drive_gf->type); |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 508 | switch (type) { |
Kevin O'Connor | a3855ad | 2009-08-16 21:59:40 -0400 | [diff] [blame] | 509 | case DTYPE_FLOPPY: |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 510 | ret = process_floppy_op(op); |
| 511 | break; |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 512 | case DTYPE_ATA: |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 513 | ret = process_ata_op(op); |
| 514 | break; |
Kevin O'Connor | a3855ad | 2009-08-16 21:59:40 -0400 | [diff] [blame] | 515 | case DTYPE_RAMDISK: |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 516 | ret = process_ramdisk_op(op); |
| 517 | break; |
Kevin O'Connor | 36c93a5 | 2009-09-12 19:35:04 -0400 | [diff] [blame] | 518 | case DTYPE_CDEMU: |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 519 | ret = process_cdemu_op(op); |
| 520 | break; |
Paolo Bonzini | 0e7fb5f | 2011-11-16 13:02:55 +0100 | [diff] [blame] | 521 | case DTYPE_VIRTIO_BLK: |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 522 | ret = process_virtio_blk_op(op); |
| 523 | break; |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 524 | case DTYPE_AHCI: ; |
Kevin O'Connor | 7c80bb8 | 2013-10-02 21:28:08 -0400 | [diff] [blame] | 525 | extern void _cfunc32flat_process_ahci_op(void); |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 526 | ret = call32(_cfunc32flat_process_ahci_op |
| 527 | , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); |
| 528 | break; |
Kevin O'Connor | bd6afe5 | 2012-07-21 12:01:12 -0400 | [diff] [blame] | 529 | case DTYPE_ATA_ATAPI: |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 530 | ret = process_atapi_op(op); |
| 531 | break; |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 532 | case DTYPE_AHCI_ATAPI: ; |
Kevin O'Connor | 7c80bb8 | 2013-10-02 21:28:08 -0400 | [diff] [blame] | 533 | extern void _cfunc32flat_process_atapi_op(void); |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 534 | ret = call32(_cfunc32flat_process_atapi_op |
| 535 | , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); |
| 536 | break; |
Paolo Bonzini | 1e749c8 | 2011-11-16 13:02:53 +0100 | [diff] [blame] | 537 | case DTYPE_USB: |
Gerd Hoffmann | e53e30d | 2012-07-20 10:59:24 +0200 | [diff] [blame] | 538 | case DTYPE_UAS: |
Paolo Bonzini | c5c488f | 2012-02-27 17:22:23 +0100 | [diff] [blame] | 539 | case DTYPE_VIRTIO_SCSI: |
Gerd Hoffmann | 9d6bac1 | 2012-07-20 10:59:25 +0200 | [diff] [blame] | 540 | case DTYPE_LSI_SCSI: |
Paolo Bonzini | 7a39e72 | 2012-08-06 13:15:06 +0200 | [diff] [blame] | 541 | case DTYPE_ESP_SCSI: |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 542 | case DTYPE_MEGASAS: |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 543 | ret = process_scsi_op(op); |
| 544 | break; |
Kevin O'Connor | de30dad | 2013-12-30 22:09:04 -0500 | [diff] [blame] | 545 | case DTYPE_USB_32: |
| 546 | case DTYPE_UAS_32: |
Kevin O'Connor | 4b400a1 | 2013-12-24 00:46:15 -0500 | [diff] [blame] | 547 | case DTYPE_PVSCSI: ; |
| 548 | extern void _cfunc32flat_process_scsi_op(void); |
| 549 | ret = call32(_cfunc32flat_process_scsi_op |
| 550 | , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); |
| 551 | break; |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 552 | default: |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 553 | ret = DISK_RET_EPARAM; |
| 554 | break; |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 555 | } |
Kevin O'Connor | 518955f | 2013-12-17 17:57:48 -0500 | [diff] [blame] | 556 | if (ret && op->count == origcount) |
| 557 | // If the count hasn't changed on error, assume no data transferred. |
| 558 | op->count = 0; |
| 559 | return ret; |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 560 | } |
| 561 | |
Kevin O'Connor | 46b8262 | 2012-05-13 12:10:30 -0400 | [diff] [blame] | 562 | // Execute a "disk_op_s" request - this runs on the extra stack. |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 563 | static int |
| 564 | __send_disk_op(struct disk_op_s *op_far, u16 op_seg) |
| 565 | { |
| 566 | struct disk_op_s dop; |
| 567 | memcpy_far(GET_SEG(SS), &dop |
| 568 | , op_seg, op_far |
| 569 | , sizeof(dop)); |
| 570 | |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 571 | dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n" |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 572 | , dop.drive_gf, (u32)dop.lba, dop.buf_fl |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 573 | , dop.count, dop.command); |
| 574 | |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 575 | int status = process_op(&dop); |
| 576 | |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 577 | // Update count with total sectors transferred. |
| 578 | SET_FARVAR(op_seg, op_far->count, dop.count); |
| 579 | |
| 580 | return status; |
| 581 | } |
| 582 | |
Kevin O'Connor | 46b8262 | 2012-05-13 12:10:30 -0400 | [diff] [blame] | 583 | // Execute a "disk_op_s" request by jumping to the extra 16bit stack. |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 584 | int |
| 585 | send_disk_op(struct disk_op_s *op) |
| 586 | { |
Kevin O'Connor | d7e998f | 2010-02-15 22:48:28 -0500 | [diff] [blame] | 587 | ASSERT16(); |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 588 | if (! CONFIG_DRIVES) |
| 589 | return -1; |
| 590 | |
Kevin O'Connor | bca0736 | 2010-03-20 20:41:38 -0400 | [diff] [blame] | 591 | return stack_hop((u32)op, GET_SEG(SS), __send_disk_op); |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 592 | } |