/[gxemul]/trunk/src/diskimage.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/diskimage.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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


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

  ViewVC Help
Powered by ViewVC 1.1.26