/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 45703 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26