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 | |
| 8 | #include "disk.h" // struct ata_s |
| 9 | #include "biosvar.h" // GET_GLOBAL |
| 10 | #include "cmos.h" // inb_cmos |
| 11 | #include "util.h" // dprintf |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 12 | #include "ata.h" // process_ata_op |
Gerd Hoffmann | d52fdf6 | 2010-11-29 09:42:13 +0100 | [diff] [blame] | 13 | #include "ahci.h" // process_ahci_op |
Paolo Bonzini | 0e7fb5f | 2011-11-16 13:02:55 +0100 | [diff] [blame^] | 14 | #include "virtio-blk.h" // process_virtio_blk_op |
Paolo Bonzini | 1e749c8 | 2011-11-16 13:02:53 +0100 | [diff] [blame] | 15 | #include "blockcmd.h" // cdb_* |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 16 | |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 17 | u8 FloppyCount VAR16VISIBLE; |
| 18 | u8 CDCount; |
| 19 | struct drive_s *IDMap[3][CONFIG_MAX_EXTDRIVE] VAR16VISIBLE; |
Gerd Hoffmann | d7a7cf3 | 2011-08-04 19:36:27 +0200 | [diff] [blame] | 20 | u8 *bounce_buf_fl VAR16VISIBLE; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 21 | |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 22 | struct drive_s * |
| 23 | getDrive(u8 exttype, u8 extdriveoffset) |
| 24 | { |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 25 | if (extdriveoffset >= ARRAY_SIZE(IDMap[0])) |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 26 | return NULL; |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 27 | struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]); |
Kevin O'Connor | 8f469b9 | 2010-02-28 01:28:11 -0500 | [diff] [blame] | 28 | if (!drive_gf) |
| 29 | return NULL; |
| 30 | return GLOBALFLAT2GLOBAL(drive_gf); |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 31 | } |
| 32 | |
Gleb Natapov | 4c90a20 | 2010-12-07 13:50:54 +0200 | [diff] [blame] | 33 | int getDriveId(u8 exttype, struct drive_s *drive_g) |
| 34 | { |
| 35 | int i; |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 36 | for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++) |
Gleb Natapov | 4c90a20 | 2010-12-07 13:50:54 +0200 | [diff] [blame] | 37 | if (getDrive(exttype, i) == drive_g) |
| 38 | return i; |
Gleb Natapov | 4c90a20 | 2010-12-07 13:50:54 +0200 | [diff] [blame] | 39 | return -1; |
| 40 | } |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 41 | |
Gerd Hoffmann | d7a7cf3 | 2011-08-04 19:36:27 +0200 | [diff] [blame] | 42 | int bounce_buf_init(void) |
| 43 | { |
| 44 | if (bounce_buf_fl) |
| 45 | return 0; |
| 46 | |
| 47 | u8 *buf = malloc_low(CDROM_SECTOR_SIZE); |
| 48 | if (!buf) { |
| 49 | warn_noalloc(); |
| 50 | return -1; |
| 51 | } |
| 52 | bounce_buf_fl = buf; |
| 53 | return 0; |
| 54 | } |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 55 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 56 | /**************************************************************** |
| 57 | * Disk geometry translation |
| 58 | ****************************************************************/ |
| 59 | |
| 60 | static u8 |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 61 | get_translation(struct drive_s *drive_g) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 62 | { |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 63 | u8 type = GET_GLOBAL(drive_g->type); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 64 | if (! CONFIG_COREBOOT && type == DTYPE_ATA) { |
| 65 | // Emulators pass in the translation info via nvram. |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 66 | u8 ataid = GET_GLOBAL(drive_g->cntl_id); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 67 | u8 channel = ataid / 2; |
| 68 | u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2); |
| 69 | translation >>= 2 * (ataid % 4); |
| 70 | translation &= 0x03; |
| 71 | return translation; |
| 72 | } |
| 73 | |
Kevin O'Connor | d2d1de0 | 2010-02-17 01:07:36 -0500 | [diff] [blame] | 74 | // Otherwise use a heuristic to determine translation type. |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 75 | u16 heads = GET_GLOBAL(drive_g->pchs.heads); |
| 76 | u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders); |
| 77 | u16 spt = GET_GLOBAL(drive_g->pchs.spt); |
Kevin O'Connor | d2d1de0 | 2010-02-17 01:07:36 -0500 | [diff] [blame] | 78 | u64 sectors = GET_GLOBAL(drive_g->sectors); |
| 79 | u64 psectors = (u64)heads * cylinders * spt; |
| 80 | if (!heads || !cylinders || !spt || psectors > sectors) |
| 81 | // pchs doesn't look valid - use LBA. |
| 82 | return TRANSLATION_LBA; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 83 | |
| 84 | if (cylinders <= 1024 && heads <= 16 && spt <= 63) |
| 85 | return TRANSLATION_NONE; |
| 86 | if (cylinders * heads <= 131072) |
| 87 | return TRANSLATION_LARGE; |
| 88 | return TRANSLATION_LBA; |
| 89 | } |
| 90 | |
Kevin O'Connor | 697e63c | 2010-12-27 21:08:53 -0500 | [diff] [blame] | 91 | static void |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 92 | setup_translation(struct drive_s *drive_g) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 93 | { |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 94 | u8 translation = get_translation(drive_g); |
| 95 | SET_GLOBAL(drive_g->translation, translation); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 96 | |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 97 | u16 heads = GET_GLOBAL(drive_g->pchs.heads); |
| 98 | u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders); |
| 99 | u16 spt = GET_GLOBAL(drive_g->pchs.spt); |
| 100 | u64 sectors = GET_GLOBAL(drive_g->sectors); |
Kevin O'Connor | 6f6a74d | 2009-11-09 19:15:50 -0500 | [diff] [blame] | 101 | const char *desc = NULL; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 102 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 103 | switch (translation) { |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 104 | default: |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 105 | case TRANSLATION_NONE: |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 106 | desc = "none"; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 107 | break; |
| 108 | case TRANSLATION_LBA: |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 109 | desc = "lba"; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 110 | spt = 63; |
| 111 | if (sectors > 63*255*1024) { |
| 112 | heads = 255; |
| 113 | cylinders = 1024; |
| 114 | break; |
| 115 | } |
| 116 | u32 sect = (u32)sectors / 63; |
| 117 | heads = sect / 1024; |
| 118 | if (heads>128) |
| 119 | heads = 255; |
| 120 | else if (heads>64) |
| 121 | heads = 128; |
| 122 | else if (heads>32) |
| 123 | heads = 64; |
| 124 | else if (heads>16) |
| 125 | heads = 32; |
| 126 | else |
| 127 | heads = 16; |
| 128 | cylinders = sect / heads; |
| 129 | break; |
| 130 | case TRANSLATION_RECHS: |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 131 | desc = "r-echs"; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 132 | // Take care not to overflow |
| 133 | if (heads==16) { |
| 134 | if (cylinders>61439) |
| 135 | cylinders=61439; |
| 136 | heads=15; |
| 137 | cylinders = (u16)((u32)(cylinders)*16/15); |
| 138 | } |
| 139 | // then go through the large bitshift process |
| 140 | case TRANSLATION_LARGE: |
| 141 | if (translation == TRANSLATION_LARGE) |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 142 | desc = "large"; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 143 | while (cylinders > 1024) { |
| 144 | cylinders >>= 1; |
| 145 | heads <<= 1; |
| 146 | |
| 147 | // If we max out the head count |
| 148 | if (heads > 127) |
| 149 | break; |
| 150 | } |
| 151 | break; |
| 152 | } |
| 153 | // clip to 1024 cylinders in lchs |
| 154 | if (cylinders > 1024) |
| 155 | cylinders = 1024; |
Kevin O'Connor | d2d1de0 | 2010-02-17 01:07:36 -0500 | [diff] [blame] | 156 | dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n" |
| 157 | , drive_g |
Kevin O'Connor | c604f2f | 2009-10-24 19:56:11 -0400 | [diff] [blame] | 158 | , drive_g->pchs.cylinders, drive_g->pchs.heads, drive_g->pchs.spt |
| 159 | , desc |
Kevin O'Connor | d2d1de0 | 2010-02-17 01:07:36 -0500 | [diff] [blame] | 160 | , cylinders, heads, spt |
| 161 | , (u32)sectors); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 162 | |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 163 | SET_GLOBAL(drive_g->lchs.heads, heads); |
| 164 | SET_GLOBAL(drive_g->lchs.cylinders, cylinders); |
| 165 | SET_GLOBAL(drive_g->lchs.spt, spt); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | |
| 169 | /**************************************************************** |
| 170 | * Drive mapping |
| 171 | ****************************************************************/ |
| 172 | |
| 173 | // Fill in Fixed Disk Parameter Table (located in ebda). |
| 174 | static void |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 175 | fill_fdpt(struct drive_s *drive_g, int hdid) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 176 | { |
Kevin O'Connor | 34ec7b0 | 2009-09-20 20:04:06 -0400 | [diff] [blame] | 177 | if (hdid > 1) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 178 | return; |
| 179 | |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 180 | u16 nlc = GET_GLOBAL(drive_g->lchs.cylinders); |
| 181 | u16 nlh = GET_GLOBAL(drive_g->lchs.heads); |
| 182 | u16 nlspt = GET_GLOBAL(drive_g->lchs.spt); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 183 | |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 184 | u16 npc = GET_GLOBAL(drive_g->pchs.cylinders); |
| 185 | u16 nph = GET_GLOBAL(drive_g->pchs.heads); |
| 186 | u16 npspt = GET_GLOBAL(drive_g->pchs.spt); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 187 | |
Kevin O'Connor | 34ec7b0 | 2009-09-20 20:04:06 -0400 | [diff] [blame] | 188 | struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid]; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 189 | fdpt->precompensation = 0xffff; |
| 190 | fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3); |
| 191 | fdpt->landing_zone = npc; |
| 192 | fdpt->cylinders = nlc; |
| 193 | fdpt->heads = nlh; |
| 194 | fdpt->sectors = nlspt; |
| 195 | |
Kevin O'Connor | 085debd | 2010-01-03 22:24:18 -0500 | [diff] [blame] | 196 | if (nlc != npc || nlh != nph || nlspt != npspt) { |
| 197 | // Logical mapping present - use extended structure. |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 198 | |
Kevin O'Connor | 085debd | 2010-01-03 22:24:18 -0500 | [diff] [blame] | 199 | // complies with Phoenix style Translated Fixed Disk Parameter |
| 200 | // Table (FDPT) |
| 201 | fdpt->phys_cylinders = npc; |
| 202 | fdpt->phys_heads = nph; |
| 203 | fdpt->phys_sectors = npspt; |
| 204 | fdpt->a0h_signature = 0xa0; |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 205 | |
Kevin O'Connor | 085debd | 2010-01-03 22:24:18 -0500 | [diff] [blame] | 206 | // Checksum structure. |
| 207 | fdpt->checksum -= checksum(fdpt, sizeof(*fdpt)); |
| 208 | } |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 209 | |
Kevin O'Connor | 34ec7b0 | 2009-09-20 20:04:06 -0400 | [diff] [blame] | 210 | if (hdid == 0) |
Kevin O'Connor | 9f98542 | 2009-09-09 11:34:39 -0400 | [diff] [blame] | 211 | SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof( |
| 212 | struct extended_bios_data_area_s, fdpt[0]))); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 213 | else |
Kevin O'Connor | 9f98542 | 2009-09-09 11:34:39 -0400 | [diff] [blame] | 214 | SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof( |
| 215 | struct extended_bios_data_area_s, fdpt[1]))); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 216 | } |
| 217 | |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 218 | // Find spot to add a drive |
| 219 | static void |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 220 | add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive_g) |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 221 | { |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 222 | if (*count >= ARRAY_SIZE(IDMap[0])) { |
Kevin O'Connor | cfdc13f | 2010-02-14 13:07:54 -0500 | [diff] [blame] | 223 | warn_noalloc(); |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 224 | return; |
| 225 | } |
Kevin O'Connor | 72eee3e | 2010-12-27 19:07:49 -0500 | [diff] [blame] | 226 | idmap[*count] = drive_g; |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 227 | *count = *count + 1; |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 228 | } |
| 229 | |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 230 | // Map a hard drive |
| 231 | void |
| 232 | map_hd_drive(struct drive_s *drive_g) |
| 233 | { |
| 234 | ASSERT32FLAT(); |
| 235 | struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); |
| 236 | int hdid = bda->hdcount; |
| 237 | dprintf(3, "Mapping hd drive %p to %d\n", drive_g, hdid); |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 238 | add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g); |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 239 | |
Kevin O'Connor | 697e63c | 2010-12-27 21:08:53 -0500 | [diff] [blame] | 240 | // Setup disk geometry translation. |
| 241 | setup_translation(drive_g); |
| 242 | |
Kevin O'Connor | 3c5e0e1 | 2010-12-27 08:37:38 -0500 | [diff] [blame] | 243 | // Fill "fdpt" structure. |
| 244 | fill_fdpt(drive_g, hdid); |
| 245 | } |
| 246 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 247 | // Map a cd |
| 248 | void |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 249 | map_cd_drive(struct drive_s *drive_g) |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 250 | { |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 251 | dprintf(3, "Mapping cd drive %p\n", drive_g); |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 252 | add_drive(IDMap[EXTTYPE_CD], &CDCount, drive_g); |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 253 | } |
| 254 | |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 255 | // Map a floppy |
| 256 | void |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 257 | map_floppy_drive(struct drive_s *drive_g) |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 258 | { |
Kevin O'Connor | d254dc2 | 2009-11-25 18:49:06 -0500 | [diff] [blame] | 259 | dprintf(3, "Mapping floppy drive %p\n", drive_g); |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 260 | add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive_g); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 261 | |
| 262 | // Update equipment word bits for floppy |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 263 | if (FloppyCount == 1) { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 264 | // 1 drive, ready for boot |
| 265 | SETBITS_BDA(equipment_list_flags, 0x01); |
| 266 | SET_BDA(floppy_harddisk_info, 0x07); |
Kevin O'Connor | a0842f8 | 2010-12-29 11:05:46 -0500 | [diff] [blame] | 267 | } else if (FloppyCount >= 2) { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 268 | // 2 drives, ready for boot |
| 269 | SETBITS_BDA(equipment_list_flags, 0x41); |
| 270 | SET_BDA(floppy_harddisk_info, 0x77); |
| 271 | } |
| 272 | } |
| 273 | |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 274 | |
| 275 | /**************************************************************** |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 276 | * 16bit calling interface |
| 277 | ****************************************************************/ |
| 278 | |
Paolo Bonzini | 1e749c8 | 2011-11-16 13:02:53 +0100 | [diff] [blame] | 279 | int |
| 280 | process_scsi_op(struct disk_op_s *op) |
| 281 | { |
| 282 | if (!CONFIG_USB_MSC) |
| 283 | return 0; |
| 284 | switch (op->command) { |
| 285 | case CMD_READ: |
| 286 | return cdb_read(op); |
| 287 | case CMD_WRITE: |
| 288 | return cdb_write(op); |
| 289 | case CMD_FORMAT: |
| 290 | case CMD_RESET: |
| 291 | case CMD_ISREADY: |
| 292 | case CMD_VERIFY: |
| 293 | case CMD_SEEK: |
| 294 | return DISK_RET_SUCCESS; |
| 295 | default: |
| 296 | op->count = 0; |
| 297 | return DISK_RET_EPARAM; |
| 298 | } |
| 299 | } |
| 300 | |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 301 | // Execute a disk_op request. |
Kevin O'Connor | 36c93a5 | 2009-09-12 19:35:04 -0400 | [diff] [blame] | 302 | int |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 303 | process_op(struct disk_op_s *op) |
| 304 | { |
Kevin O'Connor | d7e998f | 2010-02-15 22:48:28 -0500 | [diff] [blame] | 305 | ASSERT16(); |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 306 | u8 type = GET_GLOBAL(op->drive_g->type); |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 307 | switch (type) { |
Kevin O'Connor | a3855ad | 2009-08-16 21:59:40 -0400 | [diff] [blame] | 308 | case DTYPE_FLOPPY: |
| 309 | return process_floppy_op(op); |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 310 | case DTYPE_ATA: |
| 311 | return process_ata_op(op); |
| 312 | case DTYPE_ATAPI: |
| 313 | return process_atapi_op(op); |
Kevin O'Connor | a3855ad | 2009-08-16 21:59:40 -0400 | [diff] [blame] | 314 | case DTYPE_RAMDISK: |
| 315 | return process_ramdisk_op(op); |
Kevin O'Connor | 36c93a5 | 2009-09-12 19:35:04 -0400 | [diff] [blame] | 316 | case DTYPE_CDEMU: |
| 317 | return process_cdemu_op(op); |
Paolo Bonzini | 0e7fb5f | 2011-11-16 13:02:55 +0100 | [diff] [blame^] | 318 | case DTYPE_VIRTIO_BLK: |
| 319 | return process_virtio_blk_op(op); |
Gerd Hoffmann | d52fdf6 | 2010-11-29 09:42:13 +0100 | [diff] [blame] | 320 | case DTYPE_AHCI: |
| 321 | return process_ahci_op(op); |
Paolo Bonzini | 1e749c8 | 2011-11-16 13:02:53 +0100 | [diff] [blame] | 322 | case DTYPE_USB: |
| 323 | return process_scsi_op(op); |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 324 | default: |
| 325 | op->count = 0; |
| 326 | return DISK_RET_EPARAM; |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | // Execute a "disk_op_s" request - this runs on a stack in the ebda. |
| 331 | static int |
| 332 | __send_disk_op(struct disk_op_s *op_far, u16 op_seg) |
| 333 | { |
| 334 | struct disk_op_s dop; |
| 335 | memcpy_far(GET_SEG(SS), &dop |
| 336 | , op_seg, op_far |
| 337 | , sizeof(dop)); |
| 338 | |
Kevin O'Connor | 77d227b | 2009-10-22 21:48:39 -0400 | [diff] [blame] | 339 | dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n" |
| 340 | , dop.drive_g, (u32)dop.lba, dop.buf_fl |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 341 | , dop.count, dop.command); |
| 342 | |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 343 | int status = process_op(&dop); |
| 344 | |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 345 | // Update count with total sectors transferred. |
| 346 | SET_FARVAR(op_seg, op_far->count, dop.count); |
| 347 | |
| 348 | return status; |
| 349 | } |
| 350 | |
| 351 | // Execute a "disk_op_s" request by jumping to a stack in the ebda. |
| 352 | int |
| 353 | send_disk_op(struct disk_op_s *op) |
| 354 | { |
Kevin O'Connor | d7e998f | 2010-02-15 22:48:28 -0500 | [diff] [blame] | 355 | ASSERT16(); |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 356 | if (! CONFIG_DRIVES) |
| 357 | return -1; |
| 358 | |
Kevin O'Connor | bca0736 | 2010-03-20 20:41:38 -0400 | [diff] [blame] | 359 | return stack_hop((u32)op, GET_SEG(SS), __send_disk_op); |
Kevin O'Connor | af5aabb | 2009-08-16 18:48:38 -0400 | [diff] [blame] | 360 | } |