/[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 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 46422 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26