/[gxemul]/upstream/0.3.3.1/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 /upstream/0.3.3.1/src/diskimage.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26