blob: f73ec18c8f704f4214602539f563da3a5e8a2422 [file] [log] [blame]
Kevin O'Connorc892b132009-08-11 21:59:37 -04001// 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'Connorc892b132009-08-11 21:59:37 -04008#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor135f3f62013-09-14 23:57:26 -04009#include "block.h" // process_op
Kevin O'Connor5d369d82013-09-02 20:48:46 -040010#include "hw/ata.h" // process_ata_op
11#include "hw/ahci.h" // process_ahci_op
Kevin O'Connore404cad2015-07-07 11:57:50 -040012#include "hw/esp-scsi.h" // esp_scsi_process_op
Kevin O'Connor7d3ca012015-07-07 11:51:08 -040013#include "hw/lsi-scsi.h" // lsi_scsi_process_op
Kevin O'Connor0429a9e2015-07-07 12:06:01 -040014#include "hw/megasas.h" // megasas_process_op
Don Slutzf2645a82016-03-25 17:04:31 +010015#include "hw/mpt-scsi.h" // mpt_scsi_process_op
Kevin O'Connor39ca4982014-05-10 11:42:22 -040016#include "hw/pci.h" // pci_bdf_to_bus
Kevin O'Connor2dd08322015-07-07 12:35:34 -040017#include "hw/pvscsi.h" // pvscsi_process_op
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040018#include "hw/rtc.h" // rtc_read
Kevin O'Connored120902015-07-07 11:35:25 -040019#include "hw/usb-msc.h" // usb_process_op
Kevin O'Connorb70cbd62015-07-07 11:43:34 -040020#include "hw/usb-uas.h" // uas_process_op
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040021#include "hw/virtio-blk.h" // process_virtio_blk_op
Kevin O'Connore0eb5a02015-07-07 12:19:53 -040022#include "hw/virtio-scsi.h" // virtio_scsi_process_op
Julian Stecklinac83e15b2017-02-13 10:03:59 +010023#include "hw/nvme.h" // nvme_process_op
Kevin O'Connor9dea5902013-09-14 20:23:54 -040024#include "malloc.h" // malloc_low
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040025#include "output.h" // dprintf
Kevin O'Connor193632b2016-03-31 14:20:30 -040026#include "stacks.h" // call32
Kevin O'Connor135f3f62013-09-14 23:57:26 -040027#include "std/disk.h" // struct dpte_s
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040028#include "string.h" // checksum
Kevin O'Connor135f3f62013-09-14 23:57:26 -040029#include "util.h" // process_floppy_op
Kevin O'Connorc892b132009-08-11 21:59:37 -040030
Kevin O'Connor89a2f962013-02-18 23:36:03 -050031u8 FloppyCount VARFSEG;
Kevin O'Connora0842f82010-12-29 11:05:46 -050032u8 CDCount;
Kevin O'Connore52ad392013-02-20 23:48:22 -050033struct drive_s *IDMap[3][BUILD_MAX_EXTDRIVE] VARFSEG;
Kevin O'Connor89a2f962013-02-18 23:36:03 -050034u8 *bounce_buf_fl VARFSEG;
Kevin O'Connorc892b132009-08-11 21:59:37 -040035
Kevin O'Connor77d227b2009-10-22 21:48:39 -040036struct drive_s *
37getDrive(u8 exttype, u8 extdriveoffset)
38{
Kevin O'Connora0842f82010-12-29 11:05:46 -050039 if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
Kevin O'Connor77d227b2009-10-22 21:48:39 -040040 return NULL;
Kevin O'Connor1902c942013-10-26 11:48:06 -040041 return GET_GLOBAL(IDMap[exttype][extdriveoffset]);
Kevin O'Connor77d227b2009-10-22 21:48:39 -040042}
43
Kevin O'Connor1902c942013-10-26 11:48:06 -040044int getDriveId(u8 exttype, struct drive_s *drive)
Gleb Natapov4c90a202010-12-07 13:50:54 +020045{
Kevin O'Connor1902c942013-10-26 11:48:06 -040046 ASSERT32FLAT();
Gleb Natapov4c90a202010-12-07 13:50:54 +020047 int i;
Kevin O'Connora0842f82010-12-29 11:05:46 -050048 for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
Kevin O'Connor1902c942013-10-26 11:48:06 -040049 if (getDrive(exttype, i) == drive)
Gleb Natapov4c90a202010-12-07 13:50:54 +020050 return i;
Gleb Natapov4c90a202010-12-07 13:50:54 +020051 return -1;
52}
Kevin O'Connorc892b132009-08-11 21:59:37 -040053
Kevin O'Connord83c87b2013-01-21 01:14:12 -050054int create_bounce_buf(void)
Gerd Hoffmannd7a7cf32011-08-04 19:36:27 +020055{
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'Connor3c5e0e12010-12-27 08:37:38 -050067
Kevin O'Connorc892b132009-08-11 21:59:37 -040068/****************************************************************
69 * Disk geometry translation
70 ****************************************************************/
71
72static u8
Kevin O'Connor1902c942013-10-26 11:48:06 -040073get_translation(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -040074{
Kevin O'Connor1902c942013-10-26 11:48:06 -040075 u8 type = drive->type;
Kevin O'Connor897fb112013-02-07 23:32:48 -050076 if (CONFIG_QEMU && type == DTYPE_ATA) {
Kevin O'Connorc892b132009-08-11 21:59:37 -040077 // Emulators pass in the translation info via nvram.
Kevin O'Connor6a668b32015-07-14 15:12:25 -040078 u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + drive->cntl_id/4);
79 translation >>= 2 * (drive->cntl_id % 4);
Kevin O'Connorc892b132009-08-11 21:59:37 -040080 translation &= 0x03;
81 return translation;
82 }
83
Kevin O'Connord2d1de02010-02-17 01:07:36 -050084 // Otherwise use a heuristic to determine translation type.
Kevin O'Connor1902c942013-10-26 11:48:06 -040085 u16 heads = drive->pchs.head;
86 u16 cylinders = drive->pchs.cylinder;
87 u16 spt = drive->pchs.sector;
88 u64 sectors = drive->sectors;
Kevin O'Connord2d1de02010-02-17 01:07:36 -050089 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'Connorc892b132009-08-11 21:59:37 -040093
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'Connor697e63c2010-12-27 21:08:53 -0500101static void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400102setup_translation(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400103{
Kevin O'Connor1902c942013-10-26 11:48:06 -0400104 u8 translation = get_translation(drive);
105 drive->translation = translation;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400106
Kevin O'Connor1902c942013-10-26 11:48:06 -0400107 u16 heads = drive->pchs.head ;
108 u16 cylinders = drive->pchs.cylinder;
109 u16 spt = drive->pchs.sector;
110 u64 sectors = drive->sectors;
Kevin O'Connor6f6a74d2009-11-09 19:15:50 -0500111 const char *desc = NULL;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400112
Kevin O'Connorc892b132009-08-11 21:59:37 -0400113 switch (translation) {
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400114 default:
Kevin O'Connorc892b132009-08-11 21:59:37 -0400115 case TRANSLATION_NONE:
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400116 desc = "none";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400117 break;
118 case TRANSLATION_LBA:
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400119 desc = "lba";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400120 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'Connorc604f2f2009-10-24 19:56:11 -0400141 desc = "r-echs";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400142 // 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'Connorc604f2f2009-10-24 19:56:11 -0400152 desc = "large";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400153 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'Connord61ca792015-12-23 15:42:35 -0500166 dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%u\n"
Kevin O'Connor1902c942013-10-26 11:48:06 -0400167 , drive
168 , drive->pchs.cylinder, drive->pchs.head, drive->pchs.sector
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400169 , desc
Kevin O'Connord2d1de02010-02-17 01:07:36 -0500170 , cylinders, heads, spt
171 , (u32)sectors);
Kevin O'Connorc892b132009-08-11 21:59:37 -0400172
Kevin O'Connor1902c942013-10-26 11:48:06 -0400173 drive->lchs.head = heads;
174 drive->lchs.cylinder = cylinders;
175 drive->lchs.sector = spt;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400176}
177
178
179/****************************************************************
180 * Drive mapping
181 ****************************************************************/
182
183// Fill in Fixed Disk Parameter Table (located in ebda).
184static void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400185fill_fdpt(struct drive_s *drive, int hdid)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400186{
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400187 if (hdid > 1)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400188 return;
189
Kevin O'Connor1902c942013-10-26 11:48:06 -0400190 u16 nlc = drive->lchs.cylinder;
191 u16 nlh = drive->lchs.head;
192 u16 nls = drive->lchs.sector;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400193
Kevin O'Connor1902c942013-10-26 11:48:06 -0400194 u16 npc = drive->pchs.cylinder;
195 u16 nph = drive->pchs.head;
196 u16 nps = drive->pchs.sector;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400197
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400198 struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
Kevin O'Connorc892b132009-08-11 21:59:37 -0400199 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'Connor8ab9a342013-09-28 23:34:49 -0400204 fdpt->sectors = nls;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400205
Kevin O'Connor8ab9a342013-09-28 23:34:49 -0400206 if (nlc != npc || nlh != nph || nls != nps) {
Kevin O'Connor085debd2010-01-03 22:24:18 -0500207 // Logical mapping present - use extended structure.
Kevin O'Connorc892b132009-08-11 21:59:37 -0400208
Kevin O'Connor085debd2010-01-03 22:24:18 -0500209 // complies with Phoenix style Translated Fixed Disk Parameter
210 // Table (FDPT)
211 fdpt->phys_cylinders = npc;
212 fdpt->phys_heads = nph;
Kevin O'Connor8ab9a342013-09-28 23:34:49 -0400213 fdpt->phys_sectors = nps;
Kevin O'Connor085debd2010-01-03 22:24:18 -0500214 fdpt->a0h_signature = 0xa0;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400215
Kevin O'Connor085debd2010-01-03 22:24:18 -0500216 // Checksum structure.
217 fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
218 }
Kevin O'Connorc892b132009-08-11 21:59:37 -0400219
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400220 if (hdid == 0)
Kevin O'Connor9f985422009-09-09 11:34:39 -0400221 SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
222 struct extended_bios_data_area_s, fdpt[0])));
Kevin O'Connorc892b132009-08-11 21:59:37 -0400223 else
Kevin O'Connor9f985422009-09-09 11:34:39 -0400224 SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
225 struct extended_bios_data_area_s, fdpt[1])));
Kevin O'Connorc892b132009-08-11 21:59:37 -0400226}
227
Kevin O'Connord254dc22009-11-25 18:49:06 -0500228// Find spot to add a drive
229static void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400230add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive)
Kevin O'Connord254dc22009-11-25 18:49:06 -0500231{
Kevin O'Connora0842f82010-12-29 11:05:46 -0500232 if (*count >= ARRAY_SIZE(IDMap[0])) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500233 warn_noalloc();
Kevin O'Connord254dc22009-11-25 18:49:06 -0500234 return;
235 }
Kevin O'Connor1902c942013-10-26 11:48:06 -0400236 idmap[*count] = drive;
Kevin O'Connord254dc22009-11-25 18:49:06 -0500237 *count = *count + 1;
Kevin O'Connord254dc22009-11-25 18:49:06 -0500238}
239
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500240// Map a hard drive
241void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400242map_hd_drive(struct drive_s *drive)
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500243{
244 ASSERT32FLAT();
245 struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
246 int hdid = bda->hdcount;
Kevin O'Connor1902c942013-10-26 11:48:06 -0400247 dprintf(3, "Mapping hd drive %p to %d\n", drive, hdid);
248 add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive);
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500249
Kevin O'Connor697e63c2010-12-27 21:08:53 -0500250 // Setup disk geometry translation.
Kevin O'Connor1902c942013-10-26 11:48:06 -0400251 setup_translation(drive);
Kevin O'Connor697e63c2010-12-27 21:08:53 -0500252
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500253 // Fill "fdpt" structure.
Kevin O'Connor1902c942013-10-26 11:48:06 -0400254 fill_fdpt(drive, hdid);
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500255}
256
Kevin O'Connorc892b132009-08-11 21:59:37 -0400257// Map a cd
258void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400259map_cd_drive(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400260{
Kevin O'Connor1902c942013-10-26 11:48:06 -0400261 ASSERT32FLAT();
262 dprintf(3, "Mapping cd drive %p\n", drive);
263 add_drive(IDMap[EXTTYPE_CD], &CDCount, drive);
Kevin O'Connorc892b132009-08-11 21:59:37 -0400264}
265
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400266// Map a floppy
267void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400268map_floppy_drive(struct drive_s *drive)
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400269{
Kevin O'Connor1902c942013-10-26 11:48:06 -0400270 ASSERT32FLAT();
271 dprintf(3, "Mapping floppy drive %p\n", drive);
272 add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400273
274 // Update equipment word bits for floppy
Kevin O'Connora0842f82010-12-29 11:05:46 -0500275 if (FloppyCount == 1) {
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400276 // 1 drive, ready for boot
Kevin O'Connore51316d2012-06-10 09:09:22 -0400277 set_equipment_flags(0x41, 0x01);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400278 SET_BDA(floppy_harddisk_info, 0x07);
Kevin O'Connora0842f82010-12-29 11:05:46 -0500279 } else if (FloppyCount >= 2) {
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400280 // 2 drives, ready for boot
Kevin O'Connore51316d2012-06-10 09:09:22 -0400281 set_equipment_flags(0x41, 0x41);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400282 SET_BDA(floppy_harddisk_info, 0x77);
283 }
284}
285
Kevin O'Connorc892b132009-08-11 21:59:37 -0400286
287/****************************************************************
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400288 * Extended Disk Drive (EDD) get drive parameters
289 ****************************************************************/
290
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400291// 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'Connor9e735bb2014-05-10 12:46:57 -0400300static int
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400301fill_generic_edd(struct segoff_s edd, struct drive_s *drive_fl
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400302 , u32 dpte_so, u8 bus_iface, u32 iface_path, u32 device_path)
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400303{
Kevin O'Connor8aad64e2015-07-27 10:41:41 -0400304 u16 seg = edd.seg;
305 struct int13dpt_s *param_far = (void*)(edd.offset+0);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400306 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'Connore5a0b612017-07-11 12:24:50 -0400315 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'Connor39ca4982014-05-10 11:42:22 -0400321
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'Connorf8387e22014-05-10 11:54:48 -0400326 if (lba == (u64)-1) {
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400327 // 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'Connor39ca4982014-05-10 11:42:22 -0400332 } 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'Connor39ca4982014-05-10 11:42:22 -0400342 }
Kevin O'Connorf8387e22014-05-10 11:54:48 -0400343 SET_FARVAR(seg, param_far->sector_count, lba);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400344 SET_FARVAR(seg, param_far->blksize, blksize);
345
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400346 if (size < 30 || !dpte_so)
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400347 return DISK_RET_SUCCESS;
348
349 // EDD 2.x
350
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400351 SET_FARVAR(seg, param_far->size, 30);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400352 SET_FARVAR(seg, param_far->dpte.segoff, dpte_so);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400353
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400354 if (size < 66 || !bus_iface)
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400355 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'Connorb3f1fad2015-08-05 15:02:01 -0400363 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'Connor39ca4982014-05-10 11:42:22 -0400369 }
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400370 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'Connor39ca4982014-05-10 11:42:22 -0400373
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400374 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'Connor39ca4982014-05-10 11:42:22 -0400379 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'Connorb3f1fad2015-08-05 15:02:01 -0400395// Build an EDD "iface_path" field for a PCI device
396static u32
397edd_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'Connor9e735bb2014-05-10 12:46:57 -0400403struct dpte_s DefaultDPTE VARLOW;
404
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400405// EDD info for ATA and ATAPI drives
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400406static int
Kevin O'Connor8aad64e2015-07-27 10:41:41 -0400407fill_ata_edd(struct segoff_s edd, struct drive_s *drive_gf)
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400408{
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'Connorb3f1fad2015-08-05 15:02:01 -0400458 u32 bustype = EDD_ISA, ifpath = iobase1;
459 if (bdf >= 0) {
460 bustype = EDD_PCI;
461 ifpath = edd_pci_path(bdf, channel);
462 }
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400463 return fill_generic_edd(
Kevin O'Connor8aad64e2015-07-27 10:41:41 -0400464 edd, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400465 , bustype | EDD_ATA, ifpath, slave);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400466}
467
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400468// Fill Extended Disk Drive (EDD) "Get drive parameters" info for a drive
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400469int noinline
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400470fill_edd(struct segoff_s edd, struct drive_s *drive_fl)
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400471{
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400472 switch (GET_FLATPTR(drive_fl->type)) {
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400473 case DTYPE_ATA:
474 case DTYPE_ATA_ATAPI:
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400475 return fill_ata_edd(edd, drive_fl);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400476 case DTYPE_VIRTIO_BLK:
477 case DTYPE_VIRTIO_SCSI:
478 return fill_generic_edd(
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400479 edd, drive_fl, 0xffffffff, EDD_PCI | EDD_SCSI
480 , edd_pci_path(GET_FLATPTR(drive_fl->cntl_id), 0), 0);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400481 default:
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400482 return fill_generic_edd(edd, drive_fl, 0, 0, 0, 0);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400483 }
484}
485
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400486
487/****************************************************************
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400488 * Disk driver dispatch
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400489 ****************************************************************/
490
Kevin O'Connor7c480762016-02-03 11:00:17 -0500491void
492block_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 Slutzf2645a82016-03-25 17:04:31 +0100505 mpt_scsi_setup();
Julian Stecklinac83e15b2017-02-13 10:03:59 +0100506 nvme_setup();
Kevin O'Connor7c480762016-02-03 11:00:17 -0500507}
508
Kevin O'Connor85c72c62015-07-07 09:01:52 -0400509// Fallback handler for command requests not implemented by drivers
510int
511default_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'Connorc7fa7892015-07-07 08:35:51 -0400526// Command dispatch for disk drivers that run in both 16bit and 32bit mode
527static int
528process_op_both(struct disk_op_s *op)
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400529{
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400530 switch (GET_FLATPTR(op->drive_fl->type)) {
Kevin O'Connorbd6afe52012-07-21 12:01:12 -0400531 case DTYPE_ATA_ATAPI:
Kevin O'Connor91f89232015-07-07 11:11:46 -0400532 return ata_atapi_process_op(op);
Paolo Bonzini1e749c82011-11-16 13:02:53 +0100533 case DTYPE_USB:
Kevin O'Connored120902015-07-07 11:35:25 -0400534 return usb_process_op(op);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200535 case DTYPE_UAS:
Kevin O'Connorb70cbd62015-07-07 11:43:34 -0400536 return uas_process_op(op);
Gerd Hoffmann9d6bac12012-07-20 10:59:25 +0200537 case DTYPE_LSI_SCSI:
Kevin O'Connor7d3ca012015-07-07 11:51:08 -0400538 return lsi_scsi_process_op(op);
Paolo Bonzini7a39e722012-08-06 13:15:06 +0200539 case DTYPE_ESP_SCSI:
Kevin O'Connore404cad2015-07-07 11:57:50 -0400540 return esp_scsi_process_op(op);
Hannes Reinecke2df70bf2012-11-13 15:03:31 +0100541 case DTYPE_MEGASAS:
Kevin O'Connor0429a9e2015-07-07 12:06:01 -0400542 return megasas_process_op(op);
Don Slutzf2645a82016-03-25 17:04:31 +0100543 case DTYPE_MPT_SCSI:
544 return mpt_scsi_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400545 default:
546 if (!MODESEGMENT)
547 return DISK_RET_EPARAM;
548 // In 16bit mode and driver not found - try in 32bit mode
Kevin O'Connorb4cca862015-10-09 11:53:02 -0400549 return call32(process_op_32, MAKE_FLATPTR(GET_SEG(SS), op)
550 , DISK_RET_EPARAM);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400551 }
552}
553
554// Command dispatch for disk drivers that only run in 32bit mode
555int VISIBLE32FLAT
556process_op_32(struct disk_op_s *op)
557{
558 ASSERT32FLAT();
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400559 switch (op->drive_fl->type) {
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400560 case DTYPE_VIRTIO_BLK:
Kevin O'Connor17856452015-07-07 14:56:20 -0400561 return virtio_blk_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400562 case DTYPE_AHCI:
Kevin O'Connor17856452015-07-07 14:56:20 -0400563 return ahci_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400564 case DTYPE_AHCI_ATAPI:
Kevin O'Connor0e5c7702015-07-07 11:24:27 -0400565 return ahci_atapi_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400566 case DTYPE_SDCARD:
Kevin O'Connor17856452015-07-07 14:56:20 -0400567 return sdcard_process_op(op);
Kevin O'Connorde30dad2013-12-30 22:09:04 -0500568 case DTYPE_USB_32:
Kevin O'Connored120902015-07-07 11:35:25 -0400569 return usb_process_op(op);
Kevin O'Connorde30dad2013-12-30 22:09:04 -0500570 case DTYPE_UAS_32:
Kevin O'Connorb70cbd62015-07-07 11:43:34 -0400571 return uas_process_op(op);
Gerd Hoffmann1d9e87b2015-06-26 09:44:00 +0200572 case DTYPE_VIRTIO_SCSI:
Kevin O'Connore0eb5a02015-07-07 12:19:53 -0400573 return virtio_scsi_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400574 case DTYPE_PVSCSI:
Kevin O'Connor2dd08322015-07-07 12:35:34 -0400575 return pvscsi_process_op(op);
Julian Stecklinac83e15b2017-02-13 10:03:59 +0100576 case DTYPE_NVME:
577 return nvme_process_op(op);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400578 default:
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400579 return process_op_both(op);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400580 }
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400581}
582
583// Command dispatch for disk drivers that only run in 16bit mode
584static int
585process_op_16(struct disk_op_s *op)
586{
587 ASSERT16();
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400588 switch (GET_FLATPTR(op->drive_fl->type)) {
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400589 case DTYPE_FLOPPY:
Kevin O'Connor17856452015-07-07 14:56:20 -0400590 return floppy_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400591 case DTYPE_ATA:
Kevin O'Connor17856452015-07-07 14:56:20 -0400592 return ata_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400593 case DTYPE_RAMDISK:
Kevin O'Connor17856452015-07-07 14:56:20 -0400594 return ramdisk_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400595 case DTYPE_CDEMU:
Kevin O'Connor17856452015-07-07 14:56:20 -0400596 return cdemu_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400597 default:
598 return process_op_both(op);
599 }
600}
601
602// Execute a disk_op_s request.
603int
604process_op(struct disk_op_s *op)
605{
Kevin O'Connor8ef686f2016-03-31 14:29:07 -0400606 dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400607 , op->drive_fl, (u32)op->lba, op->buf_fl
Kevin O'Connor8ef686f2016-03-31 14:29:07 -0400608 , op->count, op->command);
609
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400610 int ret, origcount = op->count;
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400611 if (origcount * GET_FLATPTR(op->drive_fl->blksize) > 64*1024) {
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400612 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'Connor518955f2013-12-17 17:57:48 -0500619 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'Connoraf5aabb2009-08-16 18:48:38 -0400623}