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

Annotation of /trunk/src/diskimage.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 46014 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


1 dpavlin 2 /*
2     * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 20 * $Id: diskimage.c,v 1.102 2005/11/21 09:17:25 debug Exp $
29 dpavlin 2 *
30     * Disk image support.
31     *
32     * TODO: There's probably a bug in the tape support:
33     * Let's say there are 10240 bytes left in a file, and 10240
34     * bytes are read. Then feof() is not true yet (?), so the next
35     * read will also return 10240 bytes (but all zeroes), and then after
36     * that return feof (which results in a filemark). This is probably
37     * trivial to fix, but I don't feel like it right now.
38     *
39 dpavlin 6 * TODO: diskimage_remove()? This would be useful for floppies in PC-style
40     * machines, where disks may need to be swapped during boot etc.
41 dpavlin 2 */
42    
43     #include <stdio.h>
44     #include <stdlib.h>
45     #include <string.h>
46     #include <unistd.h>
47     #include <sys/types.h>
48     #include <sys/stat.h>
49    
50     #include "cpu.h"
51     #include "diskimage.h"
52     #include "machine.h"
53     #include "misc.h"
54    
55    
56 dpavlin 20 /* #define debug fatal */
57    
58 dpavlin 2 extern int single_step;
59    
60 dpavlin 6 static char *diskimage_types[] = DISKIMAGE_TYPES;
61 dpavlin 2
62     static struct scsi_transfer *first_free_scsi_transfer_alloc = NULL;
63    
64    
65     /**************************************************************************/
66    
67     /*
68     * my_fseek():
69     *
70     * A helper function, like fseek() but takes off_t. If the system has
71     * fseeko, then that is used. Otherwise I try to fake off_t offsets here.
72     *
73     * The correct position is reached by seeking 2 billion bytes at a time
74     * (or less). Note: This method is only used for SEEK_SET, for SEEK_CUR
75     * and SEEK_END, normal fseek() is used!
76     *
77     * TODO: It seemed to work on Linux/i386, but not on Solaris/sparc (?).
78     * Anyway, most modern systems have fseeko(), so it shouldn't be a problem.
79     */
80     static int my_fseek(FILE *f, off_t offset, int whence)
81     {
82     #ifdef HACK_FSEEKO
83     if (whence == SEEK_SET) {
84     int res = 0;
85     off_t curoff = 0;
86     off_t cur_step;
87    
88     fseek(f, 0, SEEK_SET);
89     while (curoff < offset) {
90     /* How far to seek? */
91     cur_step = offset - curoff;
92     if (cur_step > 2000000000)
93     cur_step = 2000000000;
94     res = fseek(f, cur_step, SEEK_CUR);
95     if (res)
96     return res;
97     curoff += cur_step;
98     }
99     return 0;
100     } else
101     return fseek(f, offset, whence);
102     #else
103     return fseeko(f, offset, whence);
104     #endif
105     }
106    
107    
108     /**************************************************************************/
109    
110    
111     /*
112     * scsi_transfer_alloc():
113     *
114     * Allocates memory for a new scsi_transfer struct, and fills it with
115     * sane data (NULL pointers).
116     * The return value is a pointer to the new struct. If allocation
117     * failed, the program exits.
118     */
119     struct scsi_transfer *scsi_transfer_alloc(void)
120     {
121     struct scsi_transfer *p;
122    
123     if (first_free_scsi_transfer_alloc != NULL) {
124     p = first_free_scsi_transfer_alloc;
125     first_free_scsi_transfer_alloc = p->next_free;
126     } else {
127     p = malloc(sizeof(struct scsi_transfer));
128     if (p == NULL) {
129     fprintf(stderr, "scsi_transfer_alloc(): out "
130     "of memory\n");
131     exit(1);
132     }
133     }
134    
135     memset(p, 0, sizeof(struct scsi_transfer));
136    
137     return p;
138     }
139    
140    
141     /*
142     * scsi_transfer_free():
143     *
144     * Frees the space used by a scsi_transfer struct. All buffers refered
145     * to by the scsi_transfer struct are freed.
146     */
147     void scsi_transfer_free(struct scsi_transfer *p)
148     {
149     if (p == NULL) {
150     fprintf(stderr, "scsi_transfer_free(): p == NULL\n");
151     exit(1);
152     }
153    
154     if (p->msg_out != NULL)
155     free(p->msg_out);
156     if (p->cmd != NULL)
157     free(p->cmd);
158     if (p->data_out != NULL)
159     free(p->data_out);
160    
161     if (p->data_in != NULL)
162     free(p->data_in);
163     if (p->msg_in != NULL)
164     free(p->msg_in);
165     if (p->status != NULL)
166     free(p->status);
167    
168     p->next_free = first_free_scsi_transfer_alloc;
169     first_free_scsi_transfer_alloc = p;
170     }
171    
172    
173     /*
174     * scsi_transfer_allocbuf():
175     *
176     * Helper function, used by diskimage_scsicommand(), and SCSI controller
177     * devices. Example of usage:
178     *
179     * scsi_transfer_allocbuf(&xferp->msg_in_len, &xferp->msg_in, 1);
180     */
181     void scsi_transfer_allocbuf(size_t *lenp, unsigned char **pp, size_t want_len,
182     int clearflag)
183     {
184     unsigned char *p = (*pp);
185    
186     if (p != NULL) {
187     printf("WARNING! scsi_transfer_allocbuf(): old pointer "
188     "was not NULL, freeing it now\n");
189     free(p);
190     }
191    
192     (*lenp) = want_len;
193     if ((p = malloc(want_len)) == NULL) {
194     fprintf(stderr, "scsi_transfer_allocbuf(): out of "
195     "memory trying to allocate %li bytes\n", (long)want_len);
196     exit(1);
197     }
198    
199     if (clearflag)
200     memset(p, 0, want_len);
201    
202     (*pp) = p;
203     }
204    
205    
206     /**************************************************************************/
207    
208    
209     /*
210     * diskimage_exist():
211     *
212 dpavlin 6 * Returns 1 if the specified disk id (for a specific type) exists, 0
213     * otherwise.
214 dpavlin 2 */
215 dpavlin 6 int diskimage_exist(struct machine *machine, int id, int type)
216 dpavlin 2 {
217     struct diskimage *d = machine->first_diskimage;
218    
219     while (d != NULL) {
220 dpavlin 6 if (d->type == type && d->id == id)
221 dpavlin 2 return 1;
222     d = d->next;
223     }
224     return 0;
225     }
226    
227    
228     /*
229     * diskimage_recalc_size():
230     *
231     * Recalculate a disk's size by stat()-ing it.
232     * d is assumed to be non-NULL.
233     */
234     static void diskimage_recalc_size(struct diskimage *d)
235     {
236     struct stat st;
237     int res;
238     off_t size = 0;
239    
240     res = stat(d->fname, &st);
241     if (res) {
242     fprintf(stderr, "[ diskimage_recalc_size(): could not stat "
243     "'%s' ]\n", d->fname);
244     return;
245     }
246    
247     size = st.st_size;
248    
249     /*
250     * TODO: CD-ROM devices, such as /dev/cd0c, how can one
251     * check how much data is on that cd-rom without reading it?
252     * For now, assume some large number, hopefully it will be
253     * enough to hold any cd-rom image.
254     */
255     if (d->is_a_cdrom && size == 0)
256     size = 762048000;
257    
258     d->total_size = size;
259     d->ncyls = d->total_size / 1048576;
260 dpavlin 6
261     /* TODO: There is a mismatch between d->ncyls and d->cylinders,
262     SCSI-based stuff usually doesn't care. TODO: Fix this. */
263 dpavlin 2 }
264    
265    
266     /*
267     * diskimage_getsize():
268     *
269 dpavlin 6 * Returns -1 if the specified disk id/type does not exists, otherwise
270 dpavlin 2 * the size of the disk image is returned.
271     */
272 dpavlin 6 int64_t diskimage_getsize(struct machine *machine, int id, int type)
273 dpavlin 2 {
274     struct diskimage *d = machine->first_diskimage;
275    
276     while (d != NULL) {
277 dpavlin 6 if (d->type == type && d->id == id)
278 dpavlin 2 return d->total_size;
279     d = d->next;
280     }
281     return -1;
282     }
283    
284    
285     /*
286 dpavlin 6 * 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 dpavlin 2 * 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 dpavlin 12 ssize_t lendone;
414 dpavlin 2 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 dpavlin 6 int diskimage_scsicommand(struct cpu *cpu, int id, int type,
480 dpavlin 2 struct scsi_transfer *xferp)
481     {
482 dpavlin 14 char namebuf[16];
483 dpavlin 20 int retlen, i, q;
484 dpavlin 2 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 dpavlin 6 if (d->type == type && d->id == id)
498 dpavlin 2 break;
499     d = d->next;
500     }
501     if (d == NULL) {
502 dpavlin 6 fprintf(stderr, "[ diskimage_scsicommand(): %s "
503     " id %i not connected? ]\n", diskimage_types[type], id);
504 dpavlin 2 }
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 dpavlin 6 id, xferp->cmd[0]);
519 dpavlin 2
520     #if 0
521     fatal("[ diskimage_scsicommand(id=%i) cmd=0x%02x len=%i:",
522 dpavlin 6 id, xferp->cmd[0], xferp->cmd_len);
523 dpavlin 2 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 dpavlin 6 fprintf(f, "id=%i cmd =", id);
538 dpavlin 2 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 dpavlin 14 /* These are padded with spaces: */
594 dpavlin 2
595 dpavlin 20 memcpy(xferp->data_in+8, "GXemul ", 8);
596 dpavlin 14 if (diskimage_getname(cpu->machine, id,
597     type, namebuf, sizeof(namebuf))) {
598     int 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 dpavlin 20 memcpy(xferp->data_in+32, "0 ", 4);
609 dpavlin 14
610 dpavlin 2 /*
611     * Some Ultrix kernels want specific responses from
612     * the drives.
613     */
614    
615     if (machine->machine_type == MACHINE_DEC) {
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 dpavlin 20 /* memcpy(xferp->data_in+16, "CD-ROM ", 16);*/
628 dpavlin 2
629     if (machine->machine_type == MACHINE_DEC) {
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 dpavlin 20 } else if (machine->machine_type == MACHINE_ARC) {
641 dpavlin 2 /* 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_DEC) {
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 dpavlin 20 case SCSICMD_MODE_SENSE10:
711 dpavlin 2 debug("MODE_SENSE");
712 dpavlin 20 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 dpavlin 2 xferp->cmd_len);
720 dpavlin 20 }
721 dpavlin 2
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 dpavlin 6 debug("[ MODE SENSE id %i, pagecode=%i ]\n", id, pagecode);
744 dpavlin 2
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 dpavlin 20 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 dpavlin 2
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 dpavlin 20 xferp->data_in[q + 0] = pagecode;
776     xferp->data_in[q + 1] = 10;
777 dpavlin 2 break;
778     case 3: /* format device page */
779 dpavlin 20 xferp->data_in[q + 0] = pagecode;
780     xferp->data_in[q + 1] = 22;
781 dpavlin 2
782     /* 10,11 = sectors per track */
783 dpavlin 20 xferp->data_in[q + 10] = 0;
784     xferp->data_in[q + 11] = d->sectors_per_track;
785 dpavlin 2
786     /* 12,13 = physical sector size */
787 dpavlin 20 xferp->data_in[q + 12] =
788 dpavlin 2 (d->logical_block_size >> 8) & 255;
789 dpavlin 20 xferp->data_in[q + 13] = d->logical_block_size & 255;
790 dpavlin 2 break;
791     case 4: /* rigid disk geometry page */
792 dpavlin 20 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 dpavlin 2
799 dpavlin 20 xferp->data_in[q + 20] = (d->rpms >> 8) & 255;
800     xferp->data_in[q + 21] = d->rpms & 255;
801 dpavlin 2 break;
802     case 5: /* flexible disk page */
803 dpavlin 20 xferp->data_in[q + 0] = pagecode;
804     xferp->data_in[q + 1] = 0x1e;
805 dpavlin 2
806     /* 2,3 = transfer rate */
807 dpavlin 20 xferp->data_in[q + 2] = ((5000) >> 8) & 255;
808     xferp->data_in[q + 3] = (5000) & 255;
809 dpavlin 2
810 dpavlin 20 xferp->data_in[q + 4] = d->heads;
811     xferp->data_in[q + 5] = d->sectors_per_track;
812 dpavlin 2
813     /* 6,7 = data bytes per sector */
814 dpavlin 20 xferp->data_in[q + 6] = (d->logical_block_size >> 8)
815 dpavlin 2 & 255;
816 dpavlin 20 xferp->data_in[q + 7] = d->logical_block_size & 255;
817 dpavlin 2
818 dpavlin 20 xferp->data_in[q + 8] = (d->ncyls >> 8) & 255;
819     xferp->data_in[q + 9] = d->ncyls & 255;
820 dpavlin 2
821 dpavlin 20 xferp->data_in[q + 28] = (d->rpms >> 8) & 255;
822     xferp->data_in[q + 29] = d->rpms & 255;
823 dpavlin 2 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 dpavlin 6 ", ofs=%lli ]\n", id, d->tape_filenr,
869 dpavlin 2 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 = (xferp->cmd[2] << 24) + (xferp->cmd[3]
901     << 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 dpavlin 6 debug(" feof id=%i\n", id);
932 dpavlin 2 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 dpavlin 10 d->tape_offset = ftello(d->f);
941 dpavlin 2
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 = (xferp->cmd[2] << 24) + (xferp->cmd[3] << 16) +
979     (xferp->cmd[4] << 8) + xferp->cmd[5];
980     retlen = (xferp->cmd[7] << 8) + xferp->cmd[8];
981     }
982    
983     size = retlen * d->logical_block_size;
984     ofs *= d->logical_block_size;
985    
986     if (xferp->data_out_offset != size) {
987     debug(", data_out == NULL, wanting %i bytes, \n\n",
988     (int)size);
989     xferp->data_out_len = size;
990     return 2;
991     }
992    
993     debug(", data_out != NULL, OK :-)");
994    
995     debug("WRITE ofs=%i size=%i offset=%i\n", (int)ofs,
996     (int)size, (int)xferp->data_out_offset);
997    
998     diskimage__internal_access(d, 1, ofs,
999     xferp->data_out, size);
1000    
1001     /* TODO: how about return code? */
1002    
1003     /* Is this really necessary? */
1004     /* fsync(fileno(d->f)); */
1005    
1006     diskimage__return_default_status_and_message(xferp);
1007     break;
1008    
1009     case SCSICMD_SYNCHRONIZE_CACHE:
1010     debug("SYNCHRONIZE_CACHE");
1011    
1012     if (xferp->cmd_len != 10)
1013     debug(" (weird len=%i)", xferp->cmd_len);
1014    
1015     /* TODO: actualy care about cmd[] */
1016     fsync(fileno(d->f));
1017    
1018     diskimage__return_default_status_and_message(xferp);
1019     break;
1020    
1021     case SCSICMD_START_STOP_UNIT:
1022     debug("START_STOP_UNIT");
1023    
1024     if (xferp->cmd_len != 6)
1025     debug(" (weird len=%i)", xferp->cmd_len);
1026    
1027 dpavlin 12 for (i=0; i<xferp->cmd_len; i++)
1028 dpavlin 2 debug(" %02x", xferp->cmd[i]);
1029    
1030     /* TODO: actualy care about cmd[] */
1031    
1032     diskimage__return_default_status_and_message(xferp);
1033     break;
1034    
1035     case SCSICMD_REQUEST_SENSE:
1036     debug("REQUEST_SENSE");
1037    
1038     retlen = xferp->cmd[4];
1039    
1040     /* TODO: bits 765 of buf[1] contains the LUN */
1041     if (xferp->cmd[1] != 0x00)
1042     fatal("WARNING: REQUEST_SENSE with cmd[1]=0x%02x not"
1043     " yet implemented\n", (int)xferp->cmd[1]);
1044    
1045     if (retlen < 18) {
1046     fatal("WARNING: SCSI request sense len=%i, <18!\n",
1047     (int)retlen);
1048     retlen = 18;
1049     }
1050    
1051     /* Return data: */
1052     scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
1053     retlen, 1);
1054    
1055     xferp->data_in[0] = 0x80 + 0x70;/* 0x80 = valid,
1056     0x70 = "current errors" */
1057     xferp->data_in[2] = 0x00; /* SENSE KEY! */
1058    
1059     if (d->filemark) {
1060     xferp->data_in[2] = 0x80;
1061     }
1062     debug(": [2]=0x%02x ", xferp->data_in[2]);
1063    
1064     printf(" XXX(!) \n");
1065    
1066     /* TODO */
1067     xferp->data_in[7] = retlen - 7; /* additional sense length */
1068     /* TODO */
1069    
1070     diskimage__return_default_status_and_message(xferp);
1071     break;
1072    
1073     case SCSICMD_READ_BLOCK_LIMITS:
1074     debug("READ_BLOCK_LIMITS");
1075    
1076     retlen = 6;
1077    
1078     /* TODO: bits 765 of buf[1] contains the LUN */
1079     if (xferp->cmd[1] != 0x00)
1080     fatal("WARNING: READ_BLOCK_LIMITS with cmd[1]="
1081     "0x%02x not yet implemented\n", (int)xferp->cmd[1]);
1082    
1083     /* Return data: */
1084     scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
1085     retlen, 1);
1086    
1087     /*
1088     * data[0] is reserved, data[1..3] contain the maximum block
1089     * length limit, data[4..5] contain the minimum limit.
1090     */
1091    
1092     {
1093     int max_limit = 32768;
1094     int min_limit = 128;
1095    
1096     xferp->data_in[1] = (max_limit >> 16) & 255;
1097     xferp->data_in[2] = (max_limit >> 8) & 255;
1098     xferp->data_in[3] = max_limit & 255;
1099     xferp->data_in[4] = (min_limit >> 8) & 255;
1100     xferp->data_in[5] = min_limit & 255;
1101     }
1102    
1103     diskimage__return_default_status_and_message(xferp);
1104     break;
1105    
1106     case SCSICMD_REWIND:
1107     debug("REWIND");
1108    
1109     /* TODO: bits 765 of buf[1] contains the LUN */
1110     if ((xferp->cmd[1] & 0xe0) != 0x00)
1111     fatal("WARNING: REWIND with cmd[1]=0x%02x not yet "
1112     "implemented\n", (int)xferp->cmd[1]);
1113    
1114     /* Close and reopen. */
1115    
1116     if (d->f != NULL)
1117     fclose(d->f);
1118    
1119     d->f = fopen(d->fname, d->writable? "r+" : "r");
1120     if (d->f == NULL) {
1121     fprintf(stderr, "[ diskimage: could not (re)open "
1122     "'%s' ]\n", d->fname);
1123     /* TODO: return error */
1124     }
1125    
1126     d->tape_offset = 0;
1127     d->tape_filenr = 0;
1128     d->filemark = 0;
1129    
1130     diskimage__return_default_status_and_message(xferp);
1131     break;
1132    
1133     case SCSICMD_SPACE:
1134     debug("SPACE");
1135    
1136     /* TODO: bits 765 of buf[1] contains the LUN */
1137     if ((xferp->cmd[1] & 0xe0) != 0x00)
1138     fatal("WARNING: SPACE with cmd[1]=0x%02x not yet "
1139     "implemented\n", (int)xferp->cmd[1]);
1140    
1141     /*
1142     * Bits 2..0 of buf[1] contain the 'code' which describes how
1143     * we should space, and buf[2..4] contain the number of
1144     * operations.
1145     */
1146     debug("[ SPACE: buf[] = %02x %02x %02x %02x %02x %02x ]\n",
1147     xferp->cmd[0],
1148     xferp->cmd[1],
1149     xferp->cmd[2],
1150     xferp->cmd[3],
1151     xferp->cmd[4],
1152     xferp->cmd[5]);
1153    
1154     switch (xferp->cmd[1] & 7) {
1155     case 1: /* Seek to a different file nr: */
1156     {
1157     int diff = (xferp->cmd[2] << 16) +
1158     (xferp->cmd[3] << 8) + xferp->cmd[4];
1159    
1160     /* Negative seek offset: */
1161     if (diff & (1 << 23))
1162     diff = - (16777216 - diff);
1163    
1164     d->tape_filenr += diff;
1165     }
1166    
1167     /* At end of file, switch to the next tape file: */
1168     if (d->filemark) {
1169     d->tape_filenr ++;
1170     d->filemark = 0;
1171     }
1172    
1173     debug("{ switching to tape file %i }", d->tape_filenr);
1174     diskimage__switch_tape(d);
1175     d->filemark = 0;
1176     break;
1177     default:
1178     fatal("[ diskimage.c: unimplemented SPACE type %i ]\n",
1179     xferp->cmd[1] & 7);
1180     }
1181    
1182     diskimage__return_default_status_and_message(xferp);
1183     break;
1184    
1185     case SCSICDROM_READ_SUBCHANNEL:
1186     /*
1187     * According to
1188     * http://mail-index.netbsd.org/port-i386/1997/03/03/0010.html:
1189     *
1190     * "The READ_CD_CAPACITY, READ_SUBCHANNEL, and MODE_SELECT
1191     * commands have the same opcode in SCSI or ATAPI, but don't
1192     * have the same command structure"...
1193     *
1194     * TODO: This still doesn't work. Hm.
1195     */
1196     retlen = 48;
1197    
1198     debug("CDROM_READ_SUBCHANNEL/READ_CD_CAPACITY, cmd[1]=0x%02x",
1199     xferp->cmd[1]);
1200    
1201     /* Return data: */
1202     scsi_transfer_allocbuf(&xferp->data_in_len,
1203     &xferp->data_in, retlen, 1);
1204    
1205     diskimage_recalc_size(d);
1206    
1207     size = d->total_size / d->logical_block_size;
1208     if (d->total_size & (d->logical_block_size-1))
1209     size ++;
1210    
1211     xferp->data_in[0] = (size >> 24) & 255;
1212     xferp->data_in[1] = (size >> 16) & 255;
1213     xferp->data_in[2] = (size >> 8) & 255;
1214     xferp->data_in[3] = size & 255;
1215    
1216     xferp->data_in[4] = (d->logical_block_size >> 24) & 255;
1217     xferp->data_in[5] = (d->logical_block_size >> 16) & 255;
1218     xferp->data_in[6] = (d->logical_block_size >> 8) & 255;
1219     xferp->data_in[7] = d->logical_block_size & 255;
1220    
1221     diskimage__return_default_status_and_message(xferp);
1222     break;
1223    
1224     case SCSICDROM_READ_TOC:
1225     debug("(CDROM_READ_TOC: ");
1226     debug("lun=%i msf=%i ",
1227     xferp->cmd[1] >> 5, (xferp->cmd[1] >> 1) & 1);
1228     debug("starting_track=%i ", xferp->cmd[6]);
1229     retlen = xferp->cmd[7] * 256 + xferp->cmd[8];
1230     debug("allocation_len=%i)\n", retlen);
1231    
1232     /* Return data: */
1233     scsi_transfer_allocbuf(&xferp->data_in_len,
1234     &xferp->data_in, retlen, 1);
1235    
1236 dpavlin 20 xferp->data_in[0] = 0;
1237     xferp->data_in[1] = 10;
1238     xferp->data_in[2] = 0; /* First track. */
1239     xferp->data_in[3] = 0; /* Last track. */
1240 dpavlin 2
1241 dpavlin 20 /* Track 0 data: */
1242     xferp->data_in[4] = 0x00; /* Reserved. */
1243     xferp->data_in[5] = 0x04; /* ADR + CTRL:
1244     Data, not audio */
1245     xferp->data_in[6] = 0x00; /* Track nr */
1246     xferp->data_in[7] = 0x00; /* Reserved */
1247     /* 8..11 = absolute CDROM address */
1248    
1249 dpavlin 2 diskimage__return_default_status_and_message(xferp);
1250     break;
1251    
1252     case SCSICMD_MODE_SELECT:
1253     debug("[ SCSI MODE_SELECT: ");
1254    
1255     /*
1256     * TODO:
1257     *
1258     * This is super-hardcoded for NetBSD's usage of mode_select
1259     * to set the size of CDROM sectors to 2048.
1260     */
1261    
1262     if (xferp->data_out_offset == 0) {
1263     xferp->data_out_len = 12; /* TODO */
1264     debug("data_out == NULL, wanting %i bytes ]\n",
1265     (int)xferp->data_out_len);
1266     return 2;
1267     }
1268    
1269     debug("data_out!=NULL (OK), ");
1270    
1271     /* TODO: Care about cmd? */
1272    
1273     /* Set sector size to 2048: */
1274     /* 00 05 00 08 00 03 ca 40 00 00 08 00 */
1275     if (xferp->data_out[0] == 0x00 &&
1276     xferp->data_out[1] == 0x05 &&
1277     xferp->data_out[2] == 0x00 &&
1278     xferp->data_out[3] == 0x08) {
1279     d->logical_block_size =
1280     (xferp->data_out[9] << 16) +
1281     (xferp->data_out[10] << 8) +
1282     xferp->data_out[11];
1283     debug("[ setting logical_block_size to %i ]\n",
1284     d->logical_block_size);
1285     } else {
1286     int i;
1287     fatal("[ unknown MODE_SELECT: cmd =");
1288     for (i=0; i<xferp->cmd_len; i++)
1289     fatal(" %02x", xferp->cmd[i]);
1290     fatal(", data_out =");
1291     for (i=0; i<xferp->data_out_len; i++)
1292     fatal(" %02x", xferp->data_out[i]);
1293     fatal(" ]");
1294     }
1295    
1296     debug(" ]\n");
1297     diskimage__return_default_status_and_message(xferp);
1298     break;
1299    
1300 dpavlin 20 case SCSICMD_PREVENT_ALLOW_REMOVE:
1301     debug("[ SCSI 0x%02x Prevent/allow medium removal: "
1302     "TODO ]\n", xferp->cmd[0]);
1303 dpavlin 2
1304     diskimage__return_default_status_and_message(xferp);
1305     break;
1306    
1307     case 0xbd:
1308     fatal("[ SCSI 0x%02x (len %i), TODO: ", xferp->cmd[0],
1309     xferp->cmd_len);
1310     for (i=0; i<xferp->cmd_len; i++)
1311     fatal(" %02x", xferp->cmd[i]);
1312     fatal(" ]\n");
1313    
1314     /*
1315     * Used by Windows NT?
1316     *
1317     * Not documented in http://www.danbbs.dk/~dino/
1318     * SCSI/SCSI2-D.html.
1319     * Google gave the answer "MECHANISM_STATUS" for ATAPI. Hm.
1320     */
1321    
1322     if (xferp->cmd_len < 12) {
1323     fatal("WEIRD LEN?\n");
1324     retlen = 8;
1325     } else {
1326     retlen = xferp->cmd[8] * 256 + xferp->cmd[9];
1327     }
1328    
1329     /* Return data: */
1330     scsi_transfer_allocbuf(&xferp->data_in_len,
1331     &xferp->data_in, retlen, 1);
1332    
1333     diskimage__return_default_status_and_message(xferp);
1334 dpavlin 10
1335 dpavlin 2 break;
1336    
1337     default:
1338     fatal("[ UNIMPLEMENTED SCSI command 0x%02x, disk id=%i ]\n",
1339 dpavlin 6 xferp->cmd[0], id);
1340 dpavlin 2 exit(1);
1341     }
1342     debug(" ]\n");
1343    
1344     return 1;
1345     }
1346    
1347    
1348     /*
1349     * diskimage_access():
1350     *
1351     * Read from or write to a disk image on a machine.
1352     *
1353     * Returns 1 if the access completed successfully, 0 otherwise.
1354     */
1355 dpavlin 6 int diskimage_access(struct machine *machine, int id, int type, int writeflag,
1356 dpavlin 2 off_t offset, unsigned char *buf, size_t len)
1357     {
1358     struct diskimage *d = machine->first_diskimage;
1359    
1360     while (d != NULL) {
1361 dpavlin 6 if (d->type == type && d->id == id)
1362 dpavlin 2 break;
1363     d = d->next;
1364     }
1365    
1366     if (d == NULL) {
1367     fatal("[ diskimage_access(): ERROR: trying to access a "
1368 dpavlin 6 "non-existant %s disk image (id %i)\n",
1369     diskimage_types[type], id);
1370 dpavlin 2 return 0;
1371     }
1372    
1373     return diskimage__internal_access(d, writeflag, offset, buf, len);
1374     }
1375    
1376    
1377     /*
1378     * diskimage_add():
1379     *
1380     * Add a disk image. fname is the filename of the disk image.
1381     * The filename may be prefixed with one or more modifiers, followed
1382     * by a colon.
1383     *
1384 dpavlin 6 * b specifies that this is a bootable device
1385     * c CD-ROM (instead of a normal DISK)
1386 dpavlin 4 * d DISK (this is the default)
1387     * f FLOPPY (instead of SCSI)
1388 dpavlin 6 * gH;S; set geometry (H=heads, S=sectors per track, cylinders are
1389     * automatically calculated). (This is ignored for floppies.)
1390 dpavlin 2 * i IDE (instead of SCSI)
1391     * r read-only (don't allow changes to the file)
1392 dpavlin 4 * s SCSI (this is the default)
1393     * t tape
1394 dpavlin 2 * 0-7 force a specific SCSI ID number
1395     *
1396     * machine is assumed to be non-NULL.
1397     * Returns an integer >= 0 identifying the disk image.
1398     */
1399     int diskimage_add(struct machine *machine, char *fname)
1400     {
1401     struct diskimage *d, *d2;
1402 dpavlin 6 int id = 0, override_heads=0, override_spt=0;
1403     int64_t bytespercyl;
1404 dpavlin 2 char *cp;
1405 dpavlin 6 int prefix_b=0, prefix_c=0, prefix_d=0, prefix_f=0, prefix_g=0;
1406     int prefix_i=0, prefix_r=0, prefix_s=0, prefix_t=0, prefix_id = -1;
1407 dpavlin 2
1408     if (fname == NULL) {
1409     fprintf(stderr, "diskimage_add(): NULL ptr\n");
1410     return 0;
1411     }
1412    
1413     /* Get prefix from fname: */
1414     cp = strchr(fname, ':');
1415     if (cp != NULL) {
1416     while (fname <= cp) {
1417     char c = *fname++;
1418     switch (c) {
1419     case '0':
1420     case '1':
1421     case '2':
1422     case '3':
1423     case '4':
1424     case '5':
1425     case '6':
1426     case '7':
1427     prefix_id = c - '0';
1428     break;
1429     case 'b':
1430     prefix_b = 1;
1431     break;
1432     case 'c':
1433     prefix_c = 1;
1434     break;
1435     case 'd':
1436     prefix_d = 1;
1437     break;
1438 dpavlin 4 case 'f':
1439     prefix_f = 1;
1440     break;
1441 dpavlin 6 case 'g':
1442     prefix_g = 1;
1443     override_heads = atoi(fname);
1444     while (*fname != '\0' && *fname != ';')
1445     fname ++;
1446     if (*fname == ';')
1447     fname ++;
1448     override_spt = atoi(fname);
1449     while (*fname != '\0' && *fname != ';' &&
1450     *fname != ':')
1451     fname ++;
1452     if (*fname == ';')
1453     fname ++;
1454     if (override_heads < 1 ||
1455     override_spt < 1) {
1456     fatal("Bad geometry: heads=%i "
1457     "spt=%i\n", override_heads,
1458     override_spt);
1459     exit(1);
1460     }
1461     break;
1462 dpavlin 2 case 'i':
1463     prefix_i = 1;
1464     break;
1465 dpavlin 4 case 'r':
1466     prefix_r = 1;
1467     break;
1468     case 's':
1469     prefix_s = 1;
1470     break;
1471 dpavlin 2 case 't':
1472     prefix_t = 1;
1473     break;
1474     case ':':
1475     break;
1476     default:
1477     fprintf(stderr, "diskimage_add(): invalid "
1478     "prefix char '%c'\n", c);
1479     exit(1);
1480     }
1481     }
1482     }
1483    
1484     /* Allocate a new diskimage struct: */
1485     d = malloc(sizeof(struct diskimage));
1486     if (d == NULL) {
1487     fprintf(stderr, "out of memory in diskimage_add()\n");
1488     exit(1);
1489     }
1490     memset(d, 0, sizeof(struct diskimage));
1491    
1492     d2 = machine->first_diskimage;
1493     if (d2 == NULL) {
1494     machine->first_diskimage = d;
1495     } else {
1496     while (d2->next != NULL)
1497     d2 = d2->next;
1498     d2->next = d;
1499     }
1500    
1501     d->type = DISKIMAGE_SCSI;
1502    
1503 dpavlin 4 /* Special cases: some machines usually have FLOPPY/IDE, not SCSI: */
1504     if (machine->arch == ARCH_X86 ||
1505     machine->machine_type == MACHINE_COBALT ||
1506 dpavlin 10 machine->machine_type == MACHINE_EVBMIPS ||
1507 dpavlin 4 machine->machine_type == MACHINE_HPCMIPS ||
1508 dpavlin 20 machine->machine_type == MACHINE_BEBOX ||
1509     machine->machine_type == MACHINE_PREP ||
1510 dpavlin 14 machine->machine_type == MACHINE_CATS ||
1511     machine->machine_type == MACHINE_NETWINDER ||
1512 dpavlin 4 machine->machine_type == MACHINE_PS2)
1513     d->type = DISKIMAGE_IDE;
1514    
1515     if (prefix_i + prefix_f + prefix_s > 1) {
1516     fprintf(stderr, "Invalid disk image prefix(es). You can"
1517     "only use one of i, f, and s\nfor each disk image.\n");
1518     exit(1);
1519     }
1520    
1521 dpavlin 2 if (prefix_i)
1522     d->type = DISKIMAGE_IDE;
1523 dpavlin 4 if (prefix_f)
1524     d->type = DISKIMAGE_FLOPPY;
1525     if (prefix_s)
1526     d->type = DISKIMAGE_SCSI;
1527 dpavlin 2
1528     d->fname = strdup(fname);
1529     if (d->fname == NULL) {
1530     fprintf(stderr, "out of memory\n");
1531     exit(1);
1532     }
1533    
1534     d->logical_block_size = 512;
1535    
1536     /*
1537     * Is this a tape, CD-ROM or a normal disk?
1538     *
1539     * An intelligent guess, if no prefixes are used, would be that
1540 dpavlin 14 * filenames ending with .iso or .cdr are CD-ROM images.
1541 dpavlin 2 */
1542     if (prefix_t) {
1543     d->is_a_tape = 1;
1544     } else {
1545     if (prefix_c ||
1546     ((strlen(d->fname) > 4 &&
1547 dpavlin 14 (strcasecmp(d->fname + strlen(d->fname) - 4, ".cdr") == 0 ||
1548     strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0))
1549 dpavlin 2 && !prefix_d)
1550     ) {
1551     d->is_a_cdrom = 1;
1552    
1553     /*
1554     * This is tricky. Should I use 512 or 2048 here?
1555     * NetBSD/pmax 1.6.2 and Ultrix likes 512 bytes
1556     * per sector, but NetBSD 2.0_BETA suddenly ignores
1557     * this value and uses 2048 instead.
1558     *
1559     * OpenBSD/arc doesn't like 2048, it requires 512
1560     * to work correctly.
1561     *
1562     * TODO
1563     */
1564    
1565     #if 0
1566     if (machine->machine_type == MACHINE_DEC)
1567     d->logical_block_size = 512;
1568     else
1569     d->logical_block_size = 2048;
1570     #endif
1571     d->logical_block_size = 512;
1572     }
1573     }
1574    
1575     diskimage_recalc_size(d);
1576    
1577 dpavlin 6 if ((d->total_size == 720*1024 || d->total_size == 1474560
1578     || d->total_size == 2949120 || d->total_size == 1228800)
1579     && !prefix_i && !prefix_s)
1580 dpavlin 4 d->type = DISKIMAGE_FLOPPY;
1581    
1582 dpavlin 6 switch (d->type) {
1583     case DISKIMAGE_FLOPPY:
1584     if (d->total_size < 737280) {
1585     fatal("\nTODO: small (non-80-cylinder) floppies?\n\n");
1586     exit(1);
1587     }
1588     d->cylinders = 80;
1589     d->heads = 2;
1590     d->sectors_per_track = d->total_size / (d->cylinders *
1591     d->heads * 512);
1592     break;
1593     default:/* Non-floppies: */
1594     d->heads = 16;
1595     d->sectors_per_track = 63;
1596     if (prefix_g) {
1597     d->chs_override = 1;
1598     d->heads = override_heads;
1599     d->sectors_per_track = override_spt;
1600     }
1601     bytespercyl = d->heads * d->sectors_per_track * 512;
1602     d->cylinders = d->total_size / bytespercyl;
1603     if (d->cylinders * bytespercyl < d->total_size)
1604     d->cylinders ++;
1605     }
1606    
1607 dpavlin 2 d->rpms = 3600;
1608    
1609     if (prefix_b)
1610     d->is_boot_device = 1;
1611    
1612     d->writable = access(fname, W_OK) == 0? 1 : 0;
1613    
1614     if (d->is_a_cdrom || prefix_r)
1615     d->writable = 0;
1616    
1617     d->f = fopen(fname, d->writable? "r+" : "r");
1618     if (d->f == NULL) {
1619     perror(fname);
1620     exit(1);
1621     }
1622    
1623 dpavlin 6 /* Calculate which ID to use: */
1624     if (prefix_id == -1) {
1625     int free = 0, collision = 1;
1626    
1627     while (collision) {
1628     collision = 0;
1629     d2 = machine->first_diskimage;
1630     while (d2 != NULL) {
1631     /* (don't compare against ourselves :) */
1632     if (d2 == d) {
1633     d2 = d2->next;
1634     continue;
1635     }
1636     if (d2->id == free && d2->type == d->type) {
1637     collision = 1;
1638     break;
1639     }
1640     d2 = d2->next;
1641     }
1642     if (!collision)
1643     id = free;
1644     else
1645     free ++;
1646     }
1647     } else {
1648     id = prefix_id;
1649     d2 = machine->first_diskimage;
1650     while (d2 != NULL) {
1651     /* (don't compare against ourselves :) */
1652     if (d2 == d) {
1653     d2 = d2->next;
1654     continue;
1655     }
1656     if (d2->id == id && d2->type == d->type) {
1657     fprintf(stderr, "disk image id %i "
1658     "already in use\n", id);
1659     exit(1);
1660     }
1661     d2 = d2->next;
1662     }
1663     }
1664    
1665     d->id = id;
1666    
1667 dpavlin 2 return id;
1668     }
1669    
1670    
1671     /*
1672     * diskimage_bootdev():
1673     *
1674 dpavlin 6 * Returns the disk id of the device which we're booting from. If typep is
1675     * non-NULL, the type is returned as well.
1676 dpavlin 2 *
1677     * If no disk was used as boot device, then -1 is returned. (In practice,
1678     * this is used to fake network (tftp) boot.)
1679     */
1680 dpavlin 6 int diskimage_bootdev(struct machine *machine, int *typep)
1681 dpavlin 2 {
1682 dpavlin 6 struct diskimage *d;
1683    
1684     d = machine->first_diskimage;
1685 dpavlin 2 while (d != NULL) {
1686 dpavlin 6 if (d->is_boot_device) {
1687     if (typep != NULL)
1688     *typep = d->type;
1689 dpavlin 2 return d->id;
1690 dpavlin 6 }
1691 dpavlin 2 d = d->next;
1692     }
1693    
1694     d = machine->first_diskimage;
1695 dpavlin 6 if (d != NULL) {
1696     if (typep != NULL)
1697     *typep = d->type;
1698 dpavlin 2 return d->id;
1699 dpavlin 6 }
1700 dpavlin 2
1701     return -1;
1702     }
1703    
1704    
1705     /*
1706 dpavlin 14 * diskimage_getname():
1707     *
1708     * Returns 1 if a valid disk image name was returned, 0 otherwise.
1709     */
1710     int diskimage_getname(struct machine *machine, int id, int type,
1711     char *buf, size_t bufsize)
1712     {
1713     struct diskimage *d = machine->first_diskimage;
1714    
1715     if (buf == NULL)
1716     return 0;
1717    
1718     while (d != NULL) {
1719     if (d->type == type && d->id == id) {
1720     char *p = strrchr(d->fname, '/');
1721     if (p == NULL)
1722     p = d->fname;
1723     else
1724     p ++;
1725     snprintf(buf, bufsize, "%s", p);
1726     return 1;
1727     }
1728     d = d->next;
1729     }
1730     return 0;
1731     }
1732    
1733    
1734     /*
1735 dpavlin 2 * diskimage_is_a_cdrom():
1736     *
1737 dpavlin 6 * Returns 1 if a disk image is a CDROM, 0 otherwise.
1738 dpavlin 2 */
1739 dpavlin 6 int diskimage_is_a_cdrom(struct machine *machine, int id, int type)
1740 dpavlin 2 {
1741     struct diskimage *d = machine->first_diskimage;
1742    
1743     while (d != NULL) {
1744 dpavlin 6 if (d->type == type && d->id == id)
1745 dpavlin 2 return d->is_a_cdrom;
1746     d = d->next;
1747     }
1748     return 0;
1749     }
1750    
1751    
1752     /*
1753     * diskimage_is_a_tape():
1754     *
1755 dpavlin 6 * Returns 1 if a disk image is a tape, 0 otherwise.
1756     *
1757 dpavlin 2 * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation
1758     * boot strings.)
1759     */
1760 dpavlin 6 int diskimage_is_a_tape(struct machine *machine, int id, int type)
1761 dpavlin 2 {
1762     struct diskimage *d = machine->first_diskimage;
1763    
1764     while (d != NULL) {
1765 dpavlin 6 if (d->type == type && d->id == id)
1766 dpavlin 2 return d->is_a_tape;
1767     d = d->next;
1768     }
1769     return 0;
1770     }
1771    
1772    
1773     /*
1774     * diskimage_dump_info():
1775     *
1776     * Debug dump of all diskimages that are loaded for a specific machine.
1777     */
1778     void diskimage_dump_info(struct machine *machine)
1779     {
1780     int iadd=4;
1781     struct diskimage *d = machine->first_diskimage;
1782    
1783     while (d != NULL) {
1784     debug("diskimage: %s\n", d->fname);
1785     debug_indentation(iadd);
1786    
1787     switch (d->type) {
1788     case DISKIMAGE_SCSI:
1789     debug("SCSI");
1790     break;
1791     case DISKIMAGE_IDE:
1792     debug("IDE");
1793     break;
1794 dpavlin 4 case DISKIMAGE_FLOPPY:
1795     debug("FLOPPY");
1796     break;
1797 dpavlin 2 default:
1798     debug("UNKNOWN type %i", d->type);
1799     }
1800    
1801     debug(" %s", d->is_a_tape? "TAPE" :
1802     (d->is_a_cdrom? "CD-ROM" : "DISK"));
1803     debug(" id %i, ", d->id);
1804     debug("%s, ", d->writable? "read/write" : "read-only");
1805    
1806 dpavlin 4 if (d->type == DISKIMAGE_FLOPPY)
1807     debug("%lli KB", (long long) (d->total_size / 1024));
1808     else
1809     debug("%lli MB", (long long) (d->total_size / 1048576));
1810    
1811 dpavlin 6 if (d->type == DISKIMAGE_FLOPPY || d->chs_override)
1812     debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads,
1813     d->sectors_per_track);
1814     else
1815     debug(" (%lli sectors)", (long long)
1816     (d->total_size / 512));
1817 dpavlin 2
1818 dpavlin 6 if (d->is_boot_device)
1819     debug(" (BOOT)");
1820     debug("\n");
1821    
1822 dpavlin 2 debug_indentation(-iadd);
1823    
1824     d = d->next;
1825     }
1826     }
1827    

  ViewVC Help
Powered by ViewVC 1.1.26