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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show annotations)
Mon Oct 8 16:21:34 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 47581 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1497 2007/03/18 03:41:36 debug Exp $
20070224	Minor update to the initialization of the ns16550 in
		machine_walnut.c, to allow that machine type to boot with the
		new interrupt system (although it is still a dummy machine).
		Adding a wdc at 0x14000000 to machine_landisk.c, and fixing
		the SCIF serial interrupts of the SH4 cpu enough to get
		NetBSD/landisk booting from a disk image :-)  Adding a
		preliminary install instruction skeleton to guestoses.html.
20070306	Adding SH-IPL+G PROM emulation, and also passing the "end"
		symbol in r5 on bootup, for Landisk emulation. This is enough
		to get OpenBSD/landisk to install :)  Adding a preliminary
		install instruction skeleton to the documentation. SuperH
		emulation is still shaky, though :-/
20070307	Fixed a strangeness in memory_sh.c (read/write was never
		returned for any page). (Unknown whether this fixes any actual
		problems, though.)
20070308	dev_ram.c fix: invalidate code translations on writes to
		RAM, emulated as separate devices. Linux/dreamcast gets
		further in the boot process than before, but still bugs out
		in userland.
		Fixing bugs in the "stc.l gbr,@-rN" and "ldc.l @rN+,gbr" SuperH 
		instructions (they should NOT check the MD bit), allowing the
		Linux/dreamcast Live CD to reach userland correctly :-)
20070310	Changing the cpu name "Alpha" in src/useremul.c to "21364" to
		unbreak userland syscall emulation of FreeBSD/Alpha binaries.
20070314	Applying a patch from Michael Yaroslavtsev which fixes the
		previous Linux lib64 patch to the configure script.
20070315	Adding a (dummy) sun4v machine type, and SPARC T1 cpu type.
20070316	Creating a new directory, src/disk, and moving diskimage.c
		to it. Separating out bootblock loading stuff from emul.c into
		new files in src/disk.
		Adding some more SPARC registers.
20070318	Preparing/testing for a minirelease, 0.4.4.1.

==============  RELEASE 0.4.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26