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

Contents of /trunk/src/diskimage.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 45788 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26