/[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 14 - (show annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 45344 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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

  ViewVC Help
Powered by ViewVC 1.1.26