/[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 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 45837 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26