blob: 264f3768df75694d343b3741c30232f29b2c8d7e [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
10#include "bregs.h" // struct bregs
Kevin O'Connor5d369d82013-09-02 20:48:46 -040011#include "hw/ata.h" // process_ata_op
12#include "hw/ahci.h" // process_ahci_op
Kevin O'Connor5d369d82013-09-02 20:48:46 -040013#include "hw/blockcmd.h" // cdb_*
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040014#include "hw/rtc.h" // rtc_read
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040015#include "hw/virtio-blk.h" // process_virtio_blk_op
Kevin O'Connor9dea5902013-09-14 20:23:54 -040016#include "malloc.h" // malloc_low
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040017#include "output.h" // dprintf
Kevin O'Connor3df600b2013-09-14 19:28:55 -040018#include "stacks.h" // stack_hop
Kevin O'Connor135f3f62013-09-14 23:57:26 -040019#include "std/disk.h" // struct dpte_s
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040020#include "string.h" // checksum
Kevin O'Connor135f3f62013-09-14 23:57:26 -040021#include "util.h" // process_floppy_op
Kevin O'Connorc892b132009-08-11 21:59:37 -040022
Kevin O'Connor89a2f962013-02-18 23:36:03 -050023u8 FloppyCount VARFSEG;
Kevin O'Connora0842f82010-12-29 11:05:46 -050024u8 CDCount;
Kevin O'Connore52ad392013-02-20 23:48:22 -050025struct drive_s *IDMap[3][BUILD_MAX_EXTDRIVE] VARFSEG;
Kevin O'Connor89a2f962013-02-18 23:36:03 -050026u8 *bounce_buf_fl VARFSEG;
Kevin O'Connord3140832012-05-13 22:46:12 -040027struct dpte_s DefaultDPTE VARLOW;
Kevin O'Connorc892b132009-08-11 21:59:37 -040028
Kevin O'Connor77d227b2009-10-22 21:48:39 -040029struct drive_s *
30getDrive(u8 exttype, u8 extdriveoffset)
31{
Kevin O'Connora0842f82010-12-29 11:05:46 -050032 if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
Kevin O'Connor77d227b2009-10-22 21:48:39 -040033 return NULL;
Kevin O'Connor1902c942013-10-26 11:48:06 -040034 return GET_GLOBAL(IDMap[exttype][extdriveoffset]);
Kevin O'Connor77d227b2009-10-22 21:48:39 -040035}
36
Kevin O'Connor1902c942013-10-26 11:48:06 -040037int getDriveId(u8 exttype, struct drive_s *drive)
Gleb Natapov4c90a202010-12-07 13:50:54 +020038{
Kevin O'Connor1902c942013-10-26 11:48:06 -040039 ASSERT32FLAT();
Gleb Natapov4c90a202010-12-07 13:50:54 +020040 int i;
Kevin O'Connora0842f82010-12-29 11:05:46 -050041 for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
Kevin O'Connor1902c942013-10-26 11:48:06 -040042 if (getDrive(exttype, i) == drive)
Gleb Natapov4c90a202010-12-07 13:50:54 +020043 return i;
Gleb Natapov4c90a202010-12-07 13:50:54 +020044 return -1;
45}
Kevin O'Connorc892b132009-08-11 21:59:37 -040046
Kevin O'Connord83c87b2013-01-21 01:14:12 -050047int create_bounce_buf(void)
Gerd Hoffmannd7a7cf32011-08-04 19:36:27 +020048{
49 if (bounce_buf_fl)
50 return 0;
51
52 u8 *buf = malloc_low(CDROM_SECTOR_SIZE);
53 if (!buf) {
54 warn_noalloc();
55 return -1;
56 }
57 bounce_buf_fl = buf;
58 return 0;
59}
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -050060
Kevin O'Connorc892b132009-08-11 21:59:37 -040061/****************************************************************
62 * Disk geometry translation
63 ****************************************************************/
64
65static u8
Kevin O'Connor1902c942013-10-26 11:48:06 -040066get_translation(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -040067{
Kevin O'Connor1902c942013-10-26 11:48:06 -040068 u8 type = drive->type;
Kevin O'Connor897fb112013-02-07 23:32:48 -050069 if (CONFIG_QEMU && type == DTYPE_ATA) {
Kevin O'Connorc892b132009-08-11 21:59:37 -040070 // Emulators pass in the translation info via nvram.
Kevin O'Connor1902c942013-10-26 11:48:06 -040071 u8 ataid = drive->cntl_id;
Kevin O'Connorc892b132009-08-11 21:59:37 -040072 u8 channel = ataid / 2;
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040073 u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + channel/2);
Kevin O'Connorc892b132009-08-11 21:59:37 -040074 translation >>= 2 * (ataid % 4);
75 translation &= 0x03;
76 return translation;
77 }
78
Kevin O'Connord2d1de02010-02-17 01:07:36 -050079 // Otherwise use a heuristic to determine translation type.
Kevin O'Connor1902c942013-10-26 11:48:06 -040080 u16 heads = drive->pchs.head;
81 u16 cylinders = drive->pchs.cylinder;
82 u16 spt = drive->pchs.sector;
83 u64 sectors = drive->sectors;
Kevin O'Connord2d1de02010-02-17 01:07:36 -050084 u64 psectors = (u64)heads * cylinders * spt;
85 if (!heads || !cylinders || !spt || psectors > sectors)
86 // pchs doesn't look valid - use LBA.
87 return TRANSLATION_LBA;
Kevin O'Connorc892b132009-08-11 21:59:37 -040088
89 if (cylinders <= 1024 && heads <= 16 && spt <= 63)
90 return TRANSLATION_NONE;
91 if (cylinders * heads <= 131072)
92 return TRANSLATION_LARGE;
93 return TRANSLATION_LBA;
94}
95
Kevin O'Connor697e63c2010-12-27 21:08:53 -050096static void
Kevin O'Connor1902c942013-10-26 11:48:06 -040097setup_translation(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -040098{
Kevin O'Connor1902c942013-10-26 11:48:06 -040099 u8 translation = get_translation(drive);
100 drive->translation = translation;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400101
Kevin O'Connor1902c942013-10-26 11:48:06 -0400102 u16 heads = drive->pchs.head ;
103 u16 cylinders = drive->pchs.cylinder;
104 u16 spt = drive->pchs.sector;
105 u64 sectors = drive->sectors;
Kevin O'Connor6f6a74d2009-11-09 19:15:50 -0500106 const char *desc = NULL;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400107
Kevin O'Connorc892b132009-08-11 21:59:37 -0400108 switch (translation) {
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400109 default:
Kevin O'Connorc892b132009-08-11 21:59:37 -0400110 case TRANSLATION_NONE:
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400111 desc = "none";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400112 break;
113 case TRANSLATION_LBA:
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400114 desc = "lba";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400115 spt = 63;
116 if (sectors > 63*255*1024) {
117 heads = 255;
118 cylinders = 1024;
119 break;
120 }
121 u32 sect = (u32)sectors / 63;
122 heads = sect / 1024;
123 if (heads>128)
124 heads = 255;
125 else if (heads>64)
126 heads = 128;
127 else if (heads>32)
128 heads = 64;
129 else if (heads>16)
130 heads = 32;
131 else
132 heads = 16;
133 cylinders = sect / heads;
134 break;
135 case TRANSLATION_RECHS:
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400136 desc = "r-echs";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400137 // Take care not to overflow
138 if (heads==16) {
139 if (cylinders>61439)
140 cylinders=61439;
141 heads=15;
142 cylinders = (u16)((u32)(cylinders)*16/15);
143 }
144 // then go through the large bitshift process
145 case TRANSLATION_LARGE:
146 if (translation == TRANSLATION_LARGE)
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400147 desc = "large";
Kevin O'Connorc892b132009-08-11 21:59:37 -0400148 while (cylinders > 1024) {
149 cylinders >>= 1;
150 heads <<= 1;
151
152 // If we max out the head count
153 if (heads > 127)
154 break;
155 }
156 break;
157 }
158 // clip to 1024 cylinders in lchs
159 if (cylinders > 1024)
160 cylinders = 1024;
Kevin O'Connord2d1de02010-02-17 01:07:36 -0500161 dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n"
Kevin O'Connor1902c942013-10-26 11:48:06 -0400162 , drive
163 , drive->pchs.cylinder, drive->pchs.head, drive->pchs.sector
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400164 , desc
Kevin O'Connord2d1de02010-02-17 01:07:36 -0500165 , cylinders, heads, spt
166 , (u32)sectors);
Kevin O'Connorc892b132009-08-11 21:59:37 -0400167
Kevin O'Connor1902c942013-10-26 11:48:06 -0400168 drive->lchs.head = heads;
169 drive->lchs.cylinder = cylinders;
170 drive->lchs.sector = spt;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400171}
172
173
174/****************************************************************
175 * Drive mapping
176 ****************************************************************/
177
178// Fill in Fixed Disk Parameter Table (located in ebda).
179static void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400180fill_fdpt(struct drive_s *drive, int hdid)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400181{
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400182 if (hdid > 1)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400183 return;
184
Kevin O'Connor1902c942013-10-26 11:48:06 -0400185 u16 nlc = drive->lchs.cylinder;
186 u16 nlh = drive->lchs.head;
187 u16 nls = drive->lchs.sector;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400188
Kevin O'Connor1902c942013-10-26 11:48:06 -0400189 u16 npc = drive->pchs.cylinder;
190 u16 nph = drive->pchs.head;
191 u16 nps = drive->pchs.sector;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400192
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400193 struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
Kevin O'Connorc892b132009-08-11 21:59:37 -0400194 fdpt->precompensation = 0xffff;
195 fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
196 fdpt->landing_zone = npc;
197 fdpt->cylinders = nlc;
198 fdpt->heads = nlh;
Kevin O'Connor8ab9a342013-09-28 23:34:49 -0400199 fdpt->sectors = nls;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400200
Kevin O'Connor8ab9a342013-09-28 23:34:49 -0400201 if (nlc != npc || nlh != nph || nls != nps) {
Kevin O'Connor085debd2010-01-03 22:24:18 -0500202 // Logical mapping present - use extended structure.
Kevin O'Connorc892b132009-08-11 21:59:37 -0400203
Kevin O'Connor085debd2010-01-03 22:24:18 -0500204 // complies with Phoenix style Translated Fixed Disk Parameter
205 // Table (FDPT)
206 fdpt->phys_cylinders = npc;
207 fdpt->phys_heads = nph;
Kevin O'Connor8ab9a342013-09-28 23:34:49 -0400208 fdpt->phys_sectors = nps;
Kevin O'Connor085debd2010-01-03 22:24:18 -0500209 fdpt->a0h_signature = 0xa0;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400210
Kevin O'Connor085debd2010-01-03 22:24:18 -0500211 // Checksum structure.
212 fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
213 }
Kevin O'Connorc892b132009-08-11 21:59:37 -0400214
Kevin O'Connor34ec7b02009-09-20 20:04:06 -0400215 if (hdid == 0)
Kevin O'Connor9f985422009-09-09 11:34:39 -0400216 SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
217 struct extended_bios_data_area_s, fdpt[0])));
Kevin O'Connorc892b132009-08-11 21:59:37 -0400218 else
Kevin O'Connor9f985422009-09-09 11:34:39 -0400219 SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
220 struct extended_bios_data_area_s, fdpt[1])));
Kevin O'Connorc892b132009-08-11 21:59:37 -0400221}
222
Kevin O'Connord254dc22009-11-25 18:49:06 -0500223// Find spot to add a drive
224static void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400225add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive)
Kevin O'Connord254dc22009-11-25 18:49:06 -0500226{
Kevin O'Connora0842f82010-12-29 11:05:46 -0500227 if (*count >= ARRAY_SIZE(IDMap[0])) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500228 warn_noalloc();
Kevin O'Connord254dc22009-11-25 18:49:06 -0500229 return;
230 }
Kevin O'Connor1902c942013-10-26 11:48:06 -0400231 idmap[*count] = drive;
Kevin O'Connord254dc22009-11-25 18:49:06 -0500232 *count = *count + 1;
Kevin O'Connord254dc22009-11-25 18:49:06 -0500233}
234
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500235// Map a hard drive
236void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400237map_hd_drive(struct drive_s *drive)
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500238{
239 ASSERT32FLAT();
240 struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
241 int hdid = bda->hdcount;
Kevin O'Connor1902c942013-10-26 11:48:06 -0400242 dprintf(3, "Mapping hd drive %p to %d\n", drive, hdid);
243 add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive);
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500244
Kevin O'Connor697e63c2010-12-27 21:08:53 -0500245 // Setup disk geometry translation.
Kevin O'Connor1902c942013-10-26 11:48:06 -0400246 setup_translation(drive);
Kevin O'Connor697e63c2010-12-27 21:08:53 -0500247
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500248 // Fill "fdpt" structure.
Kevin O'Connor1902c942013-10-26 11:48:06 -0400249 fill_fdpt(drive, hdid);
Kevin O'Connor3c5e0e12010-12-27 08:37:38 -0500250}
251
Kevin O'Connorc892b132009-08-11 21:59:37 -0400252// Map a cd
253void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400254map_cd_drive(struct drive_s *drive)
Kevin O'Connorc892b132009-08-11 21:59:37 -0400255{
Kevin O'Connor1902c942013-10-26 11:48:06 -0400256 ASSERT32FLAT();
257 dprintf(3, "Mapping cd drive %p\n", drive);
258 add_drive(IDMap[EXTTYPE_CD], &CDCount, drive);
Kevin O'Connorc892b132009-08-11 21:59:37 -0400259}
260
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400261// Map a floppy
262void
Kevin O'Connor1902c942013-10-26 11:48:06 -0400263map_floppy_drive(struct drive_s *drive)
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400264{
Kevin O'Connor1902c942013-10-26 11:48:06 -0400265 ASSERT32FLAT();
266 dprintf(3, "Mapping floppy drive %p\n", drive);
267 add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400268
269 // Update equipment word bits for floppy
Kevin O'Connora0842f82010-12-29 11:05:46 -0500270 if (FloppyCount == 1) {
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400271 // 1 drive, ready for boot
Kevin O'Connore51316d2012-06-10 09:09:22 -0400272 set_equipment_flags(0x41, 0x01);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400273 SET_BDA(floppy_harddisk_info, 0x07);
Kevin O'Connora0842f82010-12-29 11:05:46 -0500274 } else if (FloppyCount >= 2) {
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400275 // 2 drives, ready for boot
Kevin O'Connore51316d2012-06-10 09:09:22 -0400276 set_equipment_flags(0x41, 0x41);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400277 SET_BDA(floppy_harddisk_info, 0x77);
278 }
279}
280
Kevin O'Connorc892b132009-08-11 21:59:37 -0400281
282/****************************************************************
Kevin O'Connor135f3f62013-09-14 23:57:26 -0400283 * Return status functions
284 ****************************************************************/
285
286void
287__disk_ret(struct bregs *regs, u32 linecode, const char *fname)
288{
289 u8 code = linecode;
290 if (regs->dl < EXTSTART_HD)
291 SET_BDA(floppy_last_status, code);
292 else
293 SET_BDA(disk_last_status, code);
294 if (code)
295 __set_code_invalid(regs, linecode, fname);
296 else
297 set_code_success(regs);
298}
299
300void
301__disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
302{
303 u8 code = linecode;
304 if (regs->dl < EXTSTART_HD)
305 SET_BDA(floppy_last_status, code);
306 else
307 SET_BDA(disk_last_status, code);
308 __set_code_unimplemented(regs, linecode, fname);
309}
310
311
312/****************************************************************
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400313 * 16bit calling interface
314 ****************************************************************/
315
Kevin O'Connor4b400a12013-12-24 00:46:15 -0500316int VISIBLE32FLAT
Paolo Bonzini1e749c82011-11-16 13:02:53 +0100317process_scsi_op(struct disk_op_s *op)
318{
Paolo Bonzini1e749c82011-11-16 13:02:53 +0100319 switch (op->command) {
320 case CMD_READ:
321 return cdb_read(op);
322 case CMD_WRITE:
323 return cdb_write(op);
324 case CMD_FORMAT:
325 case CMD_RESET:
326 case CMD_ISREADY:
327 case CMD_VERIFY:
328 case CMD_SEEK:
329 return DISK_RET_SUCCESS;
330 default:
Paolo Bonzini1e749c82011-11-16 13:02:53 +0100331 return DISK_RET_EPARAM;
332 }
333}
334
Kevin O'Connor7c80bb82013-10-02 21:28:08 -0400335int VISIBLE32FLAT
Kevin O'Connorbd6afe52012-07-21 12:01:12 -0400336process_atapi_op(struct disk_op_s *op)
337{
338 switch (op->command) {
339 case CMD_WRITE:
340 case CMD_FORMAT:
341 return DISK_RET_EWRITEPROTECT;
342 default:
343 return process_scsi_op(op);
344 }
345}
346
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400347// Execute a disk_op request.
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400348int
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400349process_op(struct disk_op_s *op)
350{
Kevin O'Connord7e998f2010-02-15 22:48:28 -0500351 ASSERT16();
Kevin O'Connor518955f2013-12-17 17:57:48 -0500352 int ret, origcount = op->count;
Kevin O'Connor1902c942013-10-26 11:48:06 -0400353 u8 type = GET_GLOBALFLAT(op->drive_gf->type);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400354 switch (type) {
Kevin O'Connora3855ad2009-08-16 21:59:40 -0400355 case DTYPE_FLOPPY:
Kevin O'Connor518955f2013-12-17 17:57:48 -0500356 ret = process_floppy_op(op);
357 break;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400358 case DTYPE_ATA:
Kevin O'Connor518955f2013-12-17 17:57:48 -0500359 ret = process_ata_op(op);
360 break;
Kevin O'Connora3855ad2009-08-16 21:59:40 -0400361 case DTYPE_RAMDISK:
Kevin O'Connor518955f2013-12-17 17:57:48 -0500362 ret = process_ramdisk_op(op);
363 break;
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400364 case DTYPE_CDEMU:
Kevin O'Connor518955f2013-12-17 17:57:48 -0500365 ret = process_cdemu_op(op);
366 break;
Paolo Bonzini0e7fb5f2011-11-16 13:02:55 +0100367 case DTYPE_VIRTIO_BLK:
Kevin O'Connor518955f2013-12-17 17:57:48 -0500368 ret = process_virtio_blk_op(op);
369 break;
Kevin O'Connor1902c942013-10-26 11:48:06 -0400370 case DTYPE_AHCI: ;
Kevin O'Connor7c80bb82013-10-02 21:28:08 -0400371 extern void _cfunc32flat_process_ahci_op(void);
Kevin O'Connor518955f2013-12-17 17:57:48 -0500372 ret = call32(_cfunc32flat_process_ahci_op
373 , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
374 break;
Kevin O'Connorbd6afe52012-07-21 12:01:12 -0400375 case DTYPE_ATA_ATAPI:
Kevin O'Connor518955f2013-12-17 17:57:48 -0500376 ret = process_atapi_op(op);
377 break;
Kevin O'Connor1902c942013-10-26 11:48:06 -0400378 case DTYPE_AHCI_ATAPI: ;
Kevin O'Connor7c80bb82013-10-02 21:28:08 -0400379 extern void _cfunc32flat_process_atapi_op(void);
Kevin O'Connor518955f2013-12-17 17:57:48 -0500380 ret = call32(_cfunc32flat_process_atapi_op
381 , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
382 break;
Paolo Bonzini1e749c82011-11-16 13:02:53 +0100383 case DTYPE_USB:
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200384 case DTYPE_UAS:
Paolo Bonzinic5c488f2012-02-27 17:22:23 +0100385 case DTYPE_VIRTIO_SCSI:
Gerd Hoffmann9d6bac12012-07-20 10:59:25 +0200386 case DTYPE_LSI_SCSI:
Paolo Bonzini7a39e722012-08-06 13:15:06 +0200387 case DTYPE_ESP_SCSI:
Hannes Reinecke2df70bf2012-11-13 15:03:31 +0100388 case DTYPE_MEGASAS:
Kevin O'Connor518955f2013-12-17 17:57:48 -0500389 ret = process_scsi_op(op);
390 break;
Kevin O'Connorde30dad2013-12-30 22:09:04 -0500391 case DTYPE_USB_32:
392 case DTYPE_UAS_32:
Kevin O'Connor4b400a12013-12-24 00:46:15 -0500393 case DTYPE_PVSCSI: ;
394 extern void _cfunc32flat_process_scsi_op(void);
395 ret = call32(_cfunc32flat_process_scsi_op
396 , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
397 break;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400398 default:
Kevin O'Connor518955f2013-12-17 17:57:48 -0500399 ret = DISK_RET_EPARAM;
400 break;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400401 }
Kevin O'Connor518955f2013-12-17 17:57:48 -0500402 if (ret && op->count == origcount)
403 // If the count hasn't changed on error, assume no data transferred.
404 op->count = 0;
405 return ret;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400406}
407
Kevin O'Connor46b82622012-05-13 12:10:30 -0400408// Execute a "disk_op_s" request - this runs on the extra stack.
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400409static int
410__send_disk_op(struct disk_op_s *op_far, u16 op_seg)
411{
412 struct disk_op_s dop;
413 memcpy_far(GET_SEG(SS), &dop
414 , op_seg, op_far
415 , sizeof(dop));
416
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400417 dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
Kevin O'Connor1902c942013-10-26 11:48:06 -0400418 , dop.drive_gf, (u32)dop.lba, dop.buf_fl
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400419 , dop.count, dop.command);
420
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400421 int status = process_op(&dop);
422
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400423 // Update count with total sectors transferred.
424 SET_FARVAR(op_seg, op_far->count, dop.count);
425
426 return status;
427}
428
Kevin O'Connor46b82622012-05-13 12:10:30 -0400429// Execute a "disk_op_s" request by jumping to the extra 16bit stack.
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400430int
431send_disk_op(struct disk_op_s *op)
432{
Kevin O'Connord7e998f2010-02-15 22:48:28 -0500433 ASSERT16();
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400434 if (! CONFIG_DRIVES)
435 return -1;
436
Kevin O'Connorbca07362010-03-20 20:41:38 -0400437 return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400438}