/[gxemul]/trunk/src/diskimage.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/diskimage.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 44299 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: diskimage.c,v 1.91 2005/05/27 07:29:24 debug Exp $
29 *
30 * Disk image support.
31 *
32 * TODO: There's probably a bug in the tape support:
33 * Let's say there are 10240 bytes left in a file, and 10240
34 * bytes are read. Then feof() is not true yet (?), so the next
35 * read will also return 10240 bytes (but all zeroes), and then after
36 * that return feof (which results in a filemark). This is probably
37 * trivial to fix, but I don't feel like it right now.
38 *
39 * TODO: diskimage_remove()? This would be useful for floppies in PC-style
40 * machines, where disks may need to be swapped during boot etc.
41 */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49
50 #include "cpu.h"
51 #include "diskimage.h"
52 #include "machine.h"
53 #include "misc.h"
54
55
56 extern int quiet_mode;
57 extern int single_step;
58
59 static char *diskimage_types[] = DISKIMAGE_TYPES;
60
61 static struct scsi_transfer *first_free_scsi_transfer_alloc = NULL;
62
63
64 /**************************************************************************/
65
66 /*
67 * my_fseek():
68 *
69 * A helper function, like fseek() but takes off_t. If the system has
70 * fseeko, then that is used. Otherwise I try to fake off_t offsets here.
71 *
72 * The correct position is reached by seeking 2 billion bytes at a time
73 * (or less). Note: This method is only used for SEEK_SET, for SEEK_CUR
74 * and SEEK_END, normal fseek() is used!
75 *
76 * TODO: It seemed to work on Linux/i386, but not on Solaris/sparc (?).
77 * Anyway, most modern systems have fseeko(), so it shouldn't be a problem.
78 */
79 static int my_fseek(FILE *f, off_t offset, int whence)
80 {
81 #ifdef HACK_FSEEKO
82 if (whence == SEEK_SET) {
83 int res = 0;
84 off_t curoff = 0;
85 off_t cur_step;
86
87 fseek(f, 0, SEEK_SET);
88 while (curoff < offset) {
89 /* How far to seek? */
90 cur_step = offset - curoff;
91 if (cur_step > 2000000000)
92 cur_step = 2000000000;
93 res = fseek(f, cur_step, SEEK_CUR);
94 if (res)
95 return res;
96 curoff += cur_step;
97 }
98 return 0;
99 } else
100 return fseek(f, offset, whence);
101 #else
102 return fseeko(f, offset, whence);
103 #endif
104 }
105
106
107 /**************************************************************************/
108
109
110 /*
111 * scsi_transfer_alloc():
112 *
113 * Allocates memory for a new scsi_transfer struct, and fills it with
114 * sane data (NULL pointers).
115 * The return value is a pointer to the new struct. If allocation
116 * failed, the program exits.
117 */
118 struct scsi_transfer *scsi_transfer_alloc(void)
119 {
120 struct scsi_transfer *p;
121
122 if (first_free_scsi_transfer_alloc != NULL) {
123 p = first_free_scsi_transfer_alloc;
124 first_free_scsi_transfer_alloc = p->next_free;
125 } else {
126 p = malloc(sizeof(struct scsi_transfer));
127 if (p == NULL) {
128 fprintf(stderr, "scsi_transfer_alloc(): out "
129 "of memory\n");
130 exit(1);
131 }
132 }
133
134 memset(p, 0, sizeof(struct scsi_transfer));
135
136 return p;
137 }
138
139
140 /*
141 * scsi_transfer_free():
142 *
143 * Frees the space used by a scsi_transfer struct. All buffers refered
144 * to by the scsi_transfer struct are freed.
145 */
146 void scsi_transfer_free(struct scsi_transfer *p)
147 {
148 if (p == NULL) {
149 fprintf(stderr, "scsi_transfer_free(): p == NULL\n");
150 exit(1);
151 }
152
153 if (p->msg_out != NULL)
154 free(p->msg_out);
155 if (p->cmd != NULL)
156 free(p->cmd);
157 if (p->data_out != NULL)
158 free(p->data_out);
159
160 if (p->data_in != NULL)
161 free(p->data_in);
162 if (p->msg_in != NULL)
163 free(p->msg_in);
164 if (p->status != NULL)
165 free(p->status);
166
167 p->next_free = first_free_scsi_transfer_alloc;
168 first_free_scsi_transfer_alloc = p;
169 }
170
171
172 /*
173 * scsi_transfer_allocbuf():
174 *
175 * Helper function, used by diskimage_scsicommand(), and SCSI controller
176 * devices. Example of usage:
177 *
178 * scsi_transfer_allocbuf(&xferp->msg_in_len, &xferp->msg_in, 1);
179 */
180 void scsi_transfer_allocbuf(size_t *lenp, unsigned char **pp, size_t want_len,
181 int clearflag)
182 {
183 unsigned char *p = (*pp);
184
185 if (p != NULL) {
186 printf("WARNING! scsi_transfer_allocbuf(): old pointer "
187 "was not NULL, freeing it now\n");
188 free(p);
189 }
190
191 (*lenp) = want_len;
192 if ((p = malloc(want_len)) == NULL) {
193 fprintf(stderr, "scsi_transfer_allocbuf(): out of "
194 "memory trying to allocate %li bytes\n", (long)want_len);
195 exit(1);
196 }
197
198 if (clearflag)
199 memset(p, 0, want_len);
200
201 (*pp) = p;
202 }
203
204
205 /**************************************************************************/
206
207
208 /*
209 * diskimage_exist():
210 *
211 * Returns 1 if the specified disk id (for a specific type) exists, 0
212 * otherwise.
213 */
214 int diskimage_exist(struct machine *machine, int id, int type)
215 {
216 struct diskimage *d = machine->first_diskimage;
217
218 while (d != NULL) {
219 if (d->type == type && d->id == id)
220 return 1;
221 d = d->next;
222 }
223 return 0;
224 }
225
226
227 /*
228 * diskimage_recalc_size():
229 *
230 * Recalculate a disk's size by stat()-ing it.
231 * d is assumed to be non-NULL.
232 */
233 static void diskimage_recalc_size(struct diskimage *d)
234 {
235 struct stat st;
236 int res;
237 off_t size = 0;
238
239 res = stat(d->fname, &st);
240 if (res) {
241 fprintf(stderr, "[ diskimage_recalc_size(): could not stat "
242 "'%s' ]\n", d->fname);
243 return;
244 }
245
246 size = st.st_size;
247
248 /*
249 * TODO: CD-ROM devices, such as /dev/cd0c, how can one
250 * check how much data is on that cd-rom without reading it?
251 * For now, assume some large number, hopefully it will be
252 * enough to hold any cd-rom image.
253 */
254 if (d->is_a_cdrom && size == 0)
255 size = 762048000;
256
257 d->total_size = size;
258 d->ncyls = d->total_size / 1048576;
259
260 /* TODO: There is a mismatch between d->ncyls and d->cylinders,
261 SCSI-based stuff usually doesn't care. TODO: Fix this. */
262 }
263
264
265 /*
266 * diskimage_getsize():
267 *
268 * Returns -1 if the specified disk id/type does not exists, otherwise
269 * the size of the disk image is returned.
270 */
271 int64_t diskimage_getsize(struct machine *machine, int id, int type)
272 {
273 struct diskimage *d = machine->first_diskimage;
274
275 while (d != NULL) {
276 if (d->type == type && d->id == id)
277 return d->total_size;
278 d = d->next;
279 }
280 return -1;
281 }
282
283
284 /*
285 * diskimage_getchs():
286 *
287 * Returns the current CHS values of a disk image.
288 */
289 void diskimage_getchs(struct machine *machine, int id, int type,
290 int *c, int *h, int *s)
291 {
292 struct diskimage *d = machine->first_diskimage;
293
294 while (d != NULL) {
295 if (d->type == type && d->id == id) {
296 *c = d->cylinders;
297 *h = d->heads;
298 *s = d->sectors_per_track;
299 return;
300 }
301 d = d->next;
302 }
303 fatal("diskimage_getchs(): disk id %i (type %i) not found?\n",
304 id, diskimage_types[type]);
305 exit(1);
306 }
307
308
309 /*
310 * diskimage__return_default_status_and_message():
311 *
312 * Set the status and msg_in parts of a scsi_transfer struct
313 * to default values (msg_in = 0x00, status = 0x00).
314 */
315 static void diskimage__return_default_status_and_message(
316 struct scsi_transfer *xferp)
317 {
318 scsi_transfer_allocbuf(&xferp->status_len, &xferp->status, 1, 0);
319 xferp->status[0] = 0x00;
320 scsi_transfer_allocbuf(&xferp->msg_in_len, &xferp->msg_in, 1, 0);
321 xferp->msg_in[0] = 0x00;
322 }
323
324
325 /*
326 * diskimage__switch_tape():
327 *
328 * Used by the SPACE command. (d is assumed to be non-NULL.)
329 */
330 static void diskimage__switch_tape(struct diskimage *d)
331 {
332 char tmpfname[1000];
333
334 snprintf(tmpfname, sizeof(tmpfname), "%s.%i",
335 d->fname, d->tape_filenr);
336 tmpfname[sizeof(tmpfname)-1] = '\0';
337
338 if (d->f != NULL)
339 fclose(d->f);
340
341 d->f = fopen(tmpfname, d->writable? "r+" : "r");
342 if (d->f == NULL) {
343 fprintf(stderr, "[ diskimage__switch_tape(): could not "
344 "(re)open '%s' ]\n", tmpfname);
345 /* TODO: return error */
346 }
347 d->tape_offset = 0;
348 }
349
350
351 /*
352 * diskimage_access__cdrom():
353 *
354 * This is a special-case function, called from diskimage__internal_access().
355 * On my FreeBSD 4.9 system, the cdrom device /dev/cd0c seems to not be able
356 * to handle something like "fseek(512); fread(512);" but it handles
357 * "fseek(2048); fread(512);" just fine. So, if diskimage__internal_access()
358 * fails in reading a block of data, this function is called as an attempt to
359 * align reads at 2048-byte sectors instead.
360 *
361 * (Ugly hack. TODO: how to solve this cleanly?)
362 *
363 * NOTE: Returns the number of bytes read, 0 if nothing was successfully
364 * read. (These are not the same as diskimage_access()).
365 */
366 #define CDROM_SECTOR_SIZE 2048
367 static size_t diskimage_access__cdrom(struct diskimage *d, off_t offset,
368 unsigned char *buf, size_t len)
369 {
370 off_t aligned_offset;
371 size_t bytes_read, total_copied = 0;
372 unsigned char cdrom_buf[CDROM_SECTOR_SIZE];
373 off_t buf_ofs, i = 0;
374
375 /* printf("diskimage_access__cdrom(): offset=0x%llx size=%lli\n",
376 (long long)offset, (long long)len); */
377
378 aligned_offset = (offset / CDROM_SECTOR_SIZE) * CDROM_SECTOR_SIZE;
379 my_fseek(d->f, aligned_offset, SEEK_SET);
380
381 while (len != 0) {
382 bytes_read = fread(cdrom_buf, 1, CDROM_SECTOR_SIZE, d->f);
383 if (bytes_read != CDROM_SECTOR_SIZE)
384 return 0;
385
386 /* Copy (part of) cdrom_buf into buf: */
387 buf_ofs = offset - aligned_offset;
388 while (buf_ofs < CDROM_SECTOR_SIZE && len != 0) {
389 buf[i ++] = cdrom_buf[buf_ofs ++];
390 total_copied ++;
391 len --;
392 }
393
394 aligned_offset += CDROM_SECTOR_SIZE;
395 offset = aligned_offset;
396 }
397
398 return total_copied;
399 }
400
401
402 /*
403 * diskimage__internal_access():
404 *
405 * Read from or write to a struct diskimage.
406 *
407 * Returns 1 if the access completed successfully, 0 otherwise.
408 */
409 static int diskimage__internal_access(struct diskimage *d, int writeflag,
410 off_t offset, unsigned char *buf, size_t len)
411 {
412 size_t lendone;
413 int res;
414
415 if (buf == NULL) {
416 fprintf(stderr, "diskimage__internal_access(): buf = NULL\n");
417 exit(1);
418 }
419 if (len == 0)
420 return 1;
421 if (d->f == NULL)
422 return 0;
423
424 res = my_fseek(d->f, offset, SEEK_SET);
425 if (res != 0) {
426 fatal("[ diskimage__internal_access(): fseek() failed on "
427 "disk id %i \n", d->id);
428 return 0;
429 }
430
431 if (writeflag) {
432 if (!d->writable)
433 return 0;
434
435 lendone = fwrite(buf, 1, len, d->f);
436 } else {
437 /*
438 * Special case for CD-ROMs. Actually, this is not needed
439 * for .iso images, only for physical CDROMS on some OSes,
440 * such as FreeBSD.
441 */
442 if (d->is_a_cdrom)
443 lendone = diskimage_access__cdrom(d, offset, buf, len);
444 else
445 lendone = fread(buf, 1, len, d->f);
446
447 if (lendone < (ssize_t)len)
448 memset(buf + lendone, 0, len - lendone);
449 }
450
451 /* Warn about non-complete data transfers: */
452 if (lendone != (ssize_t)len) {
453 fatal("[ diskimage__internal_access(): disk_id %i, offset %lli"
454 ", transfer not completed. len=%i, len_done=%i ]\n",
455 d->id, (long long)offset, (int)len, (int)lendone);
456 return 0;
457 }
458
459 return 1;
460 }
461
462
463 /*
464 * diskimage_scsicommand():
465 *
466 * Perform a SCSI command on a disk image.
467 *
468 * The xferp points to a scsi_transfer struct, containing msg_out, command,
469 * and data_out coming from the SCSI controller device. This function
470 * interprets the command, and (if necessary) creates responses in
471 * data_in, msg_in, and status.
472 *
473 * Returns:
474 * 2 if the command expects data from the DATA_OUT phase,
475 * 1 if otherwise ok,
476 * 0 on error.
477 */
478 int diskimage_scsicommand(struct cpu *cpu, int id, int type,
479 struct scsi_transfer *xferp)
480 {
481 int retlen, i;
482 uint64_t size;
483 int64_t ofs;
484 int pagecode;
485 struct machine *machine = cpu->machine;
486 struct diskimage *d;
487
488 if (machine == NULL) {
489 fatal("[ diskimage_scsicommand(): machine == NULL ]\n");
490 return 0;
491 }
492
493 d = machine->first_diskimage;
494 while (d != NULL) {
495 if (d->type == type && d->id == id)
496 break;
497 d = d->next;
498 }
499 if (d == NULL) {
500 fprintf(stderr, "[ diskimage_scsicommand(): %s "
501 " id %i not connected? ]\n", diskimage_types[type], id);
502 }
503
504 if (xferp->cmd == NULL) {
505 fatal("[ diskimage_scsicommand(): cmd == NULL ]\n");
506 return 0;
507 }
508
509 if (xferp->cmd_len < 1) {
510 fatal("[ diskimage_scsicommand(): cmd_len == %i ]\n",
511 xferp->cmd_len);
512 return 0;
513 }
514
515 debug("[ diskimage_scsicommand(id=%i) cmd=0x%02x: ",
516 id, xferp->cmd[0]);
517
518 #if 0
519 fatal("[ diskimage_scsicommand(id=%i) cmd=0x%02x len=%i:",
520 id, xferp->cmd[0], xferp->cmd_len);
521 for (i=0; i<xferp->cmd_len; i++)
522 fatal(" %02x", xferp->cmd[i]);
523 fatal("\n");
524 if (xferp->cmd_len > 7 && xferp->cmd[5] == 0x11)
525 single_step = 1;
526 #endif
527
528 #if 0
529 {
530 static FILE *f = NULL;
531 if (f == NULL)
532 f = fopen("scsi_log.txt", "w");
533 if (f != NULL) {
534 int i;
535 fprintf(f, "id=%i cmd =", id);
536 for (i=0; i<xferp->cmd_len; i++)
537 fprintf(f, " %02x", xferp->cmd[i]);
538 fprintf(f, "\n");
539 fflush(f);
540 }
541 }
542 #endif
543
544 switch (xferp->cmd[0]) {
545
546 case SCSICMD_TEST_UNIT_READY:
547 debug("TEST_UNIT_READY");
548 if (xferp->cmd_len != 6)
549 debug(" (weird len=%i)", xferp->cmd_len);
550
551 /* TODO: bits 765 of buf[1] contains the LUN */
552 if (xferp->cmd[1] != 0x00)
553 fatal("WARNING: TEST_UNIT_READY with cmd[1]=0x%02x"
554 " not yet implemented\n", (int)xferp->cmd[1]);
555
556 diskimage__return_default_status_and_message(xferp);
557 break;
558
559 case SCSICMD_INQUIRY:
560 debug("INQUIRY");
561 if (xferp->cmd_len != 6)
562 debug(" (weird len=%i)", xferp->cmd_len);
563 if (xferp->cmd[1] != 0x00) {
564 debug("WARNING: INQUIRY with cmd[1]=0x%02x not yet "
565 "implemented\n", (int)xferp->cmd[1]);
566
567 break;
568 }
569
570 /* Return values: */
571 retlen = xferp->cmd[4];
572 if (retlen < 36) {
573 fatal("WARNING: SCSI inquiry len=%i, <36!\n", retlen);
574 retlen = 36;
575 }
576
577 /* Return data: */
578 scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
579 retlen, 1);
580 xferp->data_in[0] = 0x00; /* 0x00 = Direct-access disk */
581 xferp->data_in[1] = 0x00; /* 0x00 = non-removable */
582 xferp->data_in[2] = 0x02; /* SCSI-2 */
583 #if 0
584 xferp->data_in[3] = 0x02; /* Response data format = SCSI-2 */
585 #endif
586 xferp->data_in[4] = retlen - 4; /* Additional length */
587 xferp->data_in[4] = 0x2c - 4; /* Additional length */
588 xferp->data_in[6] = 0x04; /* ACKREQQ */
589 xferp->data_in[7] = 0x60; /* WBus32, WBus16 */
590
591 /* These must be padded with spaces: */
592 memcpy(xferp->data_in+8, "FAKE ", 8);
593 memcpy(xferp->data_in+16, "DISK ", 16);
594 memcpy(xferp->data_in+32, "V0.0", 4);
595
596 /*
597 * Some Ultrix kernels want specific responses from
598 * the drives.
599 */
600
601 if (machine->machine_type == MACHINE_DEC) {
602 /* DEC, RZ25 (rev 0900) = 832527 sectors */
603 /* DEC, RZ58 (rev 2000) = 2698061 sectors */
604 memcpy(xferp->data_in+8, "DEC ", 8);
605 memcpy(xferp->data_in+16, "RZ58 (C) DEC", 16);
606 memcpy(xferp->data_in+32, "2000", 4);
607 }
608
609 /* Some data is different for CD-ROM drives: */
610 if (d->is_a_cdrom) {
611 xferp->data_in[0] = 0x05; /* 0x05 = CD-ROM */
612 xferp->data_in[1] = 0x80; /* 0x80 = removable */
613 memcpy(xferp->data_in+16, "CD-ROM ", 16);
614
615 if (machine->machine_type == MACHINE_DEC) {
616 /* SONY, CD-ROM: */
617 memcpy(xferp->data_in+8, "SONY ", 8);
618 memcpy(xferp->data_in+16,
619 "CD-ROM ", 16);
620
621 /* ... or perhaps this: */
622 memcpy(xferp->data_in+8, "DEC ", 8);
623 memcpy(xferp->data_in+16,
624 "RRD42 (C) DEC ", 16);
625 memcpy(xferp->data_in+32, "4.5d", 4);
626 } else {
627 /* NEC, CD-ROM: */
628 memcpy(xferp->data_in+8, "NEC ", 8);
629 memcpy(xferp->data_in+16,
630 "CD-ROM CDR-210P ", 16);
631 memcpy(xferp->data_in+32, "1.0 ", 4);
632 }
633 }
634
635 /* Data for tape devices: */
636 if (d->is_a_tape) {
637 xferp->data_in[0] = 0x01; /* 0x01 = tape */
638 xferp->data_in[1] = 0x80; /* 0x80 = removable */
639 memcpy(xferp->data_in+16, "TAPE ", 16);
640
641 if (machine->machine_type == MACHINE_DEC) {
642 /*
643 * TODO: find out if these are correct.
644 *
645 * The name might be TZK10, TSZ07, or TLZ04,
646 * or something completely different.
647 */
648 memcpy(xferp->data_in+8, "DEC ", 8);
649 memcpy(xferp->data_in+16,
650 "TK50 (C) DEC", 16);
651 memcpy(xferp->data_in+32, "2000", 4);
652 }
653 }
654
655 diskimage__return_default_status_and_message(xferp);
656 break;
657
658 case SCSIBLOCKCMD_READ_CAPACITY:
659 debug("READ_CAPACITY");
660
661 if (xferp->cmd_len != 10)
662 fatal(" [ weird READ_CAPACITY len=%i, should be 10 ] ",
663 xferp->cmd_len);
664 else {
665 if (xferp->cmd[8] & 1) {
666 /* Partial Medium Indicator bit... TODO */
667 fatal("WARNING: READ_CAPACITY with PMI bit"
668 " set not yet implemented\n");
669 }
670 }
671
672 /* Return data: */
673 scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
674 8, 1);
675
676 diskimage_recalc_size(d);
677
678 size = d->total_size / d->logical_block_size;
679 if (d->total_size & (d->logical_block_size-1))
680 size ++;
681
682 xferp->data_in[0] = (size >> 24) & 255;
683 xferp->data_in[1] = (size >> 16) & 255;
684 xferp->data_in[2] = (size >> 8) & 255;
685 xferp->data_in[3] = size & 255;
686
687 xferp->data_in[4] = (d->logical_block_size >> 24) & 255;
688 xferp->data_in[5] = (d->logical_block_size >> 16) & 255;
689 xferp->data_in[6] = (d->logical_block_size >> 8) & 255;
690 xferp->data_in[7] = d->logical_block_size & 255;
691
692 diskimage__return_default_status_and_message(xferp);
693 break;
694
695 case SCSICMD_MODE_SENSE:
696 debug("MODE_SENSE");
697
698 if (xferp->cmd_len != 6)
699 fatal(" (unimplemented mode_sense len=%i)",
700 xferp->cmd_len);
701
702 retlen = xferp->cmd[4];
703
704 /*
705 * NOTE/TODO: This code doesn't handle too short retlens
706 * very well. A quick hack around this is that I allocate
707 * a bit too much memory, so that nothing is actually
708 * written outside of xferp->data_in[].
709 */
710
711 retlen += 100; /* Should be enough. (Ugly.) */
712
713 if ((xferp->cmd[2] & 0xc0) != 0)
714 fatal("WARNING: mode sense, cmd[2] = 0x%02x\n",
715 xferp->cmd[2]);
716
717 /* Return data: */
718 scsi_transfer_allocbuf(&xferp->data_in_len,
719 &xferp->data_in, retlen, 1);
720
721 xferp->data_in_len -= 100; /* Restore size. */
722
723 pagecode = xferp->cmd[2] & 0x3f;
724
725 debug("[ MODE SENSE id %i, pagecode=%i ]\n", id, pagecode);
726
727 /* 4 bytes of header for 6-byte command,
728 8 bytes of header for 10-byte command. */
729 xferp->data_in[0] = retlen; /* 0: mode data length */
730 xferp->data_in[1] = d->is_a_cdrom? 0x05 : 0x00;
731 /* 1: medium type */
732 xferp->data_in[2] = 0x00; /* device specific
733 parameter */
734 xferp->data_in[3] = 8 * 1; /* block descriptor
735 length: 1 page (?) */
736
737 /* TODO: update this when implementing 10-byte commands: */
738 xferp->data_in[4] = 0x00; /* density code */
739 xferp->data_in[5] = 0; /* nr of blocks, high */
740 xferp->data_in[6] = 0; /* nr of blocks, mid */
741 xferp->data_in[7] = 0; /* nr of blocks, low */
742 xferp->data_in[8] = 0x00; /* reserved */
743 xferp->data_in[9] = (d->logical_block_size >> 16) & 255;
744 xferp->data_in[10] = (d->logical_block_size >> 8) & 255;
745 xferp->data_in[11] = d->logical_block_size & 255;
746
747 diskimage__return_default_status_and_message(xferp);
748
749 /* descriptors, 8 bytes (each) */
750
751 /* page, n bytes (each) */
752 switch (pagecode) {
753 case 0:
754 /* TODO: Nothing here? */
755 break;
756 case 1: /* read-write error recovery page */
757 xferp->data_in[12 + 0] = pagecode;
758 xferp->data_in[12 + 1] = 10;
759 break;
760 case 3: /* format device page */
761 xferp->data_in[12 + 0] = pagecode;
762 xferp->data_in[12 + 1] = 22;
763
764 /* 10,11 = sectors per track */
765 xferp->data_in[12 + 10] = 0;
766 xferp->data_in[12 + 11] = d->sectors_per_track;
767
768 /* 12,13 = physical sector size */
769 xferp->data_in[12 + 12] =
770 (d->logical_block_size >> 8) & 255;
771 xferp->data_in[12 + 13] = d->logical_block_size & 255;
772 break;
773 case 4: /* rigid disk geometry page */
774 xferp->data_in[12 + 0] = pagecode;
775 xferp->data_in[12 + 1] = 22;
776 xferp->data_in[12 + 2] = (d->ncyls >> 16) & 255;
777 xferp->data_in[12 + 3] = (d->ncyls >> 8) & 255;
778 xferp->data_in[12 + 4] = d->ncyls & 255;
779 xferp->data_in[12 + 5] = d->heads;
780
781 xferp->data_in[12 + 20] = (d->rpms >> 8) & 255;
782 xferp->data_in[12 + 21] = d->rpms & 255;
783 break;
784 case 5: /* flexible disk page */
785 xferp->data_in[12 + 0] = pagecode;
786 xferp->data_in[12 + 1] = 0x1e;
787
788 /* 2,3 = transfer rate */
789 xferp->data_in[12 + 2] = ((5000) >> 8) & 255;
790 xferp->data_in[12 + 3] = (5000) & 255;
791
792 xferp->data_in[12 + 4] = d->heads;
793 xferp->data_in[12 + 5] = d->sectors_per_track;
794
795 /* 6,7 = data bytes per sector */
796 xferp->data_in[12 + 6] = (d->logical_block_size >> 8)
797 & 255;
798 xferp->data_in[12 + 7] = d->logical_block_size & 255;
799
800 xferp->data_in[12 + 8] = (d->ncyls >> 8) & 255;
801 xferp->data_in[12 + 9] = d->ncyls & 255;
802
803 xferp->data_in[12 + 28] = (d->rpms >> 8) & 255;
804 xferp->data_in[12 + 29] = d->rpms & 255;
805 break;
806 default:
807 fatal("[ MODE_SENSE for page %i is not yet "
808 "implemented! ]\n", pagecode);
809 }
810
811 break;
812
813 case SCSICMD_READ:
814 case SCSICMD_READ_10:
815 debug("READ");
816
817 /*
818 * For tape devices, read data at the current position.
819 * For disk and CDROM devices, the command bytes contain
820 * an offset telling us where to read from the device.
821 */
822
823 if (d->is_a_tape) {
824 /* bits 7..5 of cmd[1] are the LUN bits... TODO */
825
826 size = (xferp->cmd[2] << 16) +
827 (xferp->cmd[3] << 8) +
828 xferp->cmd[4];
829
830 /* Bit 1 of cmd[1] is the SILI bit (TODO), and
831 bit 0 is the "use fixed length" bit. */
832
833 if (xferp->cmd[1] & 0x01) {
834 /* Fixed block length: */
835 size *= d->logical_block_size;
836 }
837
838 if (d->filemark) {
839 /* At end of file, switch to the next
840 automagically: */
841 d->tape_filenr ++;
842 diskimage__switch_tape(d);
843
844 d->filemark = 0;
845 }
846
847 ofs = d->tape_offset;
848
849 fatal("[ READ tape, id=%i file=%i, cmd[1]=%02x size=%i"
850 ", ofs=%lli ]\n", id, d->tape_filenr,
851 xferp->cmd[1], (int)size, (long long)ofs);
852 } else {
853 if (xferp->cmd[0] == SCSICMD_READ) {
854 if (xferp->cmd_len != 6)
855 debug(" (weird len=%i)",
856 xferp->cmd_len);
857
858 /*
859 * bits 4..0 of cmd[1], and cmd[2] and cmd[3]
860 * hold the logical block address.
861 *
862 * cmd[4] holds the number of logical blocks
863 * to transfer. (Special case if the value is
864 * 0, actually means 256.)
865 */
866 ofs = ((xferp->cmd[1] & 0x1f) << 16) +
867 (xferp->cmd[2] << 8) + xferp->cmd[3];
868 retlen = xferp->cmd[4];
869 if (retlen == 0)
870 retlen = 256;
871 } else {
872 if (xferp->cmd_len != 10)
873 debug(" (weird len=%i)",
874 xferp->cmd_len);
875
876 /*
877 * cmd[2..5] hold the logical block address.
878 * cmd[7..8] holds the number of logical
879 * blocks to transfer. (NOTE: If the value is
880 * 0, this means 0, not 65536. :-)
881 */
882 ofs = (xferp->cmd[2] << 24) + (xferp->cmd[3]
883 << 16) + (xferp->cmd[4] << 8) +
884 xferp->cmd[5];
885 retlen = (xferp->cmd[7] << 8) + xferp->cmd[8];
886 }
887
888 size = retlen * d->logical_block_size;
889 ofs *= d->logical_block_size;
890 }
891
892 /* Return data: */
893 scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
894 size, 0);
895
896 debug(" READ ofs=%lli size=%i\n", (long long)ofs, (int)size);
897
898 diskimage__return_default_status_and_message(xferp);
899
900 d->filemark = 0;
901
902 /*
903 * Failure? Then set check condition.
904 * For tapes, error should only occur at the end of a file.
905 *
906 * "If the logical unit encounters a filemark during
907 * a READ command, CHECK CONDITION status shall be
908 * returned and the filemark and valid bits shall be
909 * set to one in the sense data. The sense key shall
910 * be set to NO SENSE"..
911 */
912 if (d->is_a_tape && d->f != NULL && feof(d->f)) {
913 debug(" feof id=%i\n", id);
914 xferp->status[0] = 0x02; /* CHECK CONDITION */
915
916 d->filemark = 1;
917 } else
918 diskimage__internal_access(d, 0, ofs,
919 xferp->data_in, size);
920
921 if (d->is_a_tape && d->f != NULL)
922 d->tape_offset = ftell(d->f);
923
924 /* TODO: other errors? */
925 break;
926
927 case SCSICMD_WRITE:
928 case SCSICMD_WRITE_10:
929 debug("WRITE");
930
931 /* TODO: tape */
932
933 if (xferp->cmd[0] == SCSICMD_WRITE) {
934 if (xferp->cmd_len != 6)
935 debug(" (weird len=%i)", xferp->cmd_len);
936
937 /*
938 * bits 4..0 of cmd[1], and cmd[2] and cmd[3] hold the
939 * logical block address.
940 *
941 * cmd[4] holds the number of logical blocks to
942 * transfer. (Special case if the value is 0, actually
943 * means 256.)
944 */
945 ofs = ((xferp->cmd[1] & 0x1f) << 16) +
946 (xferp->cmd[2] << 8) + xferp->cmd[3];
947 retlen = xferp->cmd[4];
948 if (retlen == 0)
949 retlen = 256;
950 } else {
951 if (xferp->cmd_len != 10)
952 debug(" (weird len=%i)", xferp->cmd_len);
953
954 /*
955 * cmd[2..5] hold the logical block address.
956 * cmd[7..8] holds the number of logical blocks to
957 * transfer. (NOTE: If the value is 0 this means 0,
958 * not 65536.)
959 */
960 ofs = (xferp->cmd[2] << 24) + (xferp->cmd[3] << 16) +
961 (xferp->cmd[4] << 8) + xferp->cmd[5];
962 retlen = (xferp->cmd[7] << 8) + xferp->cmd[8];
963 }
964
965 size = retlen * d->logical_block_size;
966 ofs *= d->logical_block_size;
967
968 if (xferp->data_out_offset != size) {
969 debug(", data_out == NULL, wanting %i bytes, \n\n",
970 (int)size);
971 xferp->data_out_len = size;
972 return 2;
973 }
974
975 debug(", data_out != NULL, OK :-)");
976
977 debug("WRITE ofs=%i size=%i offset=%i\n", (int)ofs,
978 (int)size, (int)xferp->data_out_offset);
979
980 diskimage__internal_access(d, 1, ofs,
981 xferp->data_out, size);
982
983 /* TODO: how about return code? */
984
985 /* Is this really necessary? */
986 /* fsync(fileno(d->f)); */
987
988 diskimage__return_default_status_and_message(xferp);
989 break;
990
991 case SCSICMD_SYNCHRONIZE_CACHE:
992 debug("SYNCHRONIZE_CACHE");
993
994 if (xferp->cmd_len != 10)
995 debug(" (weird len=%i)", xferp->cmd_len);
996
997 /* TODO: actualy care about cmd[] */
998 fsync(fileno(d->f));
999
1000 diskimage__return_default_status_and_message(xferp);
1001 break;
1002
1003 case SCSICMD_START_STOP_UNIT:
1004 debug("START_STOP_UNIT");
1005
1006 if (xferp->cmd_len != 6)
1007 debug(" (weird len=%i)", xferp->cmd_len);
1008
1009 for (i=0; i<xferp->cmd_len ; i++)
1010 debug(" %02x", xferp->cmd[i]);
1011
1012 /* TODO: actualy care about cmd[] */
1013
1014 diskimage__return_default_status_and_message(xferp);
1015 break;
1016
1017 case SCSICMD_REQUEST_SENSE:
1018 debug("REQUEST_SENSE");
1019
1020 retlen = xferp->cmd[4];
1021
1022 /* TODO: bits 765 of buf[1] contains the LUN */
1023 if (xferp->cmd[1] != 0x00)
1024 fatal("WARNING: REQUEST_SENSE with cmd[1]=0x%02x not"
1025 " yet implemented\n", (int)xferp->cmd[1]);
1026
1027 if (retlen < 18) {
1028 fatal("WARNING: SCSI request sense len=%i, <18!\n",
1029 (int)retlen);
1030 retlen = 18;
1031 }
1032
1033 /* Return data: */
1034 scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
1035 retlen, 1);
1036
1037 xferp->data_in[0] = 0x80 + 0x70;/* 0x80 = valid,
1038 0x70 = "current errors" */
1039 xferp->data_in[2] = 0x00; /* SENSE KEY! */
1040
1041 if (d->filemark) {
1042 xferp->data_in[2] = 0x80;
1043 }
1044 debug(": [2]=0x%02x ", xferp->data_in[2]);
1045
1046 printf(" XXX(!) \n");
1047
1048 /* TODO */
1049 xferp->data_in[7] = retlen - 7; /* additional sense length */
1050 /* TODO */
1051
1052 diskimage__return_default_status_and_message(xferp);
1053 break;
1054
1055 case SCSICMD_READ_BLOCK_LIMITS:
1056 debug("READ_BLOCK_LIMITS");
1057
1058 retlen = 6;
1059
1060 /* TODO: bits 765 of buf[1] contains the LUN */
1061 if (xferp->cmd[1] != 0x00)
1062 fatal("WARNING: READ_BLOCK_LIMITS with cmd[1]="
1063 "0x%02x not yet implemented\n", (int)xferp->cmd[1]);
1064
1065 /* Return data: */
1066 scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
1067 retlen, 1);
1068
1069 /*
1070 * data[0] is reserved, data[1..3] contain the maximum block
1071 * length limit, data[4..5] contain the minimum limit.
1072 */
1073
1074 {
1075 int max_limit = 32768;
1076 int min_limit = 128;
1077
1078 xferp->data_in[1] = (max_limit >> 16) & 255;
1079 xferp->data_in[2] = (max_limit >> 8) & 255;
1080 xferp->data_in[3] = max_limit & 255;
1081 xferp->data_in[4] = (min_limit >> 8) & 255;
1082 xferp->data_in[5] = min_limit & 255;
1083 }
1084
1085 diskimage__return_default_status_and_message(xferp);
1086 break;
1087
1088 case SCSICMD_REWIND:
1089 debug("REWIND");
1090
1091 /* TODO: bits 765 of buf[1] contains the LUN */
1092 if ((xferp->cmd[1] & 0xe0) != 0x00)
1093 fatal("WARNING: REWIND with cmd[1]=0x%02x not yet "
1094 "implemented\n", (int)xferp->cmd[1]);
1095
1096 /* Close and reopen. */
1097
1098 if (d->f != NULL)
1099 fclose(d->f);
1100
1101 d->f = fopen(d->fname, d->writable? "r+" : "r");
1102 if (d->f == NULL) {
1103 fprintf(stderr, "[ diskimage: could not (re)open "
1104 "'%s' ]\n", d->fname);
1105 /* TODO: return error */
1106 }
1107
1108 d->tape_offset = 0;
1109 d->tape_filenr = 0;
1110 d->filemark = 0;
1111
1112 diskimage__return_default_status_and_message(xferp);
1113 break;
1114
1115 case SCSICMD_SPACE:
1116 debug("SPACE");
1117
1118 /* TODO: bits 765 of buf[1] contains the LUN */
1119 if ((xferp->cmd[1] & 0xe0) != 0x00)
1120 fatal("WARNING: SPACE with cmd[1]=0x%02x not yet "
1121 "implemented\n", (int)xferp->cmd[1]);
1122
1123 /*
1124 * Bits 2..0 of buf[1] contain the 'code' which describes how
1125 * we should space, and buf[2..4] contain the number of
1126 * operations.
1127 */
1128 debug("[ SPACE: buf[] = %02x %02x %02x %02x %02x %02x ]\n",
1129 xferp->cmd[0],
1130 xferp->cmd[1],
1131 xferp->cmd[2],
1132 xferp->cmd[3],
1133 xferp->cmd[4],
1134 xferp->cmd[5]);
1135
1136 switch (xferp->cmd[1] & 7) {
1137 case 1: /* Seek to a different file nr: */
1138 {
1139 int diff = (xferp->cmd[2] << 16) +
1140 (xferp->cmd[3] << 8) + xferp->cmd[4];
1141
1142 /* Negative seek offset: */
1143 if (diff & (1 << 23))
1144 diff = - (16777216 - diff);
1145
1146 d->tape_filenr += diff;
1147 }
1148
1149 /* At end of file, switch to the next tape file: */
1150 if (d->filemark) {
1151 d->tape_filenr ++;
1152 d->filemark = 0;
1153 }
1154
1155 debug("{ switching to tape file %i }", d->tape_filenr);
1156 diskimage__switch_tape(d);
1157 d->filemark = 0;
1158 break;
1159 default:
1160 fatal("[ diskimage.c: unimplemented SPACE type %i ]\n",
1161 xferp->cmd[1] & 7);
1162 }
1163
1164 diskimage__return_default_status_and_message(xferp);
1165 break;
1166
1167 case SCSICDROM_READ_SUBCHANNEL:
1168 /*
1169 * According to
1170 * http://mail-index.netbsd.org/port-i386/1997/03/03/0010.html:
1171 *
1172 * "The READ_CD_CAPACITY, READ_SUBCHANNEL, and MODE_SELECT
1173 * commands have the same opcode in SCSI or ATAPI, but don't
1174 * have the same command structure"...
1175 *
1176 * TODO: This still doesn't work. Hm.
1177 */
1178 retlen = 48;
1179
1180 debug("CDROM_READ_SUBCHANNEL/READ_CD_CAPACITY, cmd[1]=0x%02x",
1181 xferp->cmd[1]);
1182
1183 /* Return data: */
1184 scsi_transfer_allocbuf(&xferp->data_in_len,
1185 &xferp->data_in, retlen, 1);
1186
1187 diskimage_recalc_size(d);
1188
1189 size = d->total_size / d->logical_block_size;
1190 if (d->total_size & (d->logical_block_size-1))
1191 size ++;
1192
1193 xferp->data_in[0] = (size >> 24) & 255;
1194 xferp->data_in[1] = (size >> 16) & 255;
1195 xferp->data_in[2] = (size >> 8) & 255;
1196 xferp->data_in[3] = size & 255;
1197
1198 xferp->data_in[4] = (d->logical_block_size >> 24) & 255;
1199 xferp->data_in[5] = (d->logical_block_size >> 16) & 255;
1200 xferp->data_in[6] = (d->logical_block_size >> 8) & 255;
1201 xferp->data_in[7] = d->logical_block_size & 255;
1202
1203 diskimage__return_default_status_and_message(xferp);
1204 break;
1205
1206 case SCSICDROM_READ_TOC:
1207 debug("(CDROM_READ_TOC: ");
1208 debug("lun=%i msf=%i ",
1209 xferp->cmd[1] >> 5, (xferp->cmd[1] >> 1) & 1);
1210 debug("starting_track=%i ", xferp->cmd[6]);
1211 retlen = xferp->cmd[7] * 256 + xferp->cmd[8];
1212 debug("allocation_len=%i)\n", retlen);
1213
1214 /* Return data: */
1215 scsi_transfer_allocbuf(&xferp->data_in_len,
1216 &xferp->data_in, retlen, 1);
1217
1218 /* TODO */
1219
1220 diskimage__return_default_status_and_message(xferp);
1221 break;
1222
1223 case SCSICMD_MODE_SELECT:
1224 debug("[ SCSI MODE_SELECT: ");
1225
1226 /*
1227 * TODO:
1228 *
1229 * This is super-hardcoded for NetBSD's usage of mode_select
1230 * to set the size of CDROM sectors to 2048.
1231 */
1232
1233 if (xferp->data_out_offset == 0) {
1234 xferp->data_out_len = 12; /* TODO */
1235 debug("data_out == NULL, wanting %i bytes ]\n",
1236 (int)xferp->data_out_len);
1237 return 2;
1238 }
1239
1240 debug("data_out!=NULL (OK), ");
1241
1242 /* TODO: Care about cmd? */
1243
1244 /* Set sector size to 2048: */
1245 /* 00 05 00 08 00 03 ca 40 00 00 08 00 */
1246 if (xferp->data_out[0] == 0x00 &&
1247 xferp->data_out[1] == 0x05 &&
1248 xferp->data_out[2] == 0x00 &&
1249 xferp->data_out[3] == 0x08) {
1250 d->logical_block_size =
1251 (xferp->data_out[9] << 16) +
1252 (xferp->data_out[10] << 8) +
1253 xferp->data_out[11];
1254 debug("[ setting logical_block_size to %i ]\n",
1255 d->logical_block_size);
1256 } else {
1257 int i;
1258 fatal("[ unknown MODE_SELECT: cmd =");
1259 for (i=0; i<xferp->cmd_len; i++)
1260 fatal(" %02x", xferp->cmd[i]);
1261 fatal(", data_out =");
1262 for (i=0; i<xferp->data_out_len; i++)
1263 fatal(" %02x", xferp->data_out[i]);
1264 fatal(" ]");
1265 }
1266
1267 debug(" ]\n");
1268 diskimage__return_default_status_and_message(xferp);
1269 break;
1270
1271 case 0x1e:
1272 debug("[ SCSI 0x%02x: TODO ]\n", xferp->cmd[0]);
1273
1274 /* TODO */
1275
1276 diskimage__return_default_status_and_message(xferp);
1277 break;
1278
1279 case 0xbd:
1280 fatal("[ SCSI 0x%02x (len %i), TODO: ", xferp->cmd[0],
1281 xferp->cmd_len);
1282 for (i=0; i<xferp->cmd_len; i++)
1283 fatal(" %02x", xferp->cmd[i]);
1284 fatal(" ]\n");
1285
1286 /*
1287 * Used by Windows NT?
1288 *
1289 * Not documented in http://www.danbbs.dk/~dino/
1290 * SCSI/SCSI2-D.html.
1291 * Google gave the answer "MECHANISM_STATUS" for ATAPI. Hm.
1292 */
1293
1294 if (xferp->cmd_len < 12) {
1295 fatal("WEIRD LEN?\n");
1296 retlen = 8;
1297 } else {
1298 retlen = xferp->cmd[8] * 256 + xferp->cmd[9];
1299 }
1300
1301 /* Return data: */
1302 scsi_transfer_allocbuf(&xferp->data_in_len,
1303 &xferp->data_in, retlen, 1);
1304
1305 diskimage__return_default_status_and_message(xferp);
1306 break;
1307
1308 default:
1309 fatal("[ UNIMPLEMENTED SCSI command 0x%02x, disk id=%i ]\n",
1310 xferp->cmd[0], id);
1311 exit(1);
1312 }
1313 debug(" ]\n");
1314
1315 return 1;
1316 }
1317
1318
1319 /*
1320 * diskimage_access():
1321 *
1322 * Read from or write to a disk image on a machine.
1323 *
1324 * Returns 1 if the access completed successfully, 0 otherwise.
1325 */
1326 int diskimage_access(struct machine *machine, int id, int type, int writeflag,
1327 off_t offset, unsigned char *buf, size_t len)
1328 {
1329 struct diskimage *d = machine->first_diskimage;
1330
1331 while (d != NULL) {
1332 if (d->type == type && d->id == id)
1333 break;
1334 d = d->next;
1335 }
1336
1337 if (d == NULL) {
1338 fatal("[ diskimage_access(): ERROR: trying to access a "
1339 "non-existant %s disk image (id %i)\n",
1340 diskimage_types[type], id);
1341 return 0;
1342 }
1343
1344 return diskimage__internal_access(d, writeflag, offset, buf, len);
1345 }
1346
1347
1348 /*
1349 * diskimage_add():
1350 *
1351 * Add a disk image. fname is the filename of the disk image.
1352 * The filename may be prefixed with one or more modifiers, followed
1353 * by a colon.
1354 *
1355 * b specifies that this is a bootable device
1356 * c CD-ROM (instead of a normal DISK)
1357 * d DISK (this is the default)
1358 * f FLOPPY (instead of SCSI)
1359 * gH;S; set geometry (H=heads, S=sectors per track, cylinders are
1360 * automatically calculated). (This is ignored for floppies.)
1361 * i IDE (instead of SCSI)
1362 * r read-only (don't allow changes to the file)
1363 * s SCSI (this is the default)
1364 * t tape
1365 * 0-7 force a specific SCSI ID number
1366 *
1367 * machine is assumed to be non-NULL.
1368 * Returns an integer >= 0 identifying the disk image.
1369 */
1370 int diskimage_add(struct machine *machine, char *fname)
1371 {
1372 struct diskimage *d, *d2;
1373 int id = 0, override_heads=0, override_spt=0;
1374 int64_t bytespercyl;
1375 char *cp;
1376 int prefix_b=0, prefix_c=0, prefix_d=0, prefix_f=0, prefix_g=0;
1377 int prefix_i=0, prefix_r=0, prefix_s=0, prefix_t=0, prefix_id = -1;
1378
1379 if (fname == NULL) {
1380 fprintf(stderr, "diskimage_add(): NULL ptr\n");
1381 return 0;
1382 }
1383
1384 /* Get prefix from fname: */
1385 cp = strchr(fname, ':');
1386 if (cp != NULL) {
1387 while (fname <= cp) {
1388 char c = *fname++;
1389 switch (c) {
1390 case '0':
1391 case '1':
1392 case '2':
1393 case '3':
1394 case '4':
1395 case '5':
1396 case '6':
1397 case '7':
1398 prefix_id = c - '0';
1399 break;
1400 case 'b':
1401 prefix_b = 1;
1402 break;
1403 case 'c':
1404 prefix_c = 1;
1405 break;
1406 case 'd':
1407 prefix_d = 1;
1408 break;
1409 case 'f':
1410 prefix_f = 1;
1411 break;
1412 case 'g':
1413 prefix_g = 1;
1414 override_heads = atoi(fname);
1415 while (*fname != '\0' && *fname != ';')
1416 fname ++;
1417 if (*fname == ';')
1418 fname ++;
1419 override_spt = atoi(fname);
1420 while (*fname != '\0' && *fname != ';' &&
1421 *fname != ':')
1422 fname ++;
1423 if (*fname == ';')
1424 fname ++;
1425 if (override_heads < 1 ||
1426 override_spt < 1) {
1427 fatal("Bad geometry: heads=%i "
1428 "spt=%i\n", override_heads,
1429 override_spt);
1430 exit(1);
1431 }
1432 break;
1433 case 'i':
1434 prefix_i = 1;
1435 break;
1436 case 'r':
1437 prefix_r = 1;
1438 break;
1439 case 's':
1440 prefix_s = 1;
1441 break;
1442 case 't':
1443 prefix_t = 1;
1444 break;
1445 case ':':
1446 break;
1447 default:
1448 fprintf(stderr, "diskimage_add(): invalid "
1449 "prefix char '%c'\n", c);
1450 exit(1);
1451 }
1452 }
1453 }
1454
1455 /* Allocate a new diskimage struct: */
1456 d = malloc(sizeof(struct diskimage));
1457 if (d == NULL) {
1458 fprintf(stderr, "out of memory in diskimage_add()\n");
1459 exit(1);
1460 }
1461 memset(d, 0, sizeof(struct diskimage));
1462
1463 d2 = machine->first_diskimage;
1464 if (d2 == NULL) {
1465 machine->first_diskimage = d;
1466 } else {
1467 while (d2->next != NULL)
1468 d2 = d2->next;
1469 d2->next = d;
1470 }
1471
1472 d->type = DISKIMAGE_SCSI;
1473
1474 /* Special cases: some machines usually have FLOPPY/IDE, not SCSI: */
1475 if (machine->arch == ARCH_X86 ||
1476 machine->machine_type == MACHINE_COBALT ||
1477 machine->machine_type == MACHINE_HPCMIPS ||
1478 machine->machine_type == MACHINE_PS2)
1479 d->type = DISKIMAGE_IDE;
1480
1481 if (prefix_i + prefix_f + prefix_s > 1) {
1482 fprintf(stderr, "Invalid disk image prefix(es). You can"
1483 "only use one of i, f, and s\nfor each disk image.\n");
1484 exit(1);
1485 }
1486
1487 if (prefix_i)
1488 d->type = DISKIMAGE_IDE;
1489 if (prefix_f)
1490 d->type = DISKIMAGE_FLOPPY;
1491 if (prefix_s)
1492 d->type = DISKIMAGE_SCSI;
1493
1494 d->fname = strdup(fname);
1495 if (d->fname == NULL) {
1496 fprintf(stderr, "out of memory\n");
1497 exit(1);
1498 }
1499
1500 d->logical_block_size = 512;
1501
1502 /*
1503 * Is this a tape, CD-ROM or a normal disk?
1504 *
1505 * An intelligent guess, if no prefixes are used, would be that
1506 * filenames ending with .iso are CD-ROM images.
1507 */
1508 if (prefix_t) {
1509 d->is_a_tape = 1;
1510 } else {
1511 if (prefix_c ||
1512 ((strlen(d->fname) > 4 &&
1513 strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0)
1514 && !prefix_d)
1515 ) {
1516 d->is_a_cdrom = 1;
1517
1518 /*
1519 * This is tricky. Should I use 512 or 2048 here?
1520 * NetBSD/pmax 1.6.2 and Ultrix likes 512 bytes
1521 * per sector, but NetBSD 2.0_BETA suddenly ignores
1522 * this value and uses 2048 instead.
1523 *
1524 * OpenBSD/arc doesn't like 2048, it requires 512
1525 * to work correctly.
1526 *
1527 * TODO
1528 */
1529
1530 #if 0
1531 if (machine->machine_type == MACHINE_DEC)
1532 d->logical_block_size = 512;
1533 else
1534 d->logical_block_size = 2048;
1535 #endif
1536 d->logical_block_size = 512;
1537 }
1538 }
1539
1540 diskimage_recalc_size(d);
1541
1542 if ((d->total_size == 720*1024 || d->total_size == 1474560
1543 || d->total_size == 2949120 || d->total_size == 1228800)
1544 && !prefix_i && !prefix_s)
1545 d->type = DISKIMAGE_FLOPPY;
1546
1547 switch (d->type) {
1548 case DISKIMAGE_FLOPPY:
1549 if (d->total_size < 737280) {
1550 fatal("\nTODO: small (non-80-cylinder) floppies?\n\n");
1551 exit(1);
1552 }
1553 d->cylinders = 80;
1554 d->heads = 2;
1555 d->sectors_per_track = d->total_size / (d->cylinders *
1556 d->heads * 512);
1557 break;
1558 default:/* Non-floppies: */
1559 d->heads = 16;
1560 d->sectors_per_track = 63;
1561 if (prefix_g) {
1562 d->chs_override = 1;
1563 d->heads = override_heads;
1564 d->sectors_per_track = override_spt;
1565 }
1566 bytespercyl = d->heads * d->sectors_per_track * 512;
1567 d->cylinders = d->total_size / bytespercyl;
1568 if (d->cylinders * bytespercyl < d->total_size)
1569 d->cylinders ++;
1570 }
1571
1572 d->rpms = 3600;
1573
1574 if (prefix_b)
1575 d->is_boot_device = 1;
1576
1577 d->writable = access(fname, W_OK) == 0? 1 : 0;
1578
1579 if (d->is_a_cdrom || prefix_r)
1580 d->writable = 0;
1581
1582 d->f = fopen(fname, d->writable? "r+" : "r");
1583 if (d->f == NULL) {
1584 perror(fname);
1585 exit(1);
1586 }
1587
1588 /* Calculate which ID to use: */
1589 if (prefix_id == -1) {
1590 int free = 0, collision = 1;
1591
1592 while (collision) {
1593 collision = 0;
1594 d2 = machine->first_diskimage;
1595 while (d2 != NULL) {
1596 /* (don't compare against ourselves :) */
1597 if (d2 == d) {
1598 d2 = d2->next;
1599 continue;
1600 }
1601 if (d2->id == free && d2->type == d->type) {
1602 collision = 1;
1603 break;
1604 }
1605 d2 = d2->next;
1606 }
1607 if (!collision)
1608 id = free;
1609 else
1610 free ++;
1611 }
1612 } else {
1613 id = prefix_id;
1614 d2 = machine->first_diskimage;
1615 while (d2 != NULL) {
1616 /* (don't compare against ourselves :) */
1617 if (d2 == d) {
1618 d2 = d2->next;
1619 continue;
1620 }
1621 if (d2->id == id && d2->type == d->type) {
1622 fprintf(stderr, "disk image id %i "
1623 "already in use\n", id);
1624 exit(1);
1625 }
1626 d2 = d2->next;
1627 }
1628 }
1629
1630 d->id = id;
1631
1632 return id;
1633 }
1634
1635
1636 /*
1637 * diskimage_bootdev():
1638 *
1639 * Returns the disk id of the device which we're booting from. If typep is
1640 * non-NULL, the type is returned as well.
1641 *
1642 * If no disk was used as boot device, then -1 is returned. (In practice,
1643 * this is used to fake network (tftp) boot.)
1644 */
1645 int diskimage_bootdev(struct machine *machine, int *typep)
1646 {
1647 struct diskimage *d;
1648
1649 d = machine->first_diskimage;
1650 while (d != NULL) {
1651 if (d->is_boot_device) {
1652 if (typep != NULL)
1653 *typep = d->type;
1654 return d->id;
1655 }
1656 d = d->next;
1657 }
1658
1659 d = machine->first_diskimage;
1660 if (d != NULL) {
1661 if (typep != NULL)
1662 *typep = d->type;
1663 return d->id;
1664 }
1665
1666 return -1;
1667 }
1668
1669
1670 /*
1671 * diskimage_is_a_cdrom():
1672 *
1673 * Returns 1 if a disk image is a CDROM, 0 otherwise.
1674 */
1675 int diskimage_is_a_cdrom(struct machine *machine, int id, int type)
1676 {
1677 struct diskimage *d = machine->first_diskimage;
1678
1679 while (d != NULL) {
1680 if (d->type == type && d->id == id)
1681 return d->is_a_cdrom;
1682 d = d->next;
1683 }
1684 return 0;
1685 }
1686
1687
1688 /*
1689 * diskimage_is_a_tape():
1690 *
1691 * Returns 1 if a disk image is a tape, 0 otherwise.
1692 *
1693 * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation
1694 * boot strings.)
1695 */
1696 int diskimage_is_a_tape(struct machine *machine, int id, int type)
1697 {
1698 struct diskimage *d = machine->first_diskimage;
1699
1700 while (d != NULL) {
1701 if (d->type == type && d->id == id)
1702 return d->is_a_tape;
1703 d = d->next;
1704 }
1705 return 0;
1706 }
1707
1708
1709 /*
1710 * diskimage_dump_info():
1711 *
1712 * Debug dump of all diskimages that are loaded for a specific machine.
1713 */
1714 void diskimage_dump_info(struct machine *machine)
1715 {
1716 int iadd=4;
1717 struct diskimage *d = machine->first_diskimage;
1718
1719 while (d != NULL) {
1720 debug("diskimage: %s\n", d->fname);
1721 debug_indentation(iadd);
1722
1723 switch (d->type) {
1724 case DISKIMAGE_SCSI:
1725 debug("SCSI");
1726 break;
1727 case DISKIMAGE_IDE:
1728 debug("IDE");
1729 break;
1730 case DISKIMAGE_FLOPPY:
1731 debug("FLOPPY");
1732 break;
1733 default:
1734 debug("UNKNOWN type %i", d->type);
1735 }
1736
1737 debug(" %s", d->is_a_tape? "TAPE" :
1738 (d->is_a_cdrom? "CD-ROM" : "DISK"));
1739 debug(" id %i, ", d->id);
1740 debug("%s, ", d->writable? "read/write" : "read-only");
1741
1742 if (d->type == DISKIMAGE_FLOPPY)
1743 debug("%lli KB", (long long) (d->total_size / 1024));
1744 else
1745 debug("%lli MB", (long long) (d->total_size / 1048576));
1746
1747 if (d->type == DISKIMAGE_FLOPPY || d->chs_override)
1748 debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads,
1749 d->sectors_per_track);
1750 else
1751 debug(" (%lli sectors)", (long long)
1752 (d->total_size / 512));
1753
1754 if (d->is_boot_device)
1755 debug(" (BOOT)");
1756 debug("\n");
1757
1758 debug_indentation(-iadd);
1759
1760 d = d->next;
1761 }
1762 }
1763

  ViewVC Help
Powered by ViewVC 1.1.26