/[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 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 46014 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: diskimage.c,v 1.102 2005/11/21 09:17:25 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 int 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_DEC) {
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_DEC) {
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_DEC) {
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 = (xferp->cmd[2] << 24) + (xferp->cmd[3]
901 << 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 = (xferp->cmd[2] << 24) + (xferp->cmd[3] << 16) +
979 (xferp->cmd[4] << 8) + xferp->cmd[5];
980 retlen = (xferp->cmd[7] << 8) + xferp->cmd[8];
981 }
982
983 size = retlen * d->logical_block_size;
984 ofs *= d->logical_block_size;
985
986 if (xferp->data_out_offset != size) {
987 debug(", data_out == NULL, wanting %i bytes, \n\n",
988 (int)size);
989 xferp->data_out_len = size;
990 return 2;
991 }
992
993 debug(", data_out != NULL, OK :-)");
994
995 debug("WRITE ofs=%i size=%i offset=%i\n", (int)ofs,
996 (int)size, (int)xferp->data_out_offset);
997
998 diskimage__internal_access(d, 1, ofs,
999 xferp->data_out, size);
1000
1001 /* TODO: how about return code? */
1002
1003 /* Is this really necessary? */
1004 /* fsync(fileno(d->f)); */
1005
1006 diskimage__return_default_status_and_message(xferp);
1007 break;
1008
1009 case SCSICMD_SYNCHRONIZE_CACHE:
1010 debug("SYNCHRONIZE_CACHE");
1011
1012 if (xferp->cmd_len != 10)
1013 debug(" (weird len=%i)", xferp->cmd_len);
1014
1015 /* TODO: actualy care about cmd[] */
1016 fsync(fileno(d->f));
1017
1018 diskimage__return_default_status_and_message(xferp);
1019 break;
1020
1021 case SCSICMD_START_STOP_UNIT:
1022 debug("START_STOP_UNIT");
1023
1024 if (xferp->cmd_len != 6)
1025 debug(" (weird len=%i)", xferp->cmd_len);
1026
1027 for (i=0; i<xferp->cmd_len; i++)
1028 debug(" %02x", xferp->cmd[i]);
1029
1030 /* TODO: actualy care about cmd[] */
1031
1032 diskimage__return_default_status_and_message(xferp);
1033 break;
1034
1035 case SCSICMD_REQUEST_SENSE:
1036 debug("REQUEST_SENSE");
1037
1038 retlen = xferp->cmd[4];
1039
1040 /* TODO: bits 765 of buf[1] contains the LUN */
1041 if (xferp->cmd[1] != 0x00)
1042 fatal("WARNING: REQUEST_SENSE with cmd[1]=0x%02x not"
1043 " yet implemented\n", (int)xferp->cmd[1]);
1044
1045 if (retlen < 18) {
1046 fatal("WARNING: SCSI request sense len=%i, <18!\n",
1047 (int)retlen);
1048 retlen = 18;
1049 }
1050
1051 /* Return data: */
1052 scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
1053 retlen, 1);
1054
1055 xferp->data_in[0] = 0x80 + 0x70;/* 0x80 = valid,
1056 0x70 = "current errors" */
1057 xferp->data_in[2] = 0x00; /* SENSE KEY! */
1058
1059 if (d->filemark) {
1060 xferp->data_in[2] = 0x80;
1061 }
1062 debug(": [2]=0x%02x ", xferp->data_in[2]);
1063
1064 printf(" XXX(!) \n");
1065
1066 /* TODO */
1067 xferp->data_in[7] = retlen - 7; /* additional sense length */
1068 /* TODO */
1069
1070 diskimage__return_default_status_and_message(xferp);
1071 break;
1072
1073 case SCSICMD_READ_BLOCK_LIMITS:
1074 debug("READ_BLOCK_LIMITS");
1075
1076 retlen = 6;
1077
1078 /* TODO: bits 765 of buf[1] contains the LUN */
1079 if (xferp->cmd[1] != 0x00)
1080 fatal("WARNING: READ_BLOCK_LIMITS with cmd[1]="
1081 "0x%02x not yet implemented\n", (int)xferp->cmd[1]);
1082
1083 /* Return data: */
1084 scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
1085 retlen, 1);
1086
1087 /*
1088 * data[0] is reserved, data[1..3] contain the maximum block
1089 * length limit, data[4..5] contain the minimum limit.
1090 */
1091
1092 {
1093 int max_limit = 32768;
1094 int min_limit = 128;
1095
1096 xferp->data_in[1] = (max_limit >> 16) & 255;
1097 xferp->data_in[2] = (max_limit >> 8) & 255;
1098 xferp->data_in[3] = max_limit & 255;
1099 xferp->data_in[4] = (min_limit >> 8) & 255;
1100 xferp->data_in[5] = min_limit & 255;
1101 }
1102
1103 diskimage__return_default_status_and_message(xferp);
1104 break;
1105
1106 case SCSICMD_REWIND:
1107 debug("REWIND");
1108
1109 /* TODO: bits 765 of buf[1] contains the LUN */
1110 if ((xferp->cmd[1] & 0xe0) != 0x00)
1111 fatal("WARNING: REWIND with cmd[1]=0x%02x not yet "
1112 "implemented\n", (int)xferp->cmd[1]);
1113
1114 /* Close and reopen. */
1115
1116 if (d->f != NULL)
1117 fclose(d->f);
1118
1119 d->f = fopen(d->fname, d->writable? "r+" : "r");
1120 if (d->f == NULL) {
1121 fprintf(stderr, "[ diskimage: could not (re)open "
1122 "'%s' ]\n", d->fname);
1123 /* TODO: return error */
1124 }
1125
1126 d->tape_offset = 0;
1127 d->tape_filenr = 0;
1128 d->filemark = 0;
1129
1130 diskimage__return_default_status_and_message(xferp);
1131 break;
1132
1133 case SCSICMD_SPACE:
1134 debug("SPACE");
1135
1136 /* TODO: bits 765 of buf[1] contains the LUN */
1137 if ((xferp->cmd[1] & 0xe0) != 0x00)
1138 fatal("WARNING: SPACE with cmd[1]=0x%02x not yet "
1139 "implemented\n", (int)xferp->cmd[1]);
1140
1141 /*
1142 * Bits 2..0 of buf[1] contain the 'code' which describes how
1143 * we should space, and buf[2..4] contain the number of
1144 * operations.
1145 */
1146 debug("[ SPACE: buf[] = %02x %02x %02x %02x %02x %02x ]\n",
1147 xferp->cmd[0],
1148 xferp->cmd[1],
1149 xferp->cmd[2],
1150 xferp->cmd[3],
1151 xferp->cmd[4],
1152 xferp->cmd[5]);
1153
1154 switch (xferp->cmd[1] & 7) {
1155 case 1: /* Seek to a different file nr: */
1156 {
1157 int diff = (xferp->cmd[2] << 16) +
1158 (xferp->cmd[3] << 8) + xferp->cmd[4];
1159
1160 /* Negative seek offset: */
1161 if (diff & (1 << 23))
1162 diff = - (16777216 - diff);
1163
1164 d->tape_filenr += diff;
1165 }
1166
1167 /* At end of file, switch to the next tape file: */
1168 if (d->filemark) {
1169 d->tape_filenr ++;
1170 d->filemark = 0;
1171 }
1172
1173 debug("{ switching to tape file %i }", d->tape_filenr);
1174 diskimage__switch_tape(d);
1175 d->filemark = 0;
1176 break;
1177 default:
1178 fatal("[ diskimage.c: unimplemented SPACE type %i ]\n",
1179 xferp->cmd[1] & 7);
1180 }
1181
1182 diskimage__return_default_status_and_message(xferp);
1183 break;
1184
1185 case SCSICDROM_READ_SUBCHANNEL:
1186 /*
1187 * According to
1188 * http://mail-index.netbsd.org/port-i386/1997/03/03/0010.html:
1189 *
1190 * "The READ_CD_CAPACITY, READ_SUBCHANNEL, and MODE_SELECT
1191 * commands have the same opcode in SCSI or ATAPI, but don't
1192 * have the same command structure"...
1193 *
1194 * TODO: This still doesn't work. Hm.
1195 */
1196 retlen = 48;
1197
1198 debug("CDROM_READ_SUBCHANNEL/READ_CD_CAPACITY, cmd[1]=0x%02x",
1199 xferp->cmd[1]);
1200
1201 /* Return data: */
1202 scsi_transfer_allocbuf(&xferp->data_in_len,
1203 &xferp->data_in, retlen, 1);
1204
1205 diskimage_recalc_size(d);
1206
1207 size = d->total_size / d->logical_block_size;
1208 if (d->total_size & (d->logical_block_size-1))
1209 size ++;
1210
1211 xferp->data_in[0] = (size >> 24) & 255;
1212 xferp->data_in[1] = (size >> 16) & 255;
1213 xferp->data_in[2] = (size >> 8) & 255;
1214 xferp->data_in[3] = size & 255;
1215
1216 xferp->data_in[4] = (d->logical_block_size >> 24) & 255;
1217 xferp->data_in[5] = (d->logical_block_size >> 16) & 255;
1218 xferp->data_in[6] = (d->logical_block_size >> 8) & 255;
1219 xferp->data_in[7] = d->logical_block_size & 255;
1220
1221 diskimage__return_default_status_and_message(xferp);
1222 break;
1223
1224 case SCSICDROM_READ_TOC:
1225 debug("(CDROM_READ_TOC: ");
1226 debug("lun=%i msf=%i ",
1227 xferp->cmd[1] >> 5, (xferp->cmd[1] >> 1) & 1);
1228 debug("starting_track=%i ", xferp->cmd[6]);
1229 retlen = xferp->cmd[7] * 256 + xferp->cmd[8];
1230 debug("allocation_len=%i)\n", retlen);
1231
1232 /* Return data: */
1233 scsi_transfer_allocbuf(&xferp->data_in_len,
1234 &xferp->data_in, retlen, 1);
1235
1236 xferp->data_in[0] = 0;
1237 xferp->data_in[1] = 10;
1238 xferp->data_in[2] = 0; /* First track. */
1239 xferp->data_in[3] = 0; /* Last track. */
1240
1241 /* Track 0 data: */
1242 xferp->data_in[4] = 0x00; /* Reserved. */
1243 xferp->data_in[5] = 0x04; /* ADR + CTRL:
1244 Data, not audio */
1245 xferp->data_in[6] = 0x00; /* Track nr */
1246 xferp->data_in[7] = 0x00; /* Reserved */
1247 /* 8..11 = absolute CDROM address */
1248
1249 diskimage__return_default_status_and_message(xferp);
1250 break;
1251
1252 case SCSICMD_MODE_SELECT:
1253 debug("[ SCSI MODE_SELECT: ");
1254
1255 /*
1256 * TODO:
1257 *
1258 * This is super-hardcoded for NetBSD's usage of mode_select
1259 * to set the size of CDROM sectors to 2048.
1260 */
1261
1262 if (xferp->data_out_offset == 0) {
1263 xferp->data_out_len = 12; /* TODO */
1264 debug("data_out == NULL, wanting %i bytes ]\n",
1265 (int)xferp->data_out_len);
1266 return 2;
1267 }
1268
1269 debug("data_out!=NULL (OK), ");
1270
1271 /* TODO: Care about cmd? */
1272
1273 /* Set sector size to 2048: */
1274 /* 00 05 00 08 00 03 ca 40 00 00 08 00 */
1275 if (xferp->data_out[0] == 0x00 &&
1276 xferp->data_out[1] == 0x05 &&
1277 xferp->data_out[2] == 0x00 &&
1278 xferp->data_out[3] == 0x08) {
1279 d->logical_block_size =
1280 (xferp->data_out[9] << 16) +
1281 (xferp->data_out[10] << 8) +
1282 xferp->data_out[11];
1283 debug("[ setting logical_block_size to %i ]\n",
1284 d->logical_block_size);
1285 } else {
1286 int i;
1287 fatal("[ unknown MODE_SELECT: cmd =");
1288 for (i=0; i<xferp->cmd_len; i++)
1289 fatal(" %02x", xferp->cmd[i]);
1290 fatal(", data_out =");
1291 for (i=0; i<xferp->data_out_len; i++)
1292 fatal(" %02x", xferp->data_out[i]);
1293 fatal(" ]");
1294 }
1295
1296 debug(" ]\n");
1297 diskimage__return_default_status_and_message(xferp);
1298 break;
1299
1300 case SCSICMD_PREVENT_ALLOW_REMOVE:
1301 debug("[ SCSI 0x%02x Prevent/allow medium removal: "
1302 "TODO ]\n", xferp->cmd[0]);
1303
1304 diskimage__return_default_status_and_message(xferp);
1305 break;
1306
1307 case 0xbd:
1308 fatal("[ SCSI 0x%02x (len %i), TODO: ", xferp->cmd[0],
1309 xferp->cmd_len);
1310 for (i=0; i<xferp->cmd_len; i++)
1311 fatal(" %02x", xferp->cmd[i]);
1312 fatal(" ]\n");
1313
1314 /*
1315 * Used by Windows NT?
1316 *
1317 * Not documented in http://www.danbbs.dk/~dino/
1318 * SCSI/SCSI2-D.html.
1319 * Google gave the answer "MECHANISM_STATUS" for ATAPI. Hm.
1320 */
1321
1322 if (xferp->cmd_len < 12) {
1323 fatal("WEIRD LEN?\n");
1324 retlen = 8;
1325 } else {
1326 retlen = xferp->cmd[8] * 256 + xferp->cmd[9];
1327 }
1328
1329 /* Return data: */
1330 scsi_transfer_allocbuf(&xferp->data_in_len,
1331 &xferp->data_in, retlen, 1);
1332
1333 diskimage__return_default_status_and_message(xferp);
1334
1335 break;
1336
1337 default:
1338 fatal("[ UNIMPLEMENTED SCSI command 0x%02x, disk id=%i ]\n",
1339 xferp->cmd[0], id);
1340 exit(1);
1341 }
1342 debug(" ]\n");
1343
1344 return 1;
1345 }
1346
1347
1348 /*
1349 * diskimage_access():
1350 *
1351 * Read from or write to a disk image on a machine.
1352 *
1353 * Returns 1 if the access completed successfully, 0 otherwise.
1354 */
1355 int diskimage_access(struct machine *machine, int id, int type, int writeflag,
1356 off_t offset, unsigned char *buf, size_t len)
1357 {
1358 struct diskimage *d = machine->first_diskimage;
1359
1360 while (d != NULL) {
1361 if (d->type == type && d->id == id)
1362 break;
1363 d = d->next;
1364 }
1365
1366 if (d == NULL) {
1367 fatal("[ diskimage_access(): ERROR: trying to access a "
1368 "non-existant %s disk image (id %i)\n",
1369 diskimage_types[type], id);
1370 return 0;
1371 }
1372
1373 return diskimage__internal_access(d, writeflag, offset, buf, len);
1374 }
1375
1376
1377 /*
1378 * diskimage_add():
1379 *
1380 * Add a disk image. fname is the filename of the disk image.
1381 * The filename may be prefixed with one or more modifiers, followed
1382 * by a colon.
1383 *
1384 * b specifies that this is a bootable device
1385 * c CD-ROM (instead of a normal DISK)
1386 * d DISK (this is the default)
1387 * f FLOPPY (instead of SCSI)
1388 * gH;S; set geometry (H=heads, S=sectors per track, cylinders are
1389 * automatically calculated). (This is ignored for floppies.)
1390 * i IDE (instead of SCSI)
1391 * r read-only (don't allow changes to the file)
1392 * s SCSI (this is the default)
1393 * t tape
1394 * 0-7 force a specific SCSI ID number
1395 *
1396 * machine is assumed to be non-NULL.
1397 * Returns an integer >= 0 identifying the disk image.
1398 */
1399 int diskimage_add(struct machine *machine, char *fname)
1400 {
1401 struct diskimage *d, *d2;
1402 int id = 0, override_heads=0, override_spt=0;
1403 int64_t bytespercyl;
1404 char *cp;
1405 int prefix_b=0, prefix_c=0, prefix_d=0, prefix_f=0, prefix_g=0;
1406 int prefix_i=0, prefix_r=0, prefix_s=0, prefix_t=0, prefix_id = -1;
1407
1408 if (fname == NULL) {
1409 fprintf(stderr, "diskimage_add(): NULL ptr\n");
1410 return 0;
1411 }
1412
1413 /* Get prefix from fname: */
1414 cp = strchr(fname, ':');
1415 if (cp != NULL) {
1416 while (fname <= cp) {
1417 char c = *fname++;
1418 switch (c) {
1419 case '0':
1420 case '1':
1421 case '2':
1422 case '3':
1423 case '4':
1424 case '5':
1425 case '6':
1426 case '7':
1427 prefix_id = c - '0';
1428 break;
1429 case 'b':
1430 prefix_b = 1;
1431 break;
1432 case 'c':
1433 prefix_c = 1;
1434 break;
1435 case 'd':
1436 prefix_d = 1;
1437 break;
1438 case 'f':
1439 prefix_f = 1;
1440 break;
1441 case 'g':
1442 prefix_g = 1;
1443 override_heads = atoi(fname);
1444 while (*fname != '\0' && *fname != ';')
1445 fname ++;
1446 if (*fname == ';')
1447 fname ++;
1448 override_spt = atoi(fname);
1449 while (*fname != '\0' && *fname != ';' &&
1450 *fname != ':')
1451 fname ++;
1452 if (*fname == ';')
1453 fname ++;
1454 if (override_heads < 1 ||
1455 override_spt < 1) {
1456 fatal("Bad geometry: heads=%i "
1457 "spt=%i\n", override_heads,
1458 override_spt);
1459 exit(1);
1460 }
1461 break;
1462 case 'i':
1463 prefix_i = 1;
1464 break;
1465 case 'r':
1466 prefix_r = 1;
1467 break;
1468 case 's':
1469 prefix_s = 1;
1470 break;
1471 case 't':
1472 prefix_t = 1;
1473 break;
1474 case ':':
1475 break;
1476 default:
1477 fprintf(stderr, "diskimage_add(): invalid "
1478 "prefix char '%c'\n", c);
1479 exit(1);
1480 }
1481 }
1482 }
1483
1484 /* Allocate a new diskimage struct: */
1485 d = malloc(sizeof(struct diskimage));
1486 if (d == NULL) {
1487 fprintf(stderr, "out of memory in diskimage_add()\n");
1488 exit(1);
1489 }
1490 memset(d, 0, sizeof(struct diskimage));
1491
1492 d2 = machine->first_diskimage;
1493 if (d2 == NULL) {
1494 machine->first_diskimage = d;
1495 } else {
1496 while (d2->next != NULL)
1497 d2 = d2->next;
1498 d2->next = d;
1499 }
1500
1501 d->type = DISKIMAGE_SCSI;
1502
1503 /* Special cases: some machines usually have FLOPPY/IDE, not SCSI: */
1504 if (machine->arch == ARCH_X86 ||
1505 machine->machine_type == MACHINE_COBALT ||
1506 machine->machine_type == MACHINE_EVBMIPS ||
1507 machine->machine_type == MACHINE_HPCMIPS ||
1508 machine->machine_type == MACHINE_BEBOX ||
1509 machine->machine_type == MACHINE_PREP ||
1510 machine->machine_type == MACHINE_CATS ||
1511 machine->machine_type == MACHINE_NETWINDER ||
1512 machine->machine_type == MACHINE_PS2)
1513 d->type = DISKIMAGE_IDE;
1514
1515 if (prefix_i + prefix_f + prefix_s > 1) {
1516 fprintf(stderr, "Invalid disk image prefix(es). You can"
1517 "only use one of i, f, and s\nfor each disk image.\n");
1518 exit(1);
1519 }
1520
1521 if (prefix_i)
1522 d->type = DISKIMAGE_IDE;
1523 if (prefix_f)
1524 d->type = DISKIMAGE_FLOPPY;
1525 if (prefix_s)
1526 d->type = DISKIMAGE_SCSI;
1527
1528 d->fname = strdup(fname);
1529 if (d->fname == NULL) {
1530 fprintf(stderr, "out of memory\n");
1531 exit(1);
1532 }
1533
1534 d->logical_block_size = 512;
1535
1536 /*
1537 * Is this a tape, CD-ROM or a normal disk?
1538 *
1539 * An intelligent guess, if no prefixes are used, would be that
1540 * filenames ending with .iso or .cdr are CD-ROM images.
1541 */
1542 if (prefix_t) {
1543 d->is_a_tape = 1;
1544 } else {
1545 if (prefix_c ||
1546 ((strlen(d->fname) > 4 &&
1547 (strcasecmp(d->fname + strlen(d->fname) - 4, ".cdr") == 0 ||
1548 strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0))
1549 && !prefix_d)
1550 ) {
1551 d->is_a_cdrom = 1;
1552
1553 /*
1554 * This is tricky. Should I use 512 or 2048 here?
1555 * NetBSD/pmax 1.6.2 and Ultrix likes 512 bytes
1556 * per sector, but NetBSD 2.0_BETA suddenly ignores
1557 * this value and uses 2048 instead.
1558 *
1559 * OpenBSD/arc doesn't like 2048, it requires 512
1560 * to work correctly.
1561 *
1562 * TODO
1563 */
1564
1565 #if 0
1566 if (machine->machine_type == MACHINE_DEC)
1567 d->logical_block_size = 512;
1568 else
1569 d->logical_block_size = 2048;
1570 #endif
1571 d->logical_block_size = 512;
1572 }
1573 }
1574
1575 diskimage_recalc_size(d);
1576
1577 if ((d->total_size == 720*1024 || d->total_size == 1474560
1578 || d->total_size == 2949120 || d->total_size == 1228800)
1579 && !prefix_i && !prefix_s)
1580 d->type = DISKIMAGE_FLOPPY;
1581
1582 switch (d->type) {
1583 case DISKIMAGE_FLOPPY:
1584 if (d->total_size < 737280) {
1585 fatal("\nTODO: small (non-80-cylinder) floppies?\n\n");
1586 exit(1);
1587 }
1588 d->cylinders = 80;
1589 d->heads = 2;
1590 d->sectors_per_track = d->total_size / (d->cylinders *
1591 d->heads * 512);
1592 break;
1593 default:/* Non-floppies: */
1594 d->heads = 16;
1595 d->sectors_per_track = 63;
1596 if (prefix_g) {
1597 d->chs_override = 1;
1598 d->heads = override_heads;
1599 d->sectors_per_track = override_spt;
1600 }
1601 bytespercyl = d->heads * d->sectors_per_track * 512;
1602 d->cylinders = d->total_size / bytespercyl;
1603 if (d->cylinders * bytespercyl < d->total_size)
1604 d->cylinders ++;
1605 }
1606
1607 d->rpms = 3600;
1608
1609 if (prefix_b)
1610 d->is_boot_device = 1;
1611
1612 d->writable = access(fname, W_OK) == 0? 1 : 0;
1613
1614 if (d->is_a_cdrom || prefix_r)
1615 d->writable = 0;
1616
1617 d->f = fopen(fname, d->writable? "r+" : "r");
1618 if (d->f == NULL) {
1619 perror(fname);
1620 exit(1);
1621 }
1622
1623 /* Calculate which ID to use: */
1624 if (prefix_id == -1) {
1625 int free = 0, collision = 1;
1626
1627 while (collision) {
1628 collision = 0;
1629 d2 = machine->first_diskimage;
1630 while (d2 != NULL) {
1631 /* (don't compare against ourselves :) */
1632 if (d2 == d) {
1633 d2 = d2->next;
1634 continue;
1635 }
1636 if (d2->id == free && d2->type == d->type) {
1637 collision = 1;
1638 break;
1639 }
1640 d2 = d2->next;
1641 }
1642 if (!collision)
1643 id = free;
1644 else
1645 free ++;
1646 }
1647 } else {
1648 id = prefix_id;
1649 d2 = machine->first_diskimage;
1650 while (d2 != NULL) {
1651 /* (don't compare against ourselves :) */
1652 if (d2 == d) {
1653 d2 = d2->next;
1654 continue;
1655 }
1656 if (d2->id == id && d2->type == d->type) {
1657 fprintf(stderr, "disk image id %i "
1658 "already in use\n", id);
1659 exit(1);
1660 }
1661 d2 = d2->next;
1662 }
1663 }
1664
1665 d->id = id;
1666
1667 return id;
1668 }
1669
1670
1671 /*
1672 * diskimage_bootdev():
1673 *
1674 * Returns the disk id of the device which we're booting from. If typep is
1675 * non-NULL, the type is returned as well.
1676 *
1677 * If no disk was used as boot device, then -1 is returned. (In practice,
1678 * this is used to fake network (tftp) boot.)
1679 */
1680 int diskimage_bootdev(struct machine *machine, int *typep)
1681 {
1682 struct diskimage *d;
1683
1684 d = machine->first_diskimage;
1685 while (d != NULL) {
1686 if (d->is_boot_device) {
1687 if (typep != NULL)
1688 *typep = d->type;
1689 return d->id;
1690 }
1691 d = d->next;
1692 }
1693
1694 d = machine->first_diskimage;
1695 if (d != NULL) {
1696 if (typep != NULL)
1697 *typep = d->type;
1698 return d->id;
1699 }
1700
1701 return -1;
1702 }
1703
1704
1705 /*
1706 * diskimage_getname():
1707 *
1708 * Returns 1 if a valid disk image name was returned, 0 otherwise.
1709 */
1710 int diskimage_getname(struct machine *machine, int id, int type,
1711 char *buf, size_t bufsize)
1712 {
1713 struct diskimage *d = machine->first_diskimage;
1714
1715 if (buf == NULL)
1716 return 0;
1717
1718 while (d != NULL) {
1719 if (d->type == type && d->id == id) {
1720 char *p = strrchr(d->fname, '/');
1721 if (p == NULL)
1722 p = d->fname;
1723 else
1724 p ++;
1725 snprintf(buf, bufsize, "%s", p);
1726 return 1;
1727 }
1728 d = d->next;
1729 }
1730 return 0;
1731 }
1732
1733
1734 /*
1735 * diskimage_is_a_cdrom():
1736 *
1737 * Returns 1 if a disk image is a CDROM, 0 otherwise.
1738 */
1739 int diskimage_is_a_cdrom(struct machine *machine, int id, int type)
1740 {
1741 struct diskimage *d = machine->first_diskimage;
1742
1743 while (d != NULL) {
1744 if (d->type == type && d->id == id)
1745 return d->is_a_cdrom;
1746 d = d->next;
1747 }
1748 return 0;
1749 }
1750
1751
1752 /*
1753 * diskimage_is_a_tape():
1754 *
1755 * Returns 1 if a disk image is a tape, 0 otherwise.
1756 *
1757 * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation
1758 * boot strings.)
1759 */
1760 int diskimage_is_a_tape(struct machine *machine, int id, int type)
1761 {
1762 struct diskimage *d = machine->first_diskimage;
1763
1764 while (d != NULL) {
1765 if (d->type == type && d->id == id)
1766 return d->is_a_tape;
1767 d = d->next;
1768 }
1769 return 0;
1770 }
1771
1772
1773 /*
1774 * diskimage_dump_info():
1775 *
1776 * Debug dump of all diskimages that are loaded for a specific machine.
1777 */
1778 void diskimage_dump_info(struct machine *machine)
1779 {
1780 int iadd=4;
1781 struct diskimage *d = machine->first_diskimage;
1782
1783 while (d != NULL) {
1784 debug("diskimage: %s\n", d->fname);
1785 debug_indentation(iadd);
1786
1787 switch (d->type) {
1788 case DISKIMAGE_SCSI:
1789 debug("SCSI");
1790 break;
1791 case DISKIMAGE_IDE:
1792 debug("IDE");
1793 break;
1794 case DISKIMAGE_FLOPPY:
1795 debug("FLOPPY");
1796 break;
1797 default:
1798 debug("UNKNOWN type %i", d->type);
1799 }
1800
1801 debug(" %s", d->is_a_tape? "TAPE" :
1802 (d->is_a_cdrom? "CD-ROM" : "DISK"));
1803 debug(" id %i, ", d->id);
1804 debug("%s, ", d->writable? "read/write" : "read-only");
1805
1806 if (d->type == DISKIMAGE_FLOPPY)
1807 debug("%lli KB", (long long) (d->total_size / 1024));
1808 else
1809 debug("%lli MB", (long long) (d->total_size / 1048576));
1810
1811 if (d->type == DISKIMAGE_FLOPPY || d->chs_override)
1812 debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads,
1813 d->sectors_per_track);
1814 else
1815 debug(" (%lli sectors)", (long long)
1816 (d->total_size / 512));
1817
1818 if (d->is_boot_device)
1819 debug(" (BOOT)");
1820 debug("\n");
1821
1822 debug_indentation(-iadd);
1823
1824 d = d->next;
1825 }
1826 }
1827

  ViewVC Help
Powered by ViewVC 1.1.26