VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/scsi.c@ 23452

Last change on this file since 23452 was 21321, checked in by vboxsync, 15 years ago

OSE: export SCSI + SATA

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 KB
Line 
1/* $Id: scsi.c 21321 2009-07-07 12:31:37Z vboxsync $ */
2/** @file
3 * SCSI host adapter driver to boot from SCSI disks
4 */
5
6/*
7 * Copyright (C) 2004-2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/* The I/O port of the BusLogic SCSI adapter. */
23#define BUSLOGIC_ISA_IO_PORT 0x330
24/* The I/O port of the LsiLogic SCSI adapter. */
25#define LSILOGIC_ISA_IO_PORT 0x340
26
27#define VBOXSCSI_REGISTER_STATUS 0
28#define VBOXSCSI_REGISTER_COMMAND 0
29#define VBOXSCSI_REGISTER_DATA_IN 1
30#define VBOXSCSI_REGISTER_IDENTIFY 2
31
32#define VBOXSCSI_MAX_DEVICES 16 /* Maximum number of devices a SCSI device can have. */
33
34/* Command opcodes. */
35#define SCSI_INQUIRY 0x12
36#define SCSI_READ_CAPACITY 0x25
37#define SCSI_READ_10 0x28
38#define SCSI_WRITE_10 0x2a
39
40/* Data transfer direction. */
41#define SCSI_TXDIR_FROM_DEVICE 0
42#define SCSI_TXDIR_TO_DEVICE 1
43
44#define VBOXSCSI_BUSY (1 << 0)
45
46//#define VBOX_SCSI_DEBUG 1 /* temporary */
47
48#ifdef VBOX_SCSI_DEBUG
49# define VBOXSCSI_DEBUG(a...) BX_INFO(a)
50#else
51# define VBOXSCSI_DEBUG(a...)
52#endif
53
54int scsi_cmd_data_in(io_base, device_id, cdb_segment, aCDB, cbCDB, segment, offset, cbBuffer)
55 Bit16u io_base, aCDB, offset, cbBuffer, segment, cdb_segment;
56 Bit8u device_id, cbCDB;
57{
58 /* Check that the adapter is ready. */
59 Bit8u status;
60 Bit16u i;
61
62 do
63 {
64 status = inb(io_base+VBOXSCSI_REGISTER_STATUS);
65 } while (status & VBOXSCSI_BUSY);
66
67 /* Write target ID. */
68 outb(io_base+VBOXSCSI_REGISTER_COMMAND, device_id);
69 /* Write transfer direction. */
70 outb(io_base+VBOXSCSI_REGISTER_COMMAND, SCSI_TXDIR_FROM_DEVICE);
71 /* Write the CDB size. */
72 outb(io_base+VBOXSCSI_REGISTER_COMMAND, cbCDB);
73 /* Write buffer size. */
74 outb(io_base+VBOXSCSI_REGISTER_COMMAND, cbBuffer);
75 outb(io_base+VBOXSCSI_REGISTER_COMMAND, (cbBuffer >> 8));
76 /* Write the CDB. */
77 for (i = 0; i < cbCDB; i++)
78 outb(io_base+VBOXSCSI_REGISTER_COMMAND, read_byte(cdb_segment, aCDB + i));
79
80 /* Now wait for the command to complete. */
81 do
82 {
83 status = inb(io_base+VBOXSCSI_REGISTER_STATUS);
84 } while (status & VBOXSCSI_BUSY);
85
86#if 0
87 /* Get the read data. */
88 for (i = 0; i < cbBuffer; i++)
89 {
90 Bit8u data;
91
92 data = inb(io_base+VBOXSCSI_REGISTER_DATA_IN);
93 write_byte(segment, offset+i, data);
94
95 VBOXSCSI_DEBUG("buffer[%d]=%x\n", i, data);
96 }
97#else
98 io_base = io_base + VBOXSCSI_REGISTER_DATA_IN;
99
100ASM_START
101 push bp
102 mov bp, sp
103 mov di, _scsi_cmd_data_in.offset + 2[bp]
104 mov ax, _scsi_cmd_data_in.segment + 2[bp]
105 mov cx, _scsi_cmd_data_in.cbBuffer + 2[bp]
106
107 mov es, ax ;; segment in es
108 mov dx, _scsi_cmd_data_in.io_base + 2[bp] ;; SCSI data read port
109
110 rep
111 insb ;; CX dwords transfered from port(DX) to ES:[DI]
112
113 pop bp
114ASM_END
115#endif
116
117 return 0;
118}
119
120int scsi_cmd_data_out(io_base, device_id, cdb_segment, aCDB, cbCDB, segment, offset, cbBuffer)
121 Bit16u io_base, aCDB, offset, cbBuffer, segment, cdb_segment;
122 Bit8u device_id, cbCDB;
123{
124 /* Check that the adapter is ready. */
125 Bit8u status;
126 Bit16u i;
127
128 do
129 {
130 status = inb(io_base+VBOXSCSI_REGISTER_STATUS);
131 } while (status & VBOXSCSI_BUSY);
132
133 /* Write target ID. */
134 outb(io_base+VBOXSCSI_REGISTER_COMMAND, device_id);
135 /* Write transfer direction. */
136 outb(io_base+VBOXSCSI_REGISTER_COMMAND, SCSI_TXDIR_TO_DEVICE);
137 /* Write the CDB size. */
138 outb(io_base+VBOXSCSI_REGISTER_COMMAND, cbCDB);
139 /* Write buffer size. */
140 outb(io_base+VBOXSCSI_REGISTER_COMMAND, cbBuffer);
141 outb(io_base+VBOXSCSI_REGISTER_COMMAND, (cbBuffer >> 8));
142 /* Write the CDB. */
143 for (i = 0; i < cbCDB; i++)
144 outb(io_base+VBOXSCSI_REGISTER_COMMAND, read_byte(cdb_segment, aCDB + i));
145
146 /* Write data to I/O port. */
147 for (i = 0; i < cbBuffer; i++)
148 {
149 Bit8u data;
150
151 data = read_byte(segment, offset+i);
152 outb(io_base+VBOXSCSI_REGISTER_DATA_IN, data);
153
154 VBOXSCSI_DEBUG("buffer[%d]=%x\n", i, data);
155 }
156
157 /* Now wait for the command to complete. */
158 do
159 {
160 status = inb(io_base+VBOXSCSI_REGISTER_STATUS);
161 } while (status & VBOXSCSI_BUSY);
162
163 return 0;
164}
165
166
167/**
168 * Read sectors from an attached scsi device.
169 *
170 * @returns status code.
171 * @param device_id Id of the SCSI device to read from.
172 * @param count The number of sectors to read.
173 * @param lba The start sector to read from.
174 * @param segment The segment the buffer is in.
175 * @param offset The offset of the buffer.
176 */
177int scsi_read_sectors(device_id, count, lba, segment, offset)
178 Bit8u device_id;
179 Bit16u count, segment, offset;
180 Bit32u lba;
181{
182 Bit8u rc;
183 Bit8u aCDB[10];
184 Bit16u io_base, ebda_seg;
185 Bit8u target_id;
186
187 if (device_id > BX_MAX_SCSI_DEVICES)
188 BX_PANIC("scsi_read_sectors: device_id out of range %d\n", device_id);
189
190 // Reset count of transferred data
191 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
192 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
193
194 /* Prepare CDB */
195 write_byte(get_SS(), aCDB + 0, SCSI_READ_10);
196 write_byte(get_SS(), aCDB + 1, 0);
197 write_byte(get_SS(), aCDB + 2, (uint8_t)(lba >> 24));
198 write_byte(get_SS(), aCDB + 3, (uint8_t)(lba >> 16));
199 write_byte(get_SS(), aCDB + 4, (uint8_t)(lba >> 8));
200 write_byte(get_SS(), aCDB + 5, (uint8_t)(lba));
201 write_byte(get_SS(), aCDB + 6, 0);
202 write_byte(get_SS(), aCDB + 7, (uint8_t)(count >> 8));
203 write_byte(get_SS(), aCDB + 8, (uint8_t)(count));
204 write_byte(get_SS(), aCDB + 9, 0);
205
206 ebda_seg = read_word(0x0040, 0x000E);
207 io_base = read_word(ebda_seg, &EbdaData->scsi.devices[device_id].io_base);
208 target_id = read_byte(ebda_seg, &EbdaData->scsi.devices[device_id].target_id);
209
210 rc = scsi_cmd_data_in(io_base, target_id, get_SS(), aCDB, 10, segment, offset, (count * 512));
211
212 if (!rc)
213 {
214 write_word(ebda_seg, &EbdaData->ata.trsfsectors, count);
215 write_dword(ebda_seg, &EbdaData->ata.trsfbytes, (count * 512));
216 }
217
218 return rc;
219}
220
221/**
222 * Write sectors to an attached scsi device.
223 *
224 * @returns status code.
225 * @param device_id Id of the SCSI device to write to.
226 * @param count The number of sectors to write.
227 * @param lba The start sector to write to.
228 * @param segment The segment the buffer is in.
229 * @param offset The offset of the buffer.
230 */
231int scsi_write_sectors(device_id, count, lba, segment, offset)
232 Bit8u device_id;
233 Bit16u count, segment, offset;
234 Bit32u lba;
235{
236 Bit8u rc;
237 Bit8u aCDB[10];
238 Bit16u io_base, ebda_seg;
239 Bit8u target_id;
240
241 if (device_id > BX_MAX_SCSI_DEVICES)
242 BX_PANIC("scsi_write_sectors: device_id out of range %d\n", device_id);
243
244 // Reset count of transferred data
245 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
246 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
247
248 /* Prepare CDB */
249 write_byte(get_SS(), aCDB + 0, SCSI_WRITE_10);
250 write_byte(get_SS(), aCDB + 1, 0);
251 write_byte(get_SS(), aCDB + 2, (uint8_t)(lba >> 24));
252 write_byte(get_SS(), aCDB + 3, (uint8_t)(lba >> 16));
253 write_byte(get_SS(), aCDB + 4, (uint8_t)(lba >> 8));
254 write_byte(get_SS(), aCDB + 5, (uint8_t)(lba));
255 write_byte(get_SS(), aCDB + 6, 0);
256 write_byte(get_SS(), aCDB + 7, (uint8_t)(count >> 8));
257 write_byte(get_SS(), aCDB + 8, (uint8_t)(count));
258 write_byte(get_SS(), aCDB + 9, 0);
259
260 ebda_seg = read_word(0x0040, 0x000E);
261 io_base = read_word(ebda_seg, &EbdaData->scsi.devices[device_id].io_base);
262 target_id = read_byte(ebda_seg, &EbdaData->scsi.devices[device_id].target_id);
263
264 rc = scsi_cmd_data_out(io_base, target_id, get_SS(), aCDB, 10, segment, offset, (count * 512));
265
266 if (!rc)
267 {
268 write_word(ebda_seg, &EbdaData->ata.trsfsectors, count);
269 write_dword(ebda_seg, &EbdaData->ata.trsfbytes, (count * 512));
270 }
271
272 return rc;
273}
274
275/**
276 * Enumerate attached devices.
277 *
278 * @returns nothing.
279 * @param io_base The I/O base port of the controller.
280 */
281void scsi_enumerate_attached_devices(io_base)
282 Bit16u io_base;
283{
284 Bit16u ebda_seg;
285 Bit8u i;
286 Bit8u buffer[0x0200];
287
288 ebda_seg = read_word(0x0040, 0x000E);
289
290 write_byte(ebda_seg, &EbdaData->scsi.hdcount, 0);
291
292 /* Go through target devices. */
293 for (i = 0; i < VBOXSCSI_MAX_DEVICES; i++)
294 {
295 Bit8u rc;
296 Bit8u z;
297 Bit8u aCDB[10];
298
299 write_byte(get_SS(), aCDB + 0, SCSI_INQUIRY);
300 write_byte(get_SS(), aCDB + 1, 0);
301 write_byte(get_SS(), aCDB + 2, 0);
302 write_byte(get_SS(), aCDB + 3, 0);
303 write_byte(get_SS(), aCDB + 4, 5); /* Allocation length. */
304 write_byte(get_SS(), aCDB + 5, 0);
305
306 rc = scsi_cmd_data_in(io_base, i, get_SS(), aCDB, 6, get_SS(), buffer, 5);
307 if (rc != 0)
308 BX_PANIC("scsi_enumerate_attached_devices: SCSI_INQUIRY failed\n");
309
310 /* Check if there is a disk attached. */
311 if ( ((buffer[0] & 0xe0) == 0)
312 && ((buffer[0] & 0x1f) == 0x00))
313 {
314 VBOXSCSI_DEBUG("scsi_enumerate_attached_devices: Disk detected at %d\n", i);
315
316 /* We add the disk only if the maximum is not reached yet. */
317 if (read_byte(ebda_seg, &EbdaData->scsi.hdcount) < BX_MAX_SCSI_DEVICES)
318 {
319 Bit32u sectors, sector_size, cylinders;
320 Bit16u heads, sectors_per_track;
321 Bit8u hdcount, hdcount_scsi;
322
323 /* Issue a read capacity command now. */
324 write_byte(get_SS(), aCDB + 0, SCSI_READ_CAPACITY);
325 memsetb(get_SS(), aCDB + 1, 0, 9);
326
327 rc = scsi_cmd_data_in(io_base, i, get_SS(), aCDB, 10, get_SS(), buffer, 8);
328 if (rc != 0)
329 BX_PANIC("scsi_enumerate_attached_devices: SCSI_READ_CAPACITY failed\n");
330
331 /* Build sector number and size from the buffer. */
332 sectors = ((uint32_t)read_byte(get_SS(), buffer + 0) << 24)
333 | ((uint32_t)read_byte(get_SS(), buffer + 1) << 16)
334 | ((uint32_t)read_byte(get_SS(), buffer + 2) << 8)
335 | ((uint32_t)read_byte(get_SS(), buffer + 3));
336
337 sector_size = ((uint32_t)read_byte(get_SS(), buffer + 4) << 24)
338 | ((uint32_t)read_byte(get_SS(), buffer + 5) << 16)
339 | ((uint32_t)read_byte(get_SS(), buffer + 6) << 8)
340 | ((uint32_t)read_byte(get_SS(), buffer + 7));
341
342 /* We only support the disk if sector size is 512 bytes. */
343 if (sector_size != 512)
344 {
345 /* Leave a log entry. */
346 BX_INFO("Disk %d has an unsupported sector size of %u\n", i, sector_size);
347 continue;
348 }
349
350 /* We need to calculate the geometry for the disk. */
351 if (io_base == BUSLOGIC_ISA_IO_PORT)
352 {
353 /* This is from the BusLogic driver in the Linux kernel. */
354 if (sectors >= 4 * 1024 * 1024)
355 {
356 heads = 255;
357 sectors_per_track = 63;
358 }
359 else if (sectors >= 2 * 1024 * 1024)
360 {
361 heads = 128;
362 sectors_per_track = 32;
363 }
364 else
365 {
366 heads = 64;
367 sectors_per_track = 32;
368 }
369 cylinders = (uint32_t)(sectors / (heads * sectors_per_track));
370 }
371 else if (io_base == LSILOGIC_ISA_IO_PORT)
372 {
373 /* This is from the BusLogic driver in the Linux kernel. */
374 if (sectors >= 4 * 1024 * 1024)
375 {
376 heads = 255;
377 sectors_per_track = 63;
378 }
379 else if (sectors >= 2 * 1024 * 1024)
380 {
381 heads = 128;
382 sectors_per_track = 32;
383 }
384 else
385 {
386 heads = 64;
387 sectors_per_track = 32;
388 }
389 cylinders = (uint32_t)(sectors / (heads * sectors_per_track));
390 }
391 hdcount_scsi = read_byte(ebda_seg, &EbdaData->scsi.hdcount);
392
393 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].io_base, io_base);
394 write_byte(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].target_id, i);
395 write_byte(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.type, ATA_TYPE_SCSI);
396 write_byte(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.device, ATA_DEVICE_HD);
397 write_byte(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.removable, 0);
398 write_byte(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.lock, 0);
399 write_byte(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.mode, ATA_MODE_PIO16);
400 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.blksize, sector_size);
401 write_byte(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.translation, ATA_TRANSLATION_LBA);
402
403 /* Write lchs values. */
404 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.lchs.heads, heads);
405 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.lchs.spt, sectors_per_track);
406 if (cylinders > 1024)
407 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.lchs.cylinders, 1024);
408 else
409 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.lchs.cylinders, (Bit16u)cylinders);
410
411 /* Write pchs values. */
412 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.pchs.heads, heads);
413 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.pchs.spt, sectors_per_track);
414 if (cylinders > 1024)
415 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.pchs.cylinders, 1024);
416 else
417 write_word(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.pchs.cylinders, (Bit16u)cylinders);
418
419 write_dword(ebda_seg, &EbdaData->scsi.devices[hdcount_scsi].device_info.sectors, sectors);
420
421 /* Store the id of the disk in the ata hdidmap. */
422 hdcount = read_byte(ebda_seg, &EbdaData->ata.hdcount);
423 write_byte(ebda_seg, &EbdaData->ata.hdidmap[hdcount], hdcount_scsi + BX_MAX_ATA_DEVICES);
424 hdcount++;
425 write_byte(ebda_seg, &EbdaData->ata.hdcount, hdcount);
426
427 hdcount_scsi++;
428 write_byte(ebda_seg, &EbdaData->scsi.hdcount, hdcount_scsi);
429 }
430 else
431 {
432 /* We reached the maximum of SCSI disks we can boot from. We can quit detecting. */
433 break;
434 }
435 }
436 else
437 VBOXSCSI_DEBUG("scsi_enumerate_attached_devices: No disk detected at %d\n", i);
438 }
439}
440
441/**
442 * Init the SCSI driver and detect attached disks.
443 */
444void scsi_init( )
445{
446 Bit8u identifier;
447
448 identifier = 0;
449
450 /* Detect BusLogic adapter. */
451 outb(BUSLOGIC_ISA_IO_PORT+VBOXSCSI_REGISTER_IDENTIFY, 0x55);
452 identifier = inb(BUSLOGIC_ISA_IO_PORT+VBOXSCSI_REGISTER_IDENTIFY);
453
454 if (identifier == 0x55)
455 {
456 /* Detected - Enumerate attached devices. */
457 VBOXSCSI_DEBUG("scsi_init: BusLogic SCSI adapter detected\n");
458 scsi_enumerate_attached_devices(BUSLOGIC_ISA_IO_PORT);
459 }
460 else
461 {
462 VBOXSCSI_DEBUG("scsi_init: BusLogic SCSI adapter not detected\n");
463 }
464
465 /* Detect LsiLogic adapter. */
466 outb(LSILOGIC_ISA_IO_PORT+VBOXSCSI_REGISTER_IDENTIFY, 0x55);
467 identifier = inb(LSILOGIC_ISA_IO_PORT+VBOXSCSI_REGISTER_IDENTIFY);
468
469 if (identifier == 0x55)
470 {
471 /* Detected - Enumerate attached devices. */
472 VBOXSCSI_DEBUG("scsi_init: LsiLogic SCSI adapter detected\n");
473 scsi_enumerate_attached_devices(LSILOGIC_ISA_IO_PORT);
474 }
475 else
476 {
477 VBOXSCSI_DEBUG("scsi_init: LsiLogic SCSI adapter not detected\n");
478 }
479}
480
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette