/* util - Common SCSI utility routines. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #define PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E #define START_STOP_UNIT 0x1B void swap_bytes(ulong_t *data_buffer, ulong_t n_longs) { ulong_t *end = data_buffer + n_longs; do *data_buffer = ((*data_buffer >> 8) & 0x00FF00FF) | ((*data_buffer << 8) & 0xFF00FF00); while (++data_buffer < end); } boolean_t check_status(dsreq_t *dsp, const char *detail) { unchar status = STATUS(dsp); if ((status == STA_GOOD) || (status == STA_IGOOD)) return B_FALSE; printf("\n%s - error status: ", detail); switch (status) { case STA_CHECK: { char *msg = 0; unchar key = SENSEKEY(SENSEBUF(dsp)); unchar asc = ADDSENSECODE(SENSEBUF(dsp)); unchar ascq = SENSEBUF(dsp)[13]; switch (key) { case 0x00: msg = "No Sense"; break; case 0x01: msg = "Recovered Error"; break; case 0x02: msg = "Not ready"; break; case 0x03: msg = "Medium Error"; break; case 0x04: msg = "Hardware Error"; break; case 0x05: msg = "Illegal Request"; break; case 0x06: msg = "Unit Attention"; break; case 0x07: msg = "Data Protect"; break; case 0x08: msg = "Blank Check"; break; case 0x09: msg = ""; break; case 0x0A: msg = "Copy Aborted"; break; case 0x0B: msg = "Aborted Command"; break; case 0x0C: msg = "Equal"; break; case 0x0D: msg = "Volume overflow"; break; case 0x0E: msg = "Miscompare"; break; case 0x0F: msg = ""; break; default: msg = "??"; } printf("Asc=0x%.2X, Ascq=0x%.2X, key=0x%.2X(%s).\n", asc, ascq, key, msg); } break; case STA_BUSY: printf("unit busy.\n"); break; case STA_RESERV: printf("reserved.\n"); break; default: printf("status = 0x%.2X.\n", status); break; } return B_TRUE; } void display_progress(uint_t verbose, ulong_t total_written, ulong_t total_bytes, ulong_t buffer_size, ulong_t buffer_room) { if (verbose > 0) { if (total_bytes < 100) total_bytes = 100; if (buffer_size < 1) buffer_size = 1; printf("\r %u MB = %u%%, Buffer %d%%. ", total_written / MB, total_written / (total_bytes / 100), (buffer_size-buffer_room) * 100 / buffer_size); putchar(verbose > 1? '\n' : '\r'); fflush(stdout); } } void eject_disc(dsreq_t *dsp) { fillg0cmd(dsp, (unchar *)CMDBUF(dsp), START_STOP_UNIT, 0, 0, 0, 1<<1, 0); filldsreq(dsp, 0, 0, DSRQ_SENSE); doscsireq(getfd(dsp), dsp); } boolean_t find_device(char *dev, uint_t verbose, dsreq_t **dspp, char *device_id) { char devn[] = "/dev/scsi/sc%dd%dl0"; if (dev == 0) { int bus = 0, id; do { id = 1; do { sprintf(devn, "/dev/scsi/sc%dd%dl0", bus, id); errno = 0; *dspp = dsopen(devn, O_RDWR|O_EXCL); if (*dspp == 0) { if (verbose > 1) perror(devn); } else { if (!identify_device(*dspp, device_id)) { if (verbose > 0) printf("Using device '%s'.\n", devn); return B_FALSE; } dsclose(*dspp); } id++; } while ((errno != ENOENT) || (id < 15)); bus++; } while ((errno != ENOENT) || (bus < 2)); fprintf(stderr, "Unable to find a supported and available device.\n"); return B_TRUE; } else { int id = atoi(dev); if ((id > 0) && (id <= 15)) { sprintf(devn, "/dev/scsi/sc0d%dl0", id); dev = devn; } *dspp = dsopen(dev, O_RDWR|O_EXCL); if (*dspp == 0) { perror(dev); return B_TRUE; } if (identify_device(*dspp, device_id)) { fprintf(stderr, "Device '%s' is not a supported device.\n", dev); dsclose(*dspp); return B_TRUE; } } return B_FALSE; } void mode_select(struct dsreq *dsp, caddr_t data, ulong_t datalen) { fillg0cmd(dsp, (unchar *)CMDBUF(dsp), G0_MSEL, 0x10, 0, 0, B1(datalen), 0); filldsreq(dsp, (unchar *)data, datalen, DSRQ_WRITE|DSRQ_SENSE); doscsireq(getfd(dsp), dsp); } boolean_t prevent_removal(dsreq_t *dsp, boolean_t prevent) { fillg0cmd(dsp, (unchar *)CMDBUF(dsp), PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, (unsigned)prevent, 0); filldsreq(dsp, 0, 0, DSRQ_SENSE); doscsireq(getfd(dsp), dsp); return check_status(dsp, "Prevent/Allow Removal"); } boolean_t read_block(int *file_list, uint_t n_files, ulong_t read_size, unchar *data_buffer) { static uint_t file_no = 0; ulong_t ofs = 0; long len; do { len = read(file_list[file_no], data_buffer + ofs, read_size - ofs); if (len < 0) { perror("Read"); return B_TRUE; } if (len == 0) { file_no++; if (file_no == n_files) { fprintf(stderr, "Internal error - not enough data on image files.\n"); return B_TRUE; } } else ofs += len; } while (ofs < read_size); return B_FALSE; } void report_sizes(ulong_t capacity, ulong_t total_bytes, uint_t block_length, uint_t speed) { printf(" disc capacity image size unused\n"); printf("bytes%12u%13u%10d\n", capacity, total_bytes, capacity - total_bytes); capacity /= block_length; total_bytes /= block_length; printf("MSF %.2u:%.2u:%.2u %.2u:%.2u:%.2u ", MINUTE(capacity), SECOND(capacity), FRAME(capacity), MINUTE(total_bytes), SECOND(total_bytes), FRAME(total_bytes)); if (capacity < total_bytes) printf("-%.2u:%.2u:%.2u\n", MINUTE(total_bytes - capacity), SECOND(total_bytes - capacity), FRAME(total_bytes - capacity)); else printf(" %.2u:%.2u:%.2u\n", MINUTE(capacity - total_bytes), SECOND(capacity - total_bytes), FRAME(capacity - total_bytes)); printf("%u MB of image data at %ux speed = approx. %u min.\n", total_bytes * block_length / MB, speed, total_bytes / (60 * FRAMES_PER_SECOND * speed) + 2); } boolean_t wait_ready(dsreq_t *dsp, uint_t verbose) { uint_t retry; for (retry = 1; retry < 10; retry++) { testunitready00(dsp); if (STATUS(dsp) == STA_GOOD) return B_FALSE; } if (verbose > 0) printf("Waiting for drive to become ready.\n"); for (retry = 1; retry < 60; retry++) { sleep(1); testunitready00(dsp); if (STATUS(dsp) == STA_GOOD) return B_FALSE; } fprintf(stderr, "Drive not ready.\n"); return B_TRUE; }