/[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 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 47583 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26