blob: 1f600b85391bc63429358e8db1fbb947431609ae [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
Sam Eidermanc9ba5272019-06-26 15:38:16 +030072static int
73host_lchs_supplied(struct drive_s *drive)
74{
75 return (drive->lchs.head <= 255 &&
76 drive->lchs.sector > 0 && drive->lchs.sector <= 63);
77}
78
Kevin O'Connorc892b132009-08-11 21:59:37 -040079static u8
Kevin O'Connor1902c942013-10-26 11:48:06 -040080get_translation(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -040081{
Sam Eidermanc9ba5272019-06-26 15:38:16 +030082 if (host_lchs_supplied(drive))
83 return TRANSLATION_HOST;
Kevin O'Connor1902c942013-10-26 11:48:06 -040084 u8 type = drive->type;
Kevin O'Connor897fb112013-02-07 23:32:48 -050085 if (CONFIG_QEMU && type == DTYPE_ATA) {
Kevin O'Connorc892b132009-08-11 21:59:37 -040086 // Emulators pass in the translation info via nvram.
Kevin O'Connor6a668b32015-07-14 15:12:25 -040087 u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + drive->cntl_id/4);
88 translation >>= 2 * (drive->cntl_id % 4);
Kevin O'Connorc892b132009-08-11 21:59:37 -040089 translation &= 0x03;
90 return translation;
91 }
92
Kevin O'Connord2d1de02010-02-17 01:07:36 -050093 // Otherwise use a heuristic to determine translation type.
Kevin O'Connor1902c942013-10-26 11:48:06 -040094 u16 heads = drive->pchs.head;
95 u16 cylinders = drive->pchs.cylinder;
96 u16 spt = drive->pchs.sector;
97 u64 sectors = drive->sectors;
Kevin O'Connord2d1de02010-02-17 01:07:36 -050098 u64 psectors = (u64)heads * cylinders * spt;
99 if (!heads || !cylinders || !spt || psectors > sectors)
100 // pchs doesn't look valid - use LBA.
101 return TRANSLATION_LBA;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400102
103 if (cylinders <= 1024 && heads <= 16 && spt <= 63)
104 return TRANSLATION_NONE;
105 if (cylinders * heads <= 131072)
106 return TRANSLATION_LARGE;
107 return TRANSLATION_LBA;
108}
109
Kevin O'Connor697e63c2010-12-27 21:08:53 -0500110static void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400111setup_translation(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400112{
Kevin O'Connor1902c942013-10-26 11:48:06 -0400113 u8 translation = get_translation(drive);
114 drive->translation = translation;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400115
Kevin O'Connor1902c942013-10-26 11:48:06 -0400116 u16 heads = drive->pchs.head ;
117 u16 cylinders = drive->pchs.cylinder;
118 u16 spt = drive->pchs.sector;
119 u64 sectors = drive->sectors;
Kevin O'Connor6f6a74d2009-11-09 19:15:50 -0500120 const char *desc = NULL;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400121
Kevin O'Connorc892b132009-08-11 21:59:37 -0400122 switch (translation) {
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400123 default:
Kevin O'Connorc892b132009-08-11 21:59:37 -0400124 case TRANSLATION_NONE:
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400125 desc = "none";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400126 break;
127 case TRANSLATION_LBA:
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400128 desc = "lba";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400129 spt = 63;
130 if (sectors > 63*255*1024) {
131 heads = 255;
132 cylinders = 1024;
133 break;
134 }
135 u32 sect = (u32)sectors / 63;
136 heads = sect / 1024;
137 if (heads>128)
138 heads = 255;
139 else if (heads>64)
140 heads = 128;
141 else if (heads>32)
142 heads = 64;
143 else if (heads>16)
144 heads = 32;
145 else
146 heads = 16;
147 cylinders = sect / heads;
148 break;
149 case TRANSLATION_RECHS:
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400150 desc = "r-echs";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400151 // Take care not to overflow
152 if (heads==16) {
153 if (cylinders>61439)
154 cylinders=61439;
155 heads=15;
156 cylinders = (u16)((u32)(cylinders)*16/15);
157 }
158 // then go through the large bitshift process
159 case TRANSLATION_LARGE:
160 if (translation == TRANSLATION_LARGE)
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400161 desc = "large";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400162 while (cylinders > 1024) {
163 cylinders >>= 1;
164 heads <<= 1;
165
166 // If we max out the head count
167 if (heads > 127)
168 break;
169 }
170 break;
Sam Eidermanc9ba5272019-06-26 15:38:16 +0300171 case TRANSLATION_HOST:
172 desc = "host-supplied";
173 cylinders = drive->lchs.cylinder;
174 heads = drive->lchs.head;
175 spt = drive->lchs.sector;
176 break;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400177 }
178 // clip to 1024 cylinders in lchs
179 if (cylinders > 1024)
180 cylinders = 1024;
Kevin O'Connord61ca792015-12-23 15:42:35 -0500181 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 -0400182 , drive
183 , drive->pchs.cylinder, drive->pchs.head, drive->pchs.sector
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400184 , desc
Kevin O'Connord2d1de02010-02-17 01:07:36 -0500185 , cylinders, heads, spt
186 , (u32)sectors);
Kevin O'Connorc892b132009-08-11 21:59:37 -0400187
Kevin O'Connor1902c942013-10-26 11:48:06 -0400188 drive->lchs.head = heads;
189 drive->lchs.cylinder = cylinders;
190 drive->lchs.sector = spt;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400191}
192
193
194/****************************************************************
195 * Drive mapping
196 ****************************************************************/
197
198// Fill in Fixed Disk Parameter Table (located in ebda).
199static void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400200fill_fdpt(struct drive_s *drive, int hdid)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400201{
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400202 if (hdid > 1)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400203 return;
204
Kevin O'Connor1902c942013-10-26 11:48:06 -0400205 u16 nlc = drive->lchs.cylinder;
206 u16 nlh = drive->lchs.head;
207 u16 nls = drive->lchs.sector;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400208
Kevin O'Connor1902c942013-10-26 11:48:06 -0400209 u16 npc = drive->pchs.cylinder;
210 u16 nph = drive->pchs.head;
211 u16 nps = drive->pchs.sector;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400212
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400213 struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
Kevin O'Connorc892b132009-08-11 21:59:37 -0400214 fdpt->precompensation = 0xffff;
215 fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
216 fdpt->landing_zone = npc;
217 fdpt->cylinders = nlc;
218 fdpt->heads = nlh;
Kevin O'Connor8ab9a342013-09-28 23:34:49 -0400219 fdpt->sectors = nls;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400220
Kevin O'Connor8ab9a342013-09-28 23:34:49 -0400221 if (nlc != npc || nlh != nph || nls != nps) {
Kevin O'Connor085debd2010-01-03 22:24:18 -0500222 // Logical mapping present - use extended structure.
Kevin O'Connorc892b132009-08-11 21:59:37 -0400223
Kevin O'Connor085debd2010-01-03 22:24:18 -0500224 // complies with Phoenix style Translated Fixed Disk Parameter
225 // Table (FDPT)
226 fdpt->phys_cylinders = npc;
227 fdpt->phys_heads = nph;
Kevin O'Connor8ab9a342013-09-28 23:34:49 -0400228 fdpt->phys_sectors = nps;
Kevin O'Connor085debd2010-01-03 22:24:18 -0500229 fdpt->a0h_signature = 0xa0;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400230
Kevin O'Connor085debd2010-01-03 22:24:18 -0500231 // Checksum structure.
232 fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
233 }
Kevin O'Connorc892b132009-08-11 21:59:37 -0400234
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400235 if (hdid == 0)
Kevin O'Connor9f985422009-09-09 11:34:39 -0400236 SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
237 struct extended_bios_data_area_s, fdpt[0])));
Kevin O'Connorc892b132009-08-11 21:59:37 -0400238 else
Kevin O'Connor9f985422009-09-09 11:34:39 -0400239 SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
240 struct extended_bios_data_area_s, fdpt[1])));
Kevin O'Connorc892b132009-08-11 21:59:37 -0400241}
242
Kevin O'Connord254dc22009-11-25 18:49:06 -0500243// Find spot to add a drive
244static void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400245add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive)
Kevin O'Connord254dc22009-11-25 18:49:06 -0500246{
Kevin O'Connora0842f82010-12-29 11:05:46 -0500247 if (*count >= ARRAY_SIZE(IDMap[0])) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500248 warn_noalloc();
Kevin O'Connord254dc22009-11-25 18:49:06 -0500249 return;
250 }
Kevin O'Connor1902c942013-10-26 11:48:06 -0400251 idmap[*count] = drive;
Kevin O'Connord254dc22009-11-25 18:49:06 -0500252 *count = *count + 1;
Kevin O'Connord254dc22009-11-25 18:49:06 -0500253}
254
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500255// Map a hard drive
256void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400257map_hd_drive(struct drive_s *drive)
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500258{
259 ASSERT32FLAT();
260 struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
261 int hdid = bda->hdcount;
Kevin O'Connor1902c942013-10-26 11:48:06 -0400262 dprintf(3, "Mapping hd drive %p to %d\n", drive, hdid);
263 add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive);
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500264
Kevin O'Connor697e63c2010-12-27 21:08:53 -0500265 // Setup disk geometry translation.
Kevin O'Connor1902c942013-10-26 11:48:06 -0400266 setup_translation(drive);
Kevin O'Connor697e63c2010-12-27 21:08:53 -0500267
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500268 // Fill "fdpt" structure.
Kevin O'Connor1902c942013-10-26 11:48:06 -0400269 fill_fdpt(drive, hdid);
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500270}
271
Kevin O'Connorc892b132009-08-11 21:59:37 -0400272// Map a cd
273void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400274map_cd_drive(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400275{
Kevin O'Connor1902c942013-10-26 11:48:06 -0400276 ASSERT32FLAT();
277 dprintf(3, "Mapping cd drive %p\n", drive);
278 add_drive(IDMap[EXTTYPE_CD], &CDCount, drive);
Kevin O'Connorc892b132009-08-11 21:59:37 -0400279}
280
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400281// Map a floppy
282void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400283map_floppy_drive(struct drive_s *drive)
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400284{
Kevin O'Connor1902c942013-10-26 11:48:06 -0400285 ASSERT32FLAT();
286 dprintf(3, "Mapping floppy drive %p\n", drive);
287 add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400288
289 // Update equipment word bits for floppy
Kevin O'Connora0842f82010-12-29 11:05:46 -0500290 if (FloppyCount == 1) {
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400291 // 1 drive, ready for boot
Kevin O'Connore51316d2012-06-10 09:09:22 -0400292 set_equipment_flags(0x41, 0x01);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400293 SET_BDA(floppy_harddisk_info, 0x07);
Kevin O'Connora0842f82010-12-29 11:05:46 -0500294 } else if (FloppyCount >= 2) {
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400295 // 2 drives, ready for boot
Kevin O'Connore51316d2012-06-10 09:09:22 -0400296 set_equipment_flags(0x41, 0x41);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400297 SET_BDA(floppy_harddisk_info, 0x77);
298 }
299}
300
Kevin O'Connorc892b132009-08-11 21:59:37 -0400301
302/****************************************************************
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400303 * Extended Disk Drive (EDD) get drive parameters
304 ****************************************************************/
305
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400306// flags for bus_iface field in fill_generic_edd()
307#define EDD_ISA 0x01
308#define EDD_PCI 0x02
309#define EDD_BUS_MASK 0x0f
310#define EDD_ATA 0x10
311#define EDD_SCSI 0x20
312#define EDD_IFACE_MASK 0xf0
313
314// Fill in EDD info
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400315static int
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400316fill_generic_edd(struct segoff_s edd, struct drive_s *drive_fl
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400317 , u32 dpte_so, u8 bus_iface, u32 iface_path, u32 device_path)
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400318{
Kevin O'Connor8aad64e2015-07-27 10:41:41 -0400319 u16 seg = edd.seg;
320 struct int13dpt_s *param_far = (void*)(edd.offset+0);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400321 u16 size = GET_FARVAR(seg, param_far->size);
322 u16 t13 = size == 74;
323
324 // Buffer is too small
325 if (size < 26)
326 return DISK_RET_EPARAM;
327
328 // EDD 1.x
329
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400330 u8 type = GET_FLATPTR(drive_fl->type);
331 u16 npc = GET_FLATPTR(drive_fl->pchs.cylinder);
332 u16 nph = GET_FLATPTR(drive_fl->pchs.head);
333 u16 nps = GET_FLATPTR(drive_fl->pchs.sector);
334 u64 lba = GET_FLATPTR(drive_fl->sectors);
335 u16 blksize = GET_FLATPTR(drive_fl->blksize);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400336
337 dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
338 , size, type, npc, nph, nps, (u32)lba, blksize);
339
340 SET_FARVAR(seg, param_far->size, 26);
Kevin O'Connorf8387e22014-05-10 11:54:48 -0400341 if (lba == (u64)-1) {
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400342 // 0x74 = removable, media change, lockable, max values
343 SET_FARVAR(seg, param_far->infos, 0x74);
344 SET_FARVAR(seg, param_far->cylinders, 0xffffffff);
345 SET_FARVAR(seg, param_far->heads, 0xffffffff);
346 SET_FARVAR(seg, param_far->spt, 0xffffffff);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400347 } else {
348 if (lba > (u64)nps*nph*0x3fff) {
349 SET_FARVAR(seg, param_far->infos, 0x00); // geometry is invalid
350 SET_FARVAR(seg, param_far->cylinders, 0x3fff);
351 } else {
352 SET_FARVAR(seg, param_far->infos, 0x02); // geometry is valid
353 SET_FARVAR(seg, param_far->cylinders, (u32)npc);
354 }
355 SET_FARVAR(seg, param_far->heads, (u32)nph);
356 SET_FARVAR(seg, param_far->spt, (u32)nps);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400357 }
Kevin O'Connorf8387e22014-05-10 11:54:48 -0400358 SET_FARVAR(seg, param_far->sector_count, lba);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400359 SET_FARVAR(seg, param_far->blksize, blksize);
360
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400361 if (size < 30 || !dpte_so)
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400362 return DISK_RET_SUCCESS;
363
364 // EDD 2.x
365
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400366 SET_FARVAR(seg, param_far->size, 30);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400367 SET_FARVAR(seg, param_far->dpte.segoff, dpte_so);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400368
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400369 if (size < 66 || !bus_iface)
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400370 return DISK_RET_SUCCESS;
371
372 // EDD 3.x
373 SET_FARVAR(seg, param_far->key, 0xbedd);
374 SET_FARVAR(seg, param_far->dpi_length, t13 ? 44 : 36);
375 SET_FARVAR(seg, param_far->reserved1, 0);
376 SET_FARVAR(seg, param_far->reserved2, 0);
377
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400378 const char *host_bus = "ISA ";
379 if ((bus_iface & EDD_BUS_MASK) == EDD_PCI) {
380 host_bus = "PCI ";
381 if (!t13)
382 // Phoenix v3 spec (pre t13) did not define the PCI channel field
383 iface_path &= 0x00ffffff;
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400384 }
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400385 memcpy_far(seg, param_far->host_bus, SEG_BIOS, host_bus
386 , sizeof(param_far->host_bus));
387 SET_FARVAR(seg, param_far->iface_path, iface_path);
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400388
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400389 const char *iface_type = "ATA ";
390 if ((bus_iface & EDD_IFACE_MASK) == EDD_SCSI)
391 iface_type = "SCSI ";
392 memcpy_far(seg, param_far->iface_type, SEG_BIOS, iface_type
393 , sizeof(param_far->iface_type));
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400394 if (t13) {
395 SET_FARVAR(seg, param_far->t13.device_path[0], device_path);
396 SET_FARVAR(seg, param_far->t13.device_path[1], 0);
397
398 SET_FARVAR(seg, param_far->t13.checksum
399 , -checksum_far(seg, (void*)param_far+30, 43));
400 } else {
401 SET_FARVAR(seg, param_far->phoenix.device_path, device_path);
402
403 SET_FARVAR(seg, param_far->phoenix.checksum
404 , -checksum_far(seg, (void*)param_far+30, 35));
405 }
406
407 return DISK_RET_SUCCESS;
408}
409
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400410// Build an EDD "iface_path" field for a PCI device
411static u32
412edd_pci_path(u16 bdf, u8 channel)
413{
414 return (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
415 | (pci_bdf_to_fn(bdf) << 16) | ((u32)channel << 24));
416}
417
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400418struct dpte_s DefaultDPTE VARLOW;
419
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400420// EDD info for ATA and ATAPI drives
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400421static int
Kevin O'Connor8aad64e2015-07-27 10:41:41 -0400422fill_ata_edd(struct segoff_s edd, struct drive_s *drive_gf)
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400423{
424 if (!CONFIG_ATA)
425 return DISK_RET_EPARAM;
426
427 // Fill in dpte
428 struct atadrive_s *adrive_gf = container_of(
429 drive_gf, struct atadrive_s, drive);
430 struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
431 u8 slave = GET_GLOBALFLAT(adrive_gf->slave);
432 u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
433 u8 irq = GET_GLOBALFLAT(chan_gf->irq);
434 u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
435 int bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
436 u8 channel = GET_GLOBALFLAT(chan_gf->chanid);
437
438 u16 options = 0;
439 if (GET_GLOBALFLAT(drive_gf->type) == DTYPE_ATA) {
440 u8 translation = GET_GLOBALFLAT(drive_gf->translation);
Sam Eidermanc9ba5272019-06-26 15:38:16 +0300441 if ((translation != TRANSLATION_NONE) &&
442 (translation != TRANSLATION_HOST)) {
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400443 options |= 1<<3; // CHS translation
444 if (translation == TRANSLATION_LBA)
445 options |= 1<<9;
446 if (translation == TRANSLATION_RECHS)
447 options |= 3<<9;
448 }
449 } else {
450 // ATAPI
451 options |= 1<<5; // removable device
452 options |= 1<<6; // atapi device
453 }
454 options |= 1<<4; // lba translation
455 if (CONFIG_ATA_PIO32)
456 options |= 1<<7;
457
458 SET_LOW(DefaultDPTE.iobase1, iobase1);
459 SET_LOW(DefaultDPTE.iobase2, iobase2 + ATA_CB_DC);
460 SET_LOW(DefaultDPTE.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
461 | ATA_CB_DH_LBA));
462 SET_LOW(DefaultDPTE.unused, 0xcb);
463 SET_LOW(DefaultDPTE.irq, irq);
464 SET_LOW(DefaultDPTE.blkcount, 1);
465 SET_LOW(DefaultDPTE.dma, 0);
466 SET_LOW(DefaultDPTE.pio, 0);
467 SET_LOW(DefaultDPTE.options, options);
468 SET_LOW(DefaultDPTE.reserved, 0);
469 SET_LOW(DefaultDPTE.revision, 0x11);
470
471 u8 sum = checksum_far(SEG_LOW, &DefaultDPTE, 15);
472 SET_LOW(DefaultDPTE.checksum, -sum);
473
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400474 u32 bustype = EDD_ISA, ifpath = iobase1;
475 if (bdf >= 0) {
476 bustype = EDD_PCI;
477 ifpath = edd_pci_path(bdf, channel);
478 }
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400479 return fill_generic_edd(
Kevin O'Connor8aad64e2015-07-27 10:41:41 -0400480 edd, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400481 , bustype | EDD_ATA, ifpath, slave);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400482}
483
Kevin O'Connorb3f1fad2015-08-05 15:02:01 -0400484// Fill Extended Disk Drive (EDD) "Get drive parameters" info for a drive
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400485int noinline
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400486fill_edd(struct segoff_s edd, struct drive_s *drive_fl)
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400487{
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400488 switch (GET_FLATPTR(drive_fl->type)) {
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400489 case DTYPE_ATA:
490 case DTYPE_ATA_ATAPI:
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400491 return fill_ata_edd(edd, drive_fl);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400492 case DTYPE_VIRTIO_BLK:
493 case DTYPE_VIRTIO_SCSI:
494 return fill_generic_edd(
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400495 edd, drive_fl, 0xffffffff, EDD_PCI | EDD_SCSI
496 , edd_pci_path(GET_FLATPTR(drive_fl->cntl_id), 0), 0);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400497 default:
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400498 return fill_generic_edd(edd, drive_fl, 0, 0, 0, 0);
Kevin O'Connor9e735bb2014-05-10 12:46:57 -0400499 }
500}
501
Kevin O'Connor39ca4982014-05-10 11:42:22 -0400502
503/****************************************************************
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400504 * Disk driver dispatch
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400505 ****************************************************************/
506
Kevin O'Connor7c480762016-02-03 11:00:17 -0500507void
508block_setup(void)
509{
510 floppy_setup();
511 ata_setup();
512 ahci_setup();
513 sdcard_setup();
514 ramdisk_setup();
515 virtio_blk_setup();
516 virtio_scsi_setup();
517 lsi_scsi_setup();
518 esp_scsi_setup();
519 megasas_setup();
520 pvscsi_setup();
Don Slutzf2645a82016-03-25 17:04:31 +0100521 mpt_scsi_setup();
Julian Stecklinac83e15b2017-02-13 10:03:59 +0100522 nvme_setup();
Kevin O'Connor7c480762016-02-03 11:00:17 -0500523}
524
Kevin O'Connor85c72c62015-07-07 09:01:52 -0400525// Fallback handler for command requests not implemented by drivers
526int
527default_process_op(struct disk_op_s *op)
528{
529 switch (op->command) {
530 case CMD_FORMAT:
531 case CMD_RESET:
532 case CMD_ISREADY:
533 case CMD_VERIFY:
534 case CMD_SEEK:
535 // Return success if the driver doesn't implement these commands
536 return DISK_RET_SUCCESS;
537 default:
538 return DISK_RET_EPARAM;
539 }
540}
541
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400542// Command dispatch for disk drivers that run in both 16bit and 32bit mode
543static int
544process_op_both(struct disk_op_s *op)
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400545{
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400546 switch (GET_FLATPTR(op->drive_fl->type)) {
Kevin O'Connorbd6afe52012-07-21 12:01:12 -0400547 case DTYPE_ATA_ATAPI:
Kevin O'Connor91f89232015-07-07 11:11:46 -0400548 return ata_atapi_process_op(op);
Paolo Bonzini1e749c82011-11-16 13:02:53 +0100549 case DTYPE_USB:
Kevin O'Connored120902015-07-07 11:35:25 -0400550 return usb_process_op(op);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200551 case DTYPE_UAS:
Kevin O'Connorb70cbd62015-07-07 11:43:34 -0400552 return uas_process_op(op);
Gerd Hoffmann9d6bac12012-07-20 10:59:25 +0200553 case DTYPE_LSI_SCSI:
Kevin O'Connor7d3ca012015-07-07 11:51:08 -0400554 return lsi_scsi_process_op(op);
Paolo Bonzini7a39e722012-08-06 13:15:06 +0200555 case DTYPE_ESP_SCSI:
Kevin O'Connore404cad2015-07-07 11:57:50 -0400556 return esp_scsi_process_op(op);
Hannes Reinecke2df70bf2012-11-13 15:03:31 +0100557 case DTYPE_MEGASAS:
Kevin O'Connor0429a9e2015-07-07 12:06:01 -0400558 return megasas_process_op(op);
Don Slutzf2645a82016-03-25 17:04:31 +0100559 case DTYPE_MPT_SCSI:
560 return mpt_scsi_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400561 default:
562 if (!MODESEGMENT)
563 return DISK_RET_EPARAM;
564 // In 16bit mode and driver not found - try in 32bit mode
Kevin O'Connorb4cca862015-10-09 11:53:02 -0400565 return call32(process_op_32, MAKE_FLATPTR(GET_SEG(SS), op)
566 , DISK_RET_EPARAM);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400567 }
568}
569
570// Command dispatch for disk drivers that only run in 32bit mode
571int VISIBLE32FLAT
572process_op_32(struct disk_op_s *op)
573{
574 ASSERT32FLAT();
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400575 switch (op->drive_fl->type) {
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400576 case DTYPE_VIRTIO_BLK:
Kevin O'Connor17856452015-07-07 14:56:20 -0400577 return virtio_blk_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400578 case DTYPE_AHCI:
Kevin O'Connor17856452015-07-07 14:56:20 -0400579 return ahci_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400580 case DTYPE_AHCI_ATAPI:
Kevin O'Connor0e5c7702015-07-07 11:24:27 -0400581 return ahci_atapi_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400582 case DTYPE_SDCARD:
Kevin O'Connor17856452015-07-07 14:56:20 -0400583 return sdcard_process_op(op);
Kevin O'Connorde30dad2013-12-30 22:09:04 -0500584 case DTYPE_USB_32:
Kevin O'Connored120902015-07-07 11:35:25 -0400585 return usb_process_op(op);
Kevin O'Connorde30dad2013-12-30 22:09:04 -0500586 case DTYPE_UAS_32:
Kevin O'Connorb70cbd62015-07-07 11:43:34 -0400587 return uas_process_op(op);
Gerd Hoffmann1d9e87b2015-06-26 09:44:00 +0200588 case DTYPE_VIRTIO_SCSI:
Kevin O'Connore0eb5a02015-07-07 12:19:53 -0400589 return virtio_scsi_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400590 case DTYPE_PVSCSI:
Kevin O'Connor2dd08322015-07-07 12:35:34 -0400591 return pvscsi_process_op(op);
Julian Stecklinac83e15b2017-02-13 10:03:59 +0100592 case DTYPE_NVME:
593 return nvme_process_op(op);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400594 default:
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400595 return process_op_both(op);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400596 }
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400597}
598
599// Command dispatch for disk drivers that only run in 16bit mode
600static int
601process_op_16(struct disk_op_s *op)
602{
603 ASSERT16();
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400604 switch (GET_FLATPTR(op->drive_fl->type)) {
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400605 case DTYPE_FLOPPY:
Kevin O'Connor17856452015-07-07 14:56:20 -0400606 return floppy_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400607 case DTYPE_ATA:
Kevin O'Connor17856452015-07-07 14:56:20 -0400608 return ata_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400609 case DTYPE_RAMDISK:
Kevin O'Connor17856452015-07-07 14:56:20 -0400610 return ramdisk_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400611 case DTYPE_CDEMU:
Kevin O'Connor17856452015-07-07 14:56:20 -0400612 return cdemu_process_op(op);
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400613 default:
614 return process_op_both(op);
615 }
616}
617
618// Execute a disk_op_s request.
619int
620process_op(struct disk_op_s *op)
621{
Kevin O'Connor8ef686f2016-03-31 14:29:07 -0400622 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 -0400623 , op->drive_fl, (u32)op->lba, op->buf_fl
Kevin O'Connor8ef686f2016-03-31 14:29:07 -0400624 , op->count, op->command);
625
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400626 int ret, origcount = op->count;
Kevin O'Connore5a0b612017-07-11 12:24:50 -0400627 if (origcount * GET_FLATPTR(op->drive_fl->blksize) > 64*1024) {
Kevin O'Connorc7fa7892015-07-07 08:35:51 -0400628 op->count = 0;
629 return DISK_RET_EBOUNDARY;
630 }
631 if (MODESEGMENT)
632 ret = process_op_16(op);
633 else
634 ret = process_op_32(op);
Kevin O'Connor518955f2013-12-17 17:57:48 -0500635 if (ret && op->count == origcount)
636 // If the count hasn't changed on error, assume no data transferred.
637 op->count = 0;
638 return ret;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400639}