/[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 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 41822 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26