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