/[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

Annotation of /trunk/src/diskimage.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide 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 dpavlin 2 /*
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 dpavlin 4 * $Id: diskimage.c,v 1.84 2005/04/17 00:15:24 debug Exp $
29 dpavlin 2 *
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 dpavlin 4 if ( /* d->type == DISKIMAGE_SCSI && */ d->id == scsi_id)
220 dpavlin 2 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 dpavlin 4 if ( /* d->type == DISKIMAGE_SCSI && */ d->id == scsi_id)
274 dpavlin 2 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 dpavlin 4 if ( /* d->type == DISKIMAGE_SCSI && */ d->id == scsi_id)
468 dpavlin 2 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 dpavlin 4 /*
1304     * TODO: How about mixing SCSI, IDE, and FLOPPY in one
1305     * emulated machine?
1306     */
1307    
1308 dpavlin 2 while (d != NULL) {
1309 dpavlin 4 if ( /* d->type == DISKIMAGE_SCSI && */ d->id == scsi_id)
1310 dpavlin 2 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 dpavlin 4 * d DISK (this is the default)
1334     * f FLOPPY (instead of SCSI)
1335 dpavlin 2 * i IDE (instead of SCSI)
1336     * r read-only (don't allow changes to the file)
1337 dpavlin 4 * s SCSI (this is the default)
1338     * t tape
1339 dpavlin 2 * 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 dpavlin 4 int prefix_f = 0;
1353 dpavlin 2 int prefix_i = 0;
1354 dpavlin 4 int prefix_r = 0;
1355     int prefix_s = 0;
1356 dpavlin 2 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 dpavlin 4 case 'f':
1390     prefix_f = 1;
1391     break;
1392 dpavlin 2 case 'i':
1393     prefix_i = 1;
1394     break;
1395 dpavlin 4 case 'r':
1396     prefix_r = 1;
1397     break;
1398     case 's':
1399     prefix_s = 1;
1400     break;
1401 dpavlin 2 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 dpavlin 4 /* 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 dpavlin 2 if (prefix_i)
1481     d->type = DISKIMAGE_IDE;
1482 dpavlin 4 if (prefix_f)
1483     d->type = DISKIMAGE_FLOPPY;
1484     if (prefix_s)
1485     d->type = DISKIMAGE_SCSI;
1486 dpavlin 2
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 dpavlin 4 if (d->total_size == 1474560 && !prefix_i && !prefix_s)
1536     d->type = DISKIMAGE_FLOPPY;
1537    
1538 dpavlin 2 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 dpavlin 4 case DISKIMAGE_FLOPPY:
1643     debug("FLOPPY");
1644     break;
1645 dpavlin 2 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 dpavlin 4 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 dpavlin 2 (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