/[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

Contents of /upstream/0.3.3.1/src/diskimage.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Mon Oct 8 16:18:14 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 44299 byte(s)
0.3.3.1
1 /*
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 * $Id: diskimage.c,v 1.91 2005/05/27 07:29:24 debug Exp $
29 *
30 * Disk image support.
31 *
32 * TODO: There's probably a bug in the tape support:
33 * Let's say there are 10240 bytes left in a file, and 10240
34 * bytes are read. Then feof() is not true yet (?), so the next
35 * read will also return 10240 bytes (but all zeroes), and then after
36 * that return feof (which results in a filemark). This is probably
37 * trivial to fix, but I don't feel like it right now.
38 *
39 * TODO: diskimage_remove()? This would be useful for floppies in PC-style
40 * machines, where disks may need to be swapped during boot etc.
41 */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49
50 #include "cpu.h"
51 #include "diskimage.h"
52 #include "machine.h"
53 #include "misc.h"
54
55
56 extern int quiet_mode;
57 extern int single_step;
58
59 static char *diskimage_types[] = DISKIMAGE_TYPES;
60
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 * Returns 1 if the specified disk id (for a specific type) exists, 0
212 * otherwise.
213 */
214 int diskimage_exist(struct machine *machine, int id, int type)
215 {
216 struct diskimage *d = machine->first_diskimage;
217
218 while (d != NULL) {
219 if (d->type == type && d->id == id)
220 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
260 /* TODO: There is a mismatch between d->ncyls and d->cylinders,
261 SCSI-based stuff usually doesn't care. TODO: Fix this. */
262 }
263
264
265 /*
266 * diskimage_getsize():
267 *
268 * Returns -1 if the specified disk id/type does not exists, otherwise
269 * the size of the disk image is returned.
270 */
271 int64_t diskimage_getsize(struct machine *machine, int id, int type)
272 {
273 struct diskimage *d = machine->first_diskimage;
274
275 while (d != NULL) {
276 if (d->type == type && d->id == id)
277 return d->total_size;
278 d = d->next;
279 }
280 return -1;
281 }
282
283
284 /*
285 * 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 * 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 int diskimage_scsicommand(struct cpu *cpu, int id, int type,
479 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 if (d->type == type && d->id == id)
496 break;
497 d = d->next;
498 }
499 if (d == NULL) {
500 fprintf(stderr, "[ diskimage_scsicommand(): %s "
501 " id %i not connected? ]\n", diskimage_types[type], id);
502 }
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 id, xferp->cmd[0]);
517
518 #if 0
519 fatal("[ diskimage_scsicommand(id=%i) cmd=0x%02x len=%i:",
520 id, xferp->cmd[0], xferp->cmd_len);
521 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 fprintf(f, "id=%i cmd =", id);
536 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 debug("[ MODE SENSE id %i, pagecode=%i ]\n", id, pagecode);
726
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 xferp->data_in[12 + 11] = d->sectors_per_track;
767
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 xferp->data_in[12 + 5] = d->heads;
780
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 xferp->data_in[12 + 4] = d->heads;
793 xferp->data_in[12 + 5] = d->sectors_per_track;
794
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 ", ofs=%lli ]\n", id, d->tape_filenr,
851 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 debug(" feof id=%i\n", id);
914 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 xferp->cmd[0], id);
1311 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 int diskimage_access(struct machine *machine, int id, int type, int writeflag,
1327 off_t offset, unsigned char *buf, size_t len)
1328 {
1329 struct diskimage *d = machine->first_diskimage;
1330
1331 while (d != NULL) {
1332 if (d->type == type && d->id == id)
1333 break;
1334 d = d->next;
1335 }
1336
1337 if (d == NULL) {
1338 fatal("[ diskimage_access(): ERROR: trying to access a "
1339 "non-existant %s disk image (id %i)\n",
1340 diskimage_types[type], id);
1341 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 * b specifies that this is a bootable device
1356 * c CD-ROM (instead of a normal DISK)
1357 * d DISK (this is the default)
1358 * f FLOPPY (instead of SCSI)
1359 * gH;S; set geometry (H=heads, S=sectors per track, cylinders are
1360 * automatically calculated). (This is ignored for floppies.)
1361 * i IDE (instead of SCSI)
1362 * r read-only (don't allow changes to the file)
1363 * s SCSI (this is the default)
1364 * t tape
1365 * 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 int id = 0, override_heads=0, override_spt=0;
1374 int64_t bytespercyl;
1375 char *cp;
1376 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
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 case 'f':
1410 prefix_f = 1;
1411 break;
1412 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 case 'i':
1434 prefix_i = 1;
1435 break;
1436 case 'r':
1437 prefix_r = 1;
1438 break;
1439 case 's':
1440 prefix_s = 1;
1441 break;
1442 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 /* 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 if (prefix_i)
1488 d->type = DISKIMAGE_IDE;
1489 if (prefix_f)
1490 d->type = DISKIMAGE_FLOPPY;
1491 if (prefix_s)
1492 d->type = DISKIMAGE_SCSI;
1493
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 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 d->type = DISKIMAGE_FLOPPY;
1546
1547 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 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 /* 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 return id;
1633 }
1634
1635
1636 /*
1637 * diskimage_bootdev():
1638 *
1639 * 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 *
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 int diskimage_bootdev(struct machine *machine, int *typep)
1646 {
1647 struct diskimage *d;
1648
1649 d = machine->first_diskimage;
1650 while (d != NULL) {
1651 if (d->is_boot_device) {
1652 if (typep != NULL)
1653 *typep = d->type;
1654 return d->id;
1655 }
1656 d = d->next;
1657 }
1658
1659 d = machine->first_diskimage;
1660 if (d != NULL) {
1661 if (typep != NULL)
1662 *typep = d->type;
1663 return d->id;
1664 }
1665
1666 return -1;
1667 }
1668
1669
1670 /*
1671 * diskimage_is_a_cdrom():
1672 *
1673 * Returns 1 if a disk image is a CDROM, 0 otherwise.
1674 */
1675 int diskimage_is_a_cdrom(struct machine *machine, int id, int type)
1676 {
1677 struct diskimage *d = machine->first_diskimage;
1678
1679 while (d != NULL) {
1680 if (d->type == type && d->id == id)
1681 return d->is_a_cdrom;
1682 d = d->next;
1683 }
1684 return 0;
1685 }
1686
1687
1688 /*
1689 * diskimage_is_a_tape():
1690 *
1691 * Returns 1 if a disk image is a tape, 0 otherwise.
1692 *
1693 * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation
1694 * boot strings.)
1695 */
1696 int diskimage_is_a_tape(struct machine *machine, int id, int type)
1697 {
1698 struct diskimage *d = machine->first_diskimage;
1699
1700 while (d != NULL) {
1701 if (d->type == type && d->id == id)
1702 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 case DISKIMAGE_FLOPPY:
1731 debug("FLOPPY");
1732 break;
1733 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 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 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
1754 if (d->is_boot_device)
1755 debug(" (BOOT)");
1756 debug("\n");
1757
1758 debug_indentation(-iadd);
1759
1760 d = d->next;
1761 }
1762 }
1763

  ViewVC Help
Powered by ViewVC 1.1.26