/[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 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 45344 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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

  ViewVC Help
Powered by ViewVC 1.1.26