diskimage_scsicmd.cc Source File

Back to the index.

diskimage_scsicmd.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2009 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  * Disk image support: SCSI command emulation.
29  *
30  * TODO: There are LOTS of ugly magic values in this module. These should
31  * be replaced by proper defines.
32  *
33  * TODO: There's probably a bug in the tape support:
34  * Let's say there are 10240 bytes left in a file, and 10240
35  * bytes are read. Then feof() is not true yet (?), so the next
36  * read will also return 10240 bytes (but all zeroes), and then after
37  * that return feof (which results in a filemark). This is probably
38  * trivial to fix, but I don't feel like it right now.
39  */
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #include "cpu.h"
47 #include "diskimage.h"
48 #include "machine.h"
49 #include "misc.h"
50 
51 
52 static const char *diskimage_types[] = DISKIMAGE_TYPES;
53 static struct scsi_transfer *first_free_scsi_transfer_alloc = NULL;
54 
55 
56 /*
57  * scsi_transfer_alloc():
58  *
59  * Allocates memory for a new scsi_transfer struct, and fills it with
60  * sane data (NULL pointers).
61  * The return value is a pointer to the new struct. If allocation
62  * failed, the program exits.
63  */
65 {
66  struct scsi_transfer *p;
67 
68  if (first_free_scsi_transfer_alloc != NULL) {
69  p = first_free_scsi_transfer_alloc;
70  first_free_scsi_transfer_alloc = p->next_free;
71  } else {
72  p = (struct scsi_transfer *) malloc(sizeof(struct scsi_transfer));
73  if (p == NULL) {
74  fprintf(stderr, "scsi_transfer_alloc(): out "
75  "of memory\n");
76  exit(1);
77  }
78  }
79 
80  memset(p, 0, sizeof(struct scsi_transfer));
81 
82  return p;
83 }
84 
85 
86 /*
87  * scsi_transfer_free():
88  *
89  * Frees the space used by a scsi_transfer struct. All buffers refered
90  * to by the scsi_transfer struct are freed.
91  */
93 {
94  if (p == NULL) {
95  fprintf(stderr, "scsi_transfer_free(): p == NULL\n");
96  exit(1);
97  }
98 
99  if (p->msg_out != NULL)
100  free(p->msg_out);
101  if (p->cmd != NULL)
102  free(p->cmd);
103  if (p->data_out != NULL)
104  free(p->data_out);
105 
106  if (p->data_in != NULL)
107  free(p->data_in);
108  if (p->msg_in != NULL)
109  free(p->msg_in);
110  if (p->status != NULL)
111  free(p->status);
112 
113  p->next_free = first_free_scsi_transfer_alloc;
114  first_free_scsi_transfer_alloc = p;
115 }
116 
117 
118 /*
119  * scsi_transfer_allocbuf():
120  *
121  * Helper function, used by diskimage_scsicommand(), and SCSI controller
122  * devices. Example of usage:
123  *
124  * scsi_transfer_allocbuf(&xferp->msg_in_len, &xferp->msg_in, 1);
125  */
126 void scsi_transfer_allocbuf(size_t *lenp, unsigned char **pp, size_t want_len,
127  int clearflag)
128 {
129  unsigned char *p = (*pp);
130 
131  if (p != NULL) {
132  printf("WARNING! scsi_transfer_allocbuf(): old pointer "
133  "was not NULL, freeing it now\n");
134  free(p);
135  }
136 
137  (*lenp) = want_len;
138  if ((p = (unsigned char *) malloc(want_len)) == NULL) {
139  fprintf(stderr, "scsi_transfer_allocbuf(): out of "
140  "memory trying to allocate %li bytes\n", (long)want_len);
141  exit(1);
142  }
143 
144  if (clearflag)
145  memset(p, 0, want_len);
146 
147  (*pp) = p;
148 }
149 
150 
151 /**************************************************************************/
152 
153 
154 /*
155  * diskimage__return_default_status_and_message():
156  *
157  * Set the status and msg_in parts of a scsi_transfer struct
158  * to default values (msg_in = 0x00, status = 0x00).
159  */
160 static void diskimage__return_default_status_and_message(
161  struct scsi_transfer *xferp)
162 {
163  scsi_transfer_allocbuf(&xferp->status_len, &xferp->status, 1, 0);
164  xferp->status[0] = 0x00;
165  scsi_transfer_allocbuf(&xferp->msg_in_len, &xferp->msg_in, 1, 0);
166  xferp->msg_in[0] = 0x00;
167 }
168 
169 
170 /*
171  * diskimage__switch_tape():
172  *
173  * Used by the SPACE command. (d is assumed to be non-NULL.)
174  */
175 static void diskimage__switch_tape(struct diskimage *d)
176 {
177  char tmpfname[1000];
178 
179  snprintf(tmpfname, sizeof(tmpfname), "%s.%i",
180  d->fname, d->tape_filenr);
181  tmpfname[sizeof(tmpfname)-1] = '\0';
182 
183  if (d->f != NULL)
184  fclose(d->f);
185 
186  d->f = fopen(tmpfname, d->writable? "r+" : "r");
187  if (d->f == NULL) {
188  fprintf(stderr, "[ diskimage__switch_tape(): could not "
189  "(re)open '%s' ]\n", tmpfname);
190  /* TODO: return error */
191  }
192  d->tape_offset = 0;
193 }
194 
195 
196 /**************************************************************************/
197 
198 
199 /*
200  * diskimage_scsicommand():
201  *
202  * Perform a SCSI command on a disk image.
203  *
204  * The xferp points to a scsi_transfer struct, containing msg_out, command,
205  * and data_out coming from the SCSI controller device. This function
206  * interprets the command, and (if necessary) creates responses in
207  * data_in, msg_in, and status.
208  *
209  * Returns:
210  * 2 if the command expects data from the DATA_OUT phase,
211  * 1 if otherwise ok,
212  * 0 on error.
213  */
214 int diskimage_scsicommand(struct cpu *cpu, int id, int type,
215  struct scsi_transfer *xferp)
216 {
217  char namebuf[16];
218  int retlen, i, q;
219  uint64_t size;
220  int64_t ofs;
221  int pagecode;
222  struct machine *machine = cpu->machine;
223  struct diskimage *d;
224 
225  if (machine == NULL) {
226  fatal("[ diskimage_scsicommand(): machine == NULL ]\n");
227  return 0;
228  }
229 
230  d = machine->first_diskimage;
231  while (d != NULL) {
232  if (d->type == type && d->id == id)
233  break;
234  d = d->next;
235  }
236  if (d == NULL) {
237  fprintf(stderr, "[ diskimage_scsicommand(): %s "
238  " id %i not connected? ]\n", diskimage_types[type], id);
239  }
240 
241  if (xferp->cmd == NULL) {
242  fatal("[ diskimage_scsicommand(): cmd == NULL ]\n");
243  return 0;
244  }
245 
246  if (xferp->cmd_len < 1) {
247  fatal("[ diskimage_scsicommand(): cmd_len == %i ]\n",
248  xferp->cmd_len);
249  return 0;
250  }
251 
252  debug("[ diskimage_scsicommand(id=%i) cmd=0x%02x: ",
253  id, xferp->cmd[0]);
254 
255 #if 0
256  fatal("[ diskimage_scsicommand(id=%i) cmd=0x%02x len=%i:",
257  id, xferp->cmd[0], xferp->cmd_len);
258  for (i=0; i<xferp->cmd_len; i++)
259  fatal(" %02x", xferp->cmd[i]);
260  fatal("\n");
261 if (xferp->cmd_len > 7 && xferp->cmd[5] == 0x11)
263 #endif
264 
265 #if 0
266 {
267  static FILE *f = NULL;
268  if (f == NULL)
269  f = fopen("scsi_log.txt", "w");
270  if (f != NULL) {
271  int i;
272  fprintf(f, "id=%i cmd =", id);
273  for (i=0; i<xferp->cmd_len; i++)
274  fprintf(f, " %02x", xferp->cmd[i]);
275  fprintf(f, "\n");
276  fflush(f);
277  }
278 }
279 #endif
280 
281  switch (xferp->cmd[0]) {
282 
284  debug("TEST_UNIT_READY");
285  if (xferp->cmd_len != 6)
286  debug(" (weird len=%i)", xferp->cmd_len);
287 
288  /* TODO: bits 765 of buf[1] contains the LUN */
289  if (xferp->cmd[1] != 0x00)
290  fatal("WARNING: TEST_UNIT_READY with cmd[1]=0x%02x"
291  " not yet implemented\n", (int)xferp->cmd[1]);
292 
293  diskimage__return_default_status_and_message(xferp);
294  break;
295 
296  case SCSICMD_INQUIRY:
297  debug("INQUIRY");
298  if (xferp->cmd_len != 6)
299  debug(" (weird len=%i)", xferp->cmd_len);
300  if (xferp->cmd[1] != 0x00) {
301  debug("WARNING: INQUIRY with cmd[1]=0x%02x not yet "
302  "implemented\n", (int)xferp->cmd[1]);
303 
304  break;
305  }
306 
307  /* Return values: */
308  retlen = xferp->cmd[4];
309  if (retlen < 36) {
310  fatal("WARNING: SCSI inquiry len=%i, <36!\n", retlen);
311  retlen = 36;
312  }
313 
314  /* Return data: */
315  scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
316  retlen, 1);
317  xferp->data_in[0] = 0x00; /* 0x00 = Direct-access disk */
318  xferp->data_in[1] = 0x00; /* 0x00 = non-removable */
319  xferp->data_in[2] = 0x02; /* SCSI-2 */
320 #if 0
321 xferp->data_in[3] = 0x02; /* Response data format = SCSI-2 */
322 #endif
323  xferp->data_in[4] = retlen - 4; /* Additional length */
324 xferp->data_in[4] = 0x2c - 4; /* Additional length */
325  xferp->data_in[6] = 0x04; /* ACKREQQ */
326  xferp->data_in[7] = 0x60; /* WBus32, WBus16 */
327 
328  /* These are padded with spaces: */
329 
330  memcpy(xferp->data_in+8, "GXemul ", 8);
331  if (diskimage_getname(cpu->machine, id,
332  type, namebuf, sizeof(namebuf))) {
333  for (size_t j=0; j<sizeof(namebuf); j++) {
334  if (namebuf[j] == 0) {
335  for (; j<sizeof(namebuf); j++)
336  namebuf[j] = ' ';
337  break;
338  }
339  }
340 
341  memcpy(xferp->data_in+16, namebuf, 16);
342  } else
343  memcpy(xferp->data_in+16, "DISK ", 16);
344  memcpy(xferp->data_in+32, "0 ", 4);
345 
346  /*
347  * Some Ultrix kernels want specific responses from
348  * the drives.
349  */
350 
351  if (machine->machine_type == MACHINE_PMAX) {
352  /* DEC, RZ25 (rev 0900) = 832527 sectors */
353  /* DEC, RZ58 (rev 2000) = 2698061 sectors */
354  memcpy(xferp->data_in+8, "DEC ", 8);
355  memcpy(xferp->data_in+16, "RZ58 (C) DEC", 16);
356  memcpy(xferp->data_in+32, "2000", 4);
357  }
358 
359  /* Some data is different for CD-ROM drives: */
360  if (d->is_a_cdrom) {
361  xferp->data_in[0] = 0x05; /* 0x05 = CD-ROM */
362  xferp->data_in[1] = 0x80; /* 0x80 = removable */
363  /* memcpy(xferp->data_in+16, "CD-ROM ", 16);*/
364 
365  if (machine->machine_type == MACHINE_PMAX) {
366  /* SONY, CD-ROM: */
367  memcpy(xferp->data_in+8, "SONY ", 8);
368  memcpy(xferp->data_in+16,
369  "CD-ROM ", 16);
370 
371  /* ... or perhaps this: */
372  memcpy(xferp->data_in+8, "DEC ", 8);
373  memcpy(xferp->data_in+16,
374  "RRD42 (C) DEC ", 16);
375  memcpy(xferp->data_in+32, "4.5d", 4);
376  } else if (machine->machine_type == MACHINE_ARC) {
377  /* NEC, CD-ROM: */
378  memcpy(xferp->data_in+8, "NEC ", 8);
379  memcpy(xferp->data_in+16,
380  "CD-ROM CDR-210P ", 16);
381  memcpy(xferp->data_in+32, "1.0 ", 4);
382  }
383  }
384 
385  /* Data for tape devices: */
386  if (d->is_a_tape) {
387  xferp->data_in[0] = 0x01; /* 0x01 = tape */
388  xferp->data_in[1] = 0x80; /* 0x80 = removable */
389  memcpy(xferp->data_in+16, "TAPE ", 16);
390 
391  if (machine->machine_type == MACHINE_PMAX) {
392  /*
393  * TODO: find out if these are correct.
394  *
395  * The name might be TZK10, TSZ07, or TLZ04,
396  * or something completely different.
397  */
398  memcpy(xferp->data_in+8, "DEC ", 8);
399  memcpy(xferp->data_in+16,
400  "TK50 (C) DEC", 16);
401  memcpy(xferp->data_in+32, "2000", 4);
402  }
403  }
404 
405  diskimage__return_default_status_and_message(xferp);
406  break;
407 
409  debug("READ_CAPACITY");
410 
411  if (xferp->cmd_len != 10)
412  fatal(" [ weird READ_CAPACITY len=%i, should be 10 ] ",
413  xferp->cmd_len);
414  else {
415  if (xferp->cmd[8] & 1) {
416  /* Partial Medium Indicator bit... TODO */
417  fatal("WARNING: READ_CAPACITY with PMI bit"
418  " set not yet implemented\n");
419  }
420  }
421 
422  /* Return data: */
423  scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
424  8, 1);
425 
427 
428  size = d->total_size / d->logical_block_size;
429  if (d->total_size & (d->logical_block_size-1))
430  size ++;
431 
432  xferp->data_in[0] = (size >> 24) & 255;
433  xferp->data_in[1] = (size >> 16) & 255;
434  xferp->data_in[2] = (size >> 8) & 255;
435  xferp->data_in[3] = size & 255;
436 
437  xferp->data_in[4] = (d->logical_block_size >> 24) & 255;
438  xferp->data_in[5] = (d->logical_block_size >> 16) & 255;
439  xferp->data_in[6] = (d->logical_block_size >> 8) & 255;
440  xferp->data_in[7] = d->logical_block_size & 255;
441 
442  diskimage__return_default_status_and_message(xferp);
443  break;
444 
445  case SCSICMD_MODE_SENSE:
446  case SCSICMD_MODE_SENSE10:
447  debug("MODE_SENSE");
448  q = 4; retlen = xferp->cmd[4];
449  switch (xferp->cmd_len) {
450  case 6: break;
451  case 10:q = 8;
452  retlen = xferp->cmd[7] * 256 + xferp->cmd[8];
453  break;
454  default:fatal(" (unimplemented mode_sense len=%i)",
455  xferp->cmd_len);
456  }
457 
458  /*
459  * NOTE/TODO: This code doesn't handle too short retlens
460  * very well. A quick hack around this is that I allocate
461  * a bit too much memory, so that nothing is actually
462  * written outside of xferp->data_in[].
463  */
464 
465  retlen += 100; /* Should be enough. (Ugly.) */
466 
467  if ((xferp->cmd[2] & 0xc0) != 0)
468  fatal("WARNING: mode sense, cmd[2] = 0x%02x\n",
469  xferp->cmd[2]);
470 
471  /* Return data: */
473  &xferp->data_in, retlen, 1);
474 
475  xferp->data_in_len -= 100; /* Restore size. */
476 
477  pagecode = xferp->cmd[2] & 0x3f;
478 
479  debug("[ MODE SENSE id %i, pagecode=%i ]\n", id, pagecode);
480 
481  /* 4 bytes of header for 6-byte command,
482  8 bytes of header for 10-byte command. */
483  xferp->data_in[0] = retlen; /* 0: mode data length */
484  xferp->data_in[1] = d->is_a_cdrom? 0x05 : 0x00;
485  /* 1: medium type */
486  xferp->data_in[2] = 0x00; /* device specific
487  parameter */
488  xferp->data_in[3] = 8 * 1; /* block descriptor
489  length: 1 page (?) */
490 
491  xferp->data_in[q+0] = 0x00; /* density code */
492  xferp->data_in[q+1] = 0; /* nr of blocks, high */
493  xferp->data_in[q+2] = 0; /* nr of blocks, mid */
494  xferp->data_in[q+3] = 0; /* nr of blocks, low */
495  xferp->data_in[q+4] = 0x00; /* reserved */
496  xferp->data_in[q+5] = (d->logical_block_size >> 16) & 255;
497  xferp->data_in[q+6] = (d->logical_block_size >> 8) & 255;
498  xferp->data_in[q+7] = d->logical_block_size & 255;
499  q += 8;
500 
501  diskimage__return_default_status_and_message(xferp);
502 
503  /* descriptors, 8 bytes (each) */
504 
505  /* page, n bytes (each) */
506  switch (pagecode) {
507  case 0:
508  /* TODO: Nothing here? */
509  break;
510  case 1: /* read-write error recovery page */
511  xferp->data_in[q + 0] = pagecode;
512  xferp->data_in[q + 1] = 10;
513  break;
514  case 3: /* format device page */
515  xferp->data_in[q + 0] = pagecode;
516  xferp->data_in[q + 1] = 22;
517 
518  /* 10,11 = sectors per track */
519  xferp->data_in[q + 10] = 0;
520  xferp->data_in[q + 11] = d->sectors_per_track;
521 
522  /* 12,13 = physical sector size */
523  xferp->data_in[q + 12] =
524  (d->logical_block_size >> 8) & 255;
525  xferp->data_in[q + 13] = d->logical_block_size & 255;
526  break;
527  case 4: /* rigid disk geometry page */
528  xferp->data_in[q + 0] = pagecode;
529  xferp->data_in[q + 1] = 22;
530  xferp->data_in[q + 2] = (d->ncyls >> 16) & 255;
531  xferp->data_in[q + 3] = (d->ncyls >> 8) & 255;
532  xferp->data_in[q + 4] = d->ncyls & 255;
533  xferp->data_in[q + 5] = d->heads;
534 
535  xferp->data_in[q + 20] = (d->rpms >> 8) & 255;
536  xferp->data_in[q + 21] = d->rpms & 255;
537  break;
538  case 5: /* flexible disk page */
539  xferp->data_in[q + 0] = pagecode;
540  xferp->data_in[q + 1] = 0x1e;
541 
542  /* 2,3 = transfer rate */
543  xferp->data_in[q + 2] = ((5000) >> 8) & 255;
544  xferp->data_in[q + 3] = (5000) & 255;
545 
546  xferp->data_in[q + 4] = d->heads;
547  xferp->data_in[q + 5] = d->sectors_per_track;
548 
549  /* 6,7 = data bytes per sector */
550  xferp->data_in[q + 6] = (d->logical_block_size >> 8)
551  & 255;
552  xferp->data_in[q + 7] = d->logical_block_size & 255;
553 
554  xferp->data_in[q + 8] = (d->ncyls >> 8) & 255;
555  xferp->data_in[q + 9] = d->ncyls & 255;
556 
557  xferp->data_in[q + 28] = (d->rpms >> 8) & 255;
558  xferp->data_in[q + 29] = d->rpms & 255;
559  break;
560  default:
561  fatal("[ MODE_SENSE for page %i is not yet "
562  "implemented! ]\n", pagecode);
563  }
564 
565  break;
566 
567  case SCSICMD_READ:
568  case SCSICMD_READ_10:
569  debug("READ");
570 
571  /*
572  * For tape devices, read data at the current position.
573  * For disk and CDROM devices, the command bytes contain
574  * an offset telling us where to read from the device.
575  */
576 
577  if (d->is_a_tape) {
578  /* bits 7..5 of cmd[1] are the LUN bits... TODO */
579 
580  size = (xferp->cmd[2] << 16) +
581  (xferp->cmd[3] << 8) +
582  xferp->cmd[4];
583 
584  /* Bit 1 of cmd[1] is the SILI bit (TODO), and
585  bit 0 is the "use fixed length" bit. */
586 
587  if (xferp->cmd[1] & 0x01) {
588  /* Fixed block length: */
589  size *= d->logical_block_size;
590  }
591 
592  if (d->filemark) {
593  /* At end of file, switch to the next
594  automagically: */
595  d->tape_filenr ++;
596  diskimage__switch_tape(d);
597 
598  d->filemark = 0;
599  }
600 
601  ofs = d->tape_offset;
602 
603  fatal("[ READ tape, id=%i file=%i, cmd[1]=%02x size=%i"
604  ", ofs=%lli ]\n", id, d->tape_filenr,
605  xferp->cmd[1], (int)size, (long long)ofs);
606  } else {
607  if (xferp->cmd[0] == SCSICMD_READ) {
608  if (xferp->cmd_len != 6)
609  debug(" (weird len=%i)",
610  xferp->cmd_len);
611 
612  /*
613  * bits 4..0 of cmd[1], and cmd[2] and cmd[3]
614  * hold the logical block address.
615  *
616  * cmd[4] holds the number of logical blocks
617  * to transfer. (Special case if the value is
618  * 0, actually means 256.)
619  */
620  ofs = ((xferp->cmd[1] & 0x1f) << 16) +
621  (xferp->cmd[2] << 8) + xferp->cmd[3];
622  retlen = xferp->cmd[4];
623  if (retlen == 0)
624  retlen = 256;
625  } else {
626  if (xferp->cmd_len != 10)
627  debug(" (weird len=%i)",
628  xferp->cmd_len);
629 
630  /*
631  * cmd[2..5] hold the logical block address.
632  * cmd[7..8] holds the number of logical
633  * blocks to transfer. (NOTE: If the value is
634  * 0, this means 0, not 65536. :-)
635  */
636  ofs = ((uint64_t)xferp->cmd[2] << 24) +
637  (xferp->cmd[3] << 16) + (xferp->cmd[4] << 8)
638  + xferp->cmd[5];
639  retlen = (xferp->cmd[7] << 8) + xferp->cmd[8];
640  }
641 
642  size = retlen * d->logical_block_size;
643  ofs *= d->logical_block_size;
644  }
645 
646  /* Return data: */
647  scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
648  size, 0);
649 
650  debug(" READ ofs=%lli size=%i\n", (long long)ofs, (int)size);
651 
652  diskimage__return_default_status_and_message(xferp);
653 
654  d->filemark = 0;
655 
656  /*
657  * Failure? Then set check condition.
658  * For tapes, error should only occur at the end of a file.
659  *
660  * "If the logical unit encounters a filemark during
661  * a READ command, CHECK CONDITION status shall be
662  * returned and the filemark and valid bits shall be
663  * set to one in the sense data. The sense key shall
664  * be set to NO SENSE"..
665  */
666  if (d->is_a_tape && d->f != NULL && feof(d->f)) {
667  debug(" feof id=%i\n", id);
668  xferp->status[0] = 0x02; /* CHECK CONDITION */
669 
670  d->filemark = 1;
671  } else
672  diskimage__internal_access(d, 0, ofs,
673  xferp->data_in, size);
674 
675  if (d->is_a_tape && d->f != NULL)
676  d->tape_offset = ftello(d->f);
677 
678  /* TODO: other errors? */
679  break;
680 
681  case SCSICMD_WRITE:
682  case SCSICMD_WRITE_10:
683  debug("WRITE");
684 
685  /* TODO: tape */
686 
687  if (xferp->cmd[0] == SCSICMD_WRITE) {
688  if (xferp->cmd_len != 6)
689  debug(" (weird len=%i)", xferp->cmd_len);
690 
691  /*
692  * bits 4..0 of cmd[1], and cmd[2] and cmd[3] hold the
693  * logical block address.
694  *
695  * cmd[4] holds the number of logical blocks to
696  * transfer. (Special case if the value is 0, actually
697  * means 256.)
698  */
699  ofs = ((xferp->cmd[1] & 0x1f) << 16) +
700  (xferp->cmd[2] << 8) + xferp->cmd[3];
701  retlen = xferp->cmd[4];
702  if (retlen == 0)
703  retlen = 256;
704  } else {
705  if (xferp->cmd_len != 10)
706  debug(" (weird len=%i)", xferp->cmd_len);
707 
708  /*
709  * cmd[2..5] hold the logical block address.
710  * cmd[7..8] holds the number of logical blocks to
711  * transfer. (NOTE: If the value is 0 this means 0,
712  * not 65536.)
713  */
714  ofs = ((uint64_t)xferp->cmd[2] << 24) +
715  (xferp->cmd[3] << 16) + (xferp->cmd[4] << 8) +
716  xferp->cmd[5];
717  retlen = (xferp->cmd[7] << 8) + xferp->cmd[8];
718  }
719 
720  size = retlen * d->logical_block_size;
721  ofs *= d->logical_block_size;
722 
723  if (xferp->data_out_offset != size) {
724  debug(", data_out == NULL, wanting %i bytes, \n\n",
725  (int)size);
726  xferp->data_out_len = size;
727  return 2;
728  }
729 
730  debug(", data_out != NULL, OK :-)");
731 
732  debug("WRITE ofs=%i size=%i offset=%i\n", (int)ofs,
733  (int)size, (int)xferp->data_out_offset);
734 
735  diskimage__internal_access(d, 1, ofs,
736  xferp->data_out, size);
737 
738  /* TODO: how about return code? */
739 
740  /* Is this really necessary? */
741  /* fsync(fileno(d->f)); */
742 
743  diskimage__return_default_status_and_message(xferp);
744  break;
745 
747  debug("SYNCHRONIZE_CACHE");
748 
749  if (xferp->cmd_len != 10)
750  debug(" (weird len=%i)", xferp->cmd_len);
751 
752  /* TODO: actualy care about cmd[] */
753  fsync(fileno(d->f));
754 
755  diskimage__return_default_status_and_message(xferp);
756  break;
757 
759  debug("START_STOP_UNIT");
760 
761  if (xferp->cmd_len != 6)
762  debug(" (weird len=%i)", xferp->cmd_len);
763 
764  for (i=0; i<(ssize_t)xferp->cmd_len; i++)
765  debug(" %02x", xferp->cmd[i]);
766 
767  /* TODO: actualy care about cmd[] */
768 
769  diskimage__return_default_status_and_message(xferp);
770  break;
771 
773  debug("REQUEST_SENSE");
774 
775  retlen = xferp->cmd[4];
776 
777  /* TODO: bits 765 of buf[1] contains the LUN */
778  if (xferp->cmd[1] != 0x00)
779  fatal("WARNING: REQUEST_SENSE with cmd[1]=0x%02x not"
780  " yet implemented\n", (int)xferp->cmd[1]);
781 
782  if (retlen < 18) {
783  fatal("WARNING: SCSI request sense len=%i, <18!\n",
784  (int)retlen);
785  retlen = 18;
786  }
787 
788  /* Return data: */
789  scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
790  retlen, 1);
791 
792  xferp->data_in[0] = 0x80 + 0x70;/* 0x80 = valid,
793  0x70 = "current errors" */
794  xferp->data_in[2] = 0x00; /* SENSE KEY! */
795 
796  if (d->filemark) {
797  xferp->data_in[2] = 0x80;
798  }
799  debug(": [2]=0x%02x ", xferp->data_in[2]);
800 
801  printf(" XXX(!) \n");
802 
803  /* TODO */
804  xferp->data_in[7] = retlen - 7; /* additional sense length */
805  /* TODO */
806 
807  diskimage__return_default_status_and_message(xferp);
808  break;
809 
811  debug("READ_BLOCK_LIMITS");
812 
813  retlen = 6;
814 
815  /* TODO: bits 765 of buf[1] contains the LUN */
816  if (xferp->cmd[1] != 0x00)
817  fatal("WARNING: READ_BLOCK_LIMITS with cmd[1]="
818  "0x%02x not yet implemented\n", (int)xferp->cmd[1]);
819 
820  /* Return data: */
821  scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in,
822  retlen, 1);
823 
824  /*
825  * data[0] is reserved, data[1..3] contain the maximum block
826  * length limit, data[4..5] contain the minimum limit.
827  */
828 
829  {
830  int max_limit = 32768;
831  int min_limit = 128;
832 
833  xferp->data_in[1] = (max_limit >> 16) & 255;
834  xferp->data_in[2] = (max_limit >> 8) & 255;
835  xferp->data_in[3] = max_limit & 255;
836  xferp->data_in[4] = (min_limit >> 8) & 255;
837  xferp->data_in[5] = min_limit & 255;
838  }
839 
840  diskimage__return_default_status_and_message(xferp);
841  break;
842 
843  case SCSICMD_REWIND:
844  debug("REWIND");
845 
846  /* TODO: bits 765 of buf[1] contains the LUN */
847  if ((xferp->cmd[1] & 0xe0) != 0x00)
848  fatal("WARNING: REWIND with cmd[1]=0x%02x not yet "
849  "implemented\n", (int)xferp->cmd[1]);
850 
851  /* Close and reopen. */
852 
853  if (d->f != NULL)
854  fclose(d->f);
855 
856  d->f = fopen(d->fname, d->writable? "r+" : "r");
857  if (d->f == NULL) {
858  fprintf(stderr, "[ diskimage: could not (re)open "
859  "'%s' ]\n", d->fname);
860  /* TODO: return error */
861  }
862 
863  d->tape_offset = 0;
864  d->tape_filenr = 0;
865  d->filemark = 0;
866 
867  diskimage__return_default_status_and_message(xferp);
868  break;
869 
870  case SCSICMD_SPACE:
871  debug("SPACE");
872 
873  /* TODO: bits 765 of buf[1] contains the LUN */
874  if ((xferp->cmd[1] & 0xe0) != 0x00)
875  fatal("WARNING: SPACE with cmd[1]=0x%02x not yet "
876  "implemented\n", (int)xferp->cmd[1]);
877 
878  /*
879  * Bits 2..0 of buf[1] contain the 'code' which describes how
880  * spacing should be done, and buf[2..4] contain the number of
881  * operations.
882  */
883  debug("[ SPACE: buf[] = %02x %02x %02x %02x %02x %02x ]\n",
884  xferp->cmd[0],
885  xferp->cmd[1],
886  xferp->cmd[2],
887  xferp->cmd[3],
888  xferp->cmd[4],
889  xferp->cmd[5]);
890 
891  switch (xferp->cmd[1] & 7) {
892  case 1: /* Seek to a different file nr: */
893  {
894  int diff = (xferp->cmd[2] << 16) +
895  (xferp->cmd[3] << 8) + xferp->cmd[4];
896 
897  /* Negative seek offset: */
898  if (diff & (1 << 23))
899  diff = - (16777216 - diff);
900 
901  d->tape_filenr += diff;
902  }
903 
904  /* At end of file, switch to the next tape file: */
905  if (d->filemark) {
906  d->tape_filenr ++;
907  d->filemark = 0;
908  }
909 
910  debug("{ switching to tape file %i }", d->tape_filenr);
911  diskimage__switch_tape(d);
912  d->filemark = 0;
913  break;
914  default:
915  fatal("[ diskimage.c: unimplemented SPACE type %i ]\n",
916  xferp->cmd[1] & 7);
917  }
918 
919  diskimage__return_default_status_and_message(xferp);
920  break;
921 
923  /*
924  * According to
925  * http://mail-index.netbsd.org/port-i386/1997/03/03/0010.html:
926  *
927  * "The READ_CD_CAPACITY, READ_SUBCHANNEL, and MODE_SELECT
928  * commands have the same opcode in SCSI or ATAPI, but don't
929  * have the same command structure"...
930  *
931  * TODO: This still doesn't work. Hm.
932  */
933  retlen = 48;
934 
935  debug("CDROM_READ_SUBCHANNEL/READ_CD_CAPACITY, cmd[1]=0x%02x",
936  xferp->cmd[1]);
937 
938  /* Return data: */
940  &xferp->data_in, retlen, 1);
941 
943 
944  size = d->total_size / d->logical_block_size;
945  if (d->total_size & (d->logical_block_size-1))
946  size ++;
947 
948  xferp->data_in[0] = (size >> 24) & 255;
949  xferp->data_in[1] = (size >> 16) & 255;
950  xferp->data_in[2] = (size >> 8) & 255;
951  xferp->data_in[3] = size & 255;
952 
953  xferp->data_in[4] = (d->logical_block_size >> 24) & 255;
954  xferp->data_in[5] = (d->logical_block_size >> 16) & 255;
955  xferp->data_in[6] = (d->logical_block_size >> 8) & 255;
956  xferp->data_in[7] = d->logical_block_size & 255;
957 
958  diskimage__return_default_status_and_message(xferp);
959  break;
960 
961  case SCSICDROM_READ_TOC:
962  debug("(CDROM_READ_TOC: ");
963  debug("lun=%i msf=%i ",
964  xferp->cmd[1] >> 5, (xferp->cmd[1] >> 1) & 1);
965  debug("starting_track=%i ", xferp->cmd[6]);
966  retlen = xferp->cmd[7] * 256 + xferp->cmd[8];
967  debug("allocation_len=%i)\n", retlen);
968 
969  /* Return data: */
971  &xferp->data_in, retlen, 1);
972 
973  xferp->data_in[0] = 0;
974  xferp->data_in[1] = 10;
975  xferp->data_in[2] = 0; /* First track. */
976  xferp->data_in[3] = 0; /* Last track. */
977 
978  /* Track 0 data: */
979  xferp->data_in[4] = 0x00; /* Reserved. */
980  xferp->data_in[5] = 0x04; /* ADR + CTRL:
981  Data, not audio */
982  xferp->data_in[6] = 0x00; /* Track nr */
983  xferp->data_in[7] = 0x00; /* Reserved */
984  /* 8..11 = absolute CDROM address */
985 
986  diskimage__return_default_status_and_message(xferp);
987  break;
988 
990  /* (Patch from Håvard Eidnes.) */
991  debug("CDROM_READ_DISCINFO, cmd[1]=0x%02x", xferp->cmd[1]);
992  retlen = 34;
994  &xferp->data_in, retlen, 1);
995 
996  /* TODO: Make this more generic! */
997  xferp->data_in[0] = retlen-2; /* length of info, excl len */
998  xferp->data_in[1] = 0; /* length of info-(len field), msb */
999  xferp->data_in[2] = 0xE; /* 11=complete ses., 10=fin disc */
1000  xferp->data_in[3] = 0; /* First track on disc */
1001  xferp->data_in[4] = 1; /* Number of sessions, lsb */
1002  xferp->data_in[5] = 0; /* first_track_last_session_lsb */
1003  xferp->data_in[6] = 0; /* last_track_last_session_lsb */
1004  xferp->data_in[7] = 0x20;/* various flags */
1005  xferp->data_in[8] = 0; /* CD-ROM disc */
1006  xferp->data_in[9] = 1; /* num sessions, msb */
1007  xferp->data_in[10] = 0; /* first_track_last_session_msb */
1008  xferp->data_in[11] = 0; /* last_track_last_session_msb */
1009 
1010  /* Lead-in data, for completed cd-rom: */
1011  for (size_t j=16; j<=23; j++)
1012  xferp->data_in[j] = 0xff;
1013 
1014  diskimage__return_default_status_and_message(xferp);
1015  break;
1016 
1018  /* (Patch from Håvard Eidnes.) */
1019  debug("CDROM_READ_TRACKINFO");
1020  retlen = 36;
1022  &xferp->data_in, retlen, 1);
1023 
1025 
1026  size = d->total_size / d->logical_block_size;
1027  if (d->total_size & (d->logical_block_size-1))
1028  size ++;
1029 
1030  /* TODO: Make more generic? */
1031  /* TODO: Don't use magic values. */
1032  xferp->data_in[0] = retlen-2; /* length of info, excl len */
1033  xferp->data_in[1] = 0; /* length of info, msb */
1034  xferp->data_in[2] = 1; /* track#, lsb */
1035  xferp->data_in[3] = 1; /* session#, lsb */
1036  xferp->data_in[4] = 0; /* reserved */
1037  xferp->data_in[5] = 0x6; /* trk mode: unintr. data,
1038  copyable */
1039  xferp->data_in[6] = 0x81; /* trk info: RT + trk mode */
1040  xferp->data_in[7] = 0x2; /* last rec=valid, next w=not
1041  valid */
1042  /*
1043  * track start, next writable, free blcks,
1044  * blocking factor
1045  */
1046  for(size_t j=8; j<=23; j++)
1047  xferp->data_in[j] = 0;
1048 
1049  /* Track size: */
1050  xferp->data_in[24] = (size >> 24) & 0xff;
1051  xferp->data_in[25] = (size >> 16) & 0xff;
1052  xferp->data_in[26] = (size >> 8) & 0xff;
1053  xferp->data_in[27] = size & 0xff;
1054 
1055  /* Last recorded address, only for dvd; zero out the rest: */
1056  for (size_t k=28; k<=35; k++)
1057  xferp->data_in[k] = 0;
1058 
1059  diskimage__return_default_status_and_message(xferp);
1060  break;
1061 
1062  case SCSICMD_MODE_SELECT:
1063  debug("[ SCSI MODE_SELECT: ");
1064 
1065  /*
1066  * TODO:
1067  *
1068  * This is super-hardcoded for NetBSD's usage of mode_select
1069  * to set the size of CDROM sectors to 2048.
1070  */
1071 
1072  if (xferp->data_out_offset == 0) {
1073  xferp->data_out_len = 12; /* TODO */
1074  debug("data_out == NULL, wanting %i bytes ]\n",
1075  (int)xferp->data_out_len);
1076  return 2;
1077  }
1078 
1079  debug("data_out!=NULL (OK), ");
1080 
1081  /* TODO: Care about cmd? */
1082 
1083  /* Set sector size to 2048: */
1084  /* 00 05 00 08 00 03 ca 40 00 00 08 00 */
1085  if (xferp->data_out[0] == 0x00 &&
1086  xferp->data_out[1] == 0x05 &&
1087  xferp->data_out[2] == 0x00 &&
1088  xferp->data_out[3] == 0x08) {
1089  d->logical_block_size =
1090  (xferp->data_out[9] << 16) +
1091  (xferp->data_out[10] << 8) +
1092  xferp->data_out[11];
1093  debug("[ setting logical_block_size to %i ]\n",
1094  d->logical_block_size);
1095  } else {
1096  int j;
1097  fatal("[ unknown MODE_SELECT: cmd =");
1098  for (j=0; j<(ssize_t)xferp->cmd_len; j++)
1099  fatal(" %02x", xferp->cmd[j]);
1100  fatal(", data_out =");
1101  for (j=0; j<(ssize_t)xferp->data_out_len; j++)
1102  fatal(" %02x", xferp->data_out[j]);
1103  fatal(" ]");
1104  }
1105 
1106  debug(" ]\n");
1107  diskimage__return_default_status_and_message(xferp);
1108  break;
1109 
1111  debug("[ SCSI 0x%02x Prevent/allow medium removal: "
1112  "TODO ]\n", xferp->cmd[0]);
1113 
1114  diskimage__return_default_status_and_message(xferp);
1115  break;
1116 
1117  case 0xbd:
1118  fatal("[ SCSI 0x%02x (len %i), TODO: ", xferp->cmd[0],
1119  xferp->cmd_len);
1120  for (i=0; i<(ssize_t)xferp->cmd_len; i++)
1121  fatal(" %02x", xferp->cmd[i]);
1122  fatal(" ]\n");
1123 
1124  /*
1125  * Used by Windows NT?
1126  *
1127  * Not documented in http://www.danbbs.dk/~dino/
1128  * SCSI/SCSI2-D.html.
1129  * Google gave the answer "MECHANISM_STATUS" for ATAPI. Hm.
1130  */
1131 
1132  if (xferp->cmd_len < 12) {
1133  fatal("WEIRD LEN?\n");
1134  retlen = 8;
1135  } else {
1136  retlen = xferp->cmd[8] * 256 + xferp->cmd[9];
1137  }
1138 
1139  /* Return data: */
1141  &xferp->data_in, retlen, 1);
1142 
1143  diskimage__return_default_status_and_message(xferp);
1144 
1145  break;
1146 
1147  default:
1148  fatal("[ UNIMPLEMENTED SCSI command 0x%02x, disk id=%i ]\n",
1149  xferp->cmd[0], id);
1150  exit(1);
1151  }
1152  debug(" ]\n");
1153 
1154  return 1;
1155 }
1156 
1157 
#define SCSICDROM_READ_DISCINFO
Definition: diskimage.h:177
void fatal(const char *fmt,...)
Definition: main.cc:152
#define SCSICMD_INQUIRY
Definition: diskimage.h:157
int is_a_cdrom
Definition: diskimage.h:79
size_t data_out_len
Definition: diskimage.h:105
#define SCSICMD_SPACE
Definition: diskimage.h:183
int diskimage_getname(struct machine *machine, int id, int type, char *buf, size_t bufsize)
Definition: diskimage.cc:1019
#define SCSICMD_MODE_SENSE
Definition: diskimage.h:164
size_t cmd_len
Definition: diskimage.h:100
#define SCSICMD_READ
Definition: diskimage.h:159
#define SCSICMD_START_STOP_UNIT
Definition: diskimage.h:165
int rpms
Definition: diskimage.h:87
#define SCSICMD_SYNCHRONIZE_CACHE
Definition: diskimage.h:169
int machine_type
Definition: machine.h:111
#define SCSICMD_MODE_SENSE10
Definition: diskimage.h:167
#define SCSICMD_TEST_UNIT_READY
Definition: diskimage.h:155
int filemark
Definition: diskimage.h:85
#define SCSICMD_READ_10
Definition: diskimage.h:160
struct machine * machine
Definition: cpu.h:328
void f(int s, int func, int only_name)
int logical_block_size
Definition: diskimage.h:76
size_t data_in_len
Definition: diskimage.h:110
#define MACHINE_PMAX
Definition: machine.h:213
int is_a_tape
Definition: diskimage.h:82
#define SCSICMD_WRITE_10
Definition: diskimage.h:162
#define SCSIBLOCKCMD_READ_CAPACITY
Definition: diskimage.h:172
unsigned char * data_out
Definition: diskimage.h:104
size_t status_len
Definition: diskimage.h:114
size_t data_out_offset
Definition: diskimage.h:106
#define SCSICDROM_READ_SUBCHANNEL
Definition: diskimage.h:175
int heads
Definition: diskimage.h:71
#define MACHINE_ARC
Definition: machine.h:218
unsigned char * status
Definition: diskimage.h:113
int id
Definition: diskimage.h:59
struct scsi_transfer * next_free
Definition: diskimage.h:94
struct diskimage * first_diskimage
Definition: machine.h:142
#define SCSICMD_REQUEST_SENSE
Definition: diskimage.h:156
unsigned char * data_in
Definition: diskimage.h:109
struct scsi_transfer * scsi_transfer_alloc(void)
#define SCSICDROM_READ_TRACKINFO
Definition: diskimage.h:178
int writable
Definition: diskimage.h:78
void scsi_transfer_free(struct scsi_transfer *p)
struct diskimage * next
Definition: diskimage.h:57
unsigned char * msg_out
Definition: diskimage.h:97
int diskimage__internal_access(struct diskimage *d, int writeflag, off_t offset, unsigned char *buf, size_t len)
Definition: diskimage.cc:547
off_t total_size
Definition: diskimage.h:74
FILE * f
Definition: diskimage.h:63
#define ENTER_SINGLE_STEPPING
Definition: debugger.h:48
size_t msg_in_len
Definition: diskimage.h:112
volatile int single_step
Definition: debugger.cc:68
#define SCSICMD_MODE_SELECT
Definition: diskimage.h:163
int type
Definition: diskimage.h:58
uint64_t tape_offset
Definition: diskimage.h:83
void scsi_transfer_allocbuf(size_t *lenp, unsigned char **pp, size_t want_len, int clearflag)
#define debug
Definition: dev_adb.cc:57
#define SCSICDROM_READ_TOC
Definition: diskimage.h:176
Definition: cpu.h:326
void diskimage_recalc_size(struct diskimage *d)
Definition: diskimage.cc:165
#define SCSICMD_READ_BLOCK_LIMITS
Definition: diskimage.h:182
#define DISKIMAGE_TYPES
Definition: diskimage.h:44
int tape_filenr
Definition: diskimage.h:84
unsigned char * msg_in
Definition: diskimage.h:111
addr & if(addr >=0x24 &&page !=NULL)
#define SCSICMD_REWIND
Definition: diskimage.h:181
char * fname
Definition: diskimage.h:62
unsigned char * cmd
Definition: diskimage.h:99
int diskimage_scsicommand(struct cpu *cpu, int id, int type, struct scsi_transfer *xferp)
#define SCSICMD_PREVENT_ALLOW_REMOVE
Definition: diskimage.h:166
#define SCSICMD_WRITE
Definition: diskimage.h:161
int sectors_per_track
Definition: diskimage.h:72
int ncyls
Definition: diskimage.h:88

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13