int read_controller(const char *device, struct controller *controller) { if (!read_capacity(device, &controller->capacity)) return 0; if (!read_color(device, "red", &controller->r)) return 0; if (!read_color(device, "green", &controller->g)) return 0; if (!read_color(device, "blue", &controller->b)) return 0; return 1; }
int get_block_size() { char buf[255]; int len,lba=0,bsize=0; read_capacity(&lba,&bsize); len=255; if (mode_sense(buf,&len)==0 && buf[3]>=8) { return V3(&buf[4+5]); } if (mode_sense10(buf,&len)==0 && V2(&buf[6])>=8) { return V3(&buf[8+5]); } if (read_capacity(&lba,&bsize)==0) { return bsize; } return -1; }
/*! Execute SCSI command */ void ata_exec_io(ide_device_info *device, ide_qrequest *qrequest) { scsi_ccb *request = qrequest->request; SHOW_FLOW(3, "command=%x", request->cdb[0]); // ATA devices have one LUN only if (request->target_lun != 0) { request->subsys_status = SCSI_SEL_TIMEOUT; finish_request(qrequest, false); return; } // starting a request means deleting sense, so don't do it if // the command wants to read it if (request->cdb[0] != SCSI_OP_REQUEST_SENSE) start_request(device, qrequest); switch (request->cdb[0]) { case SCSI_OP_TEST_UNIT_READY: ata_test_unit_ready(device, qrequest); break; case SCSI_OP_REQUEST_SENSE: ide_request_sense(device, qrequest); return; case SCSI_OP_FORMAT: /* FORMAT UNIT */ // we could forward request to disk, but modern disks cannot // be formatted anyway, so we just refuse request // (exceptions are removable media devices, but to my knowledge // they don't have to be formatted as well) set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_INQUIRY: ata_inquiry(device, qrequest); break; case SCSI_OP_MODE_SELECT_10: ata_mode_select_10(device, qrequest); break; case SCSI_OP_MODE_SENSE_10: ata_mode_sense_10(device, qrequest); break; case SCSI_OP_MODE_SELECT_6: case SCSI_OP_MODE_SENSE_6: // we've told SCSI bus manager to emulates these commands set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_RESERVE: case SCSI_OP_RELEASE: // though mandatory, this doesn't make much sense in a // single initiator environment; so what set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_START_STOP: { scsi_cmd_ssu *cmd = (scsi_cmd_ssu *)request->cdb; // with no LoEj bit set, we should only allow/deny further access // we ignore that (unsupported for ATA) // with LoEj bit set, we should additionally either load or eject the medium // (start = 0 - eject; start = 1 - load) if (!cmd->start) // we must always flush cache if start = 0 ata_flush_cache(device, qrequest); if (cmd->load_eject) ata_load_eject(device, qrequest, cmd->start); break; } case SCSI_OP_PREVENT_ALLOW: { scsi_cmd_prevent_allow *cmd = (scsi_cmd_prevent_allow *)request->cdb; ata_prevent_allow(device, cmd->prevent); break; } case SCSI_OP_READ_CAPACITY: read_capacity(device, qrequest); break; case SCSI_OP_VERIFY: // does anyone uses this function? // effectly, it does a read-and-compare, which IDE doesn't support set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_SYNCHRONIZE_CACHE: // we ignore range and immediate bit, we always immediately flush everything ata_flush_cache(device, qrequest); break; // sadly, there are two possible read/write operation codes; // at least, the third one, read/write(12), is not valid for DAS case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb; uint32 pos; size_t length; pos = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba; length = cmd->length != 0 ? cmd->length : 256; SHOW_FLOW(3, "READ6/WRITE6 pos=%lx, length=%lx", pos, length); ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_6); return; } case SCSI_OP_READ_10: case SCSI_OP_WRITE_10: { scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb; uint32 pos; size_t length; pos = B_BENDIAN_TO_HOST_INT32(cmd->lba); length = B_BENDIAN_TO_HOST_INT16(cmd->length); if (length != 0) { ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_10); } else { // we cannot transfer zero blocks (apart from LBA48) finish_request(qrequest, false); } return; } default: set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); } finish_checksense(qrequest); }
int ob_esp_init(unsigned int slot, uint64_t base, unsigned long espoffset, unsigned long dmaoffset) { int id, diskcount = 0, cdcount = 0, *counter_ptr; char nodebuff[256], aliasbuff[256]; esp_private_t *esp; unsigned int i; DPRINTF("Initializing SCSI..."); esp = malloc(sizeof(esp_private_t)); if (!esp) { DPRINTF("Can't allocate ESP private structure\n"); return -1; } global_esp = esp; if (espdma_init(slot, base, dmaoffset, &esp->espdma) != 0) { return -1; } /* Get the IO region */ esp->ll = (void *)ofmem_map_io(base + (uint64_t)espoffset, sizeof(struct esp_regs)); if (esp->ll == NULL) { DPRINTF("Can't map ESP registers\n"); return -1; } esp->buffer = (void *)dvma_alloc(BUFSIZE, &esp->buffer_dvma); if (!esp->buffer || !esp->buffer_dvma) { DPRINTF("Can't get a DVMA buffer\n"); return -1; } // Chip reset esp->ll->regs[ESP_CMD] = ESP_CMD_RC; DPRINTF("ESP at 0x%lx, buffer va 0x%lx dva 0x%lx\n", (unsigned long)esp, (unsigned long)esp->buffer, (unsigned long)esp->buffer_dvma); DPRINTF("done\n"); DPRINTF("Initializing SCSI devices..."); for (id = 0; id < 8; id++) { esp->sd[id].id = id; if (!inquiry(esp, &esp->sd[id])) { DPRINTF("Unit %d not present\n", id); continue; } /* Clear Unit Attention condition from reset */ for (i = 0; i < 5; i++) { if (test_unit_ready(esp, &esp->sd[id])) { break; } } if (i == 5) { DPRINTF("Unit %d present but won't become ready\n", id); continue; } DPRINTF("Unit %d present\n", id); read_capacity(esp, &esp->sd[id]); #ifdef CONFIG_DEBUG_ESP dump_drive(&esp->sd[id]); #endif } REGISTER_NAMED_NODE(ob_esp, "/iommu/sbus/espdma/esp"); device_end(); /* set reg */ push_str("/iommu/sbus/espdma/esp"); fword("find-device"); PUSH(slot); fword("encode-int"); PUSH(espoffset); fword("encode-int"); fword("encode+"); PUSH(0x00000010); fword("encode-int"); fword("encode+"); push_str("reg"); fword("property"); PUSH(0x02625a00); fword("encode-int"); push_str("clock-frequency"); fword("property"); for (id = 0; id < 8; id++) { if (!esp->sd[id].present) continue; push_str("/iommu/sbus/espdma/esp"); fword("find-device"); fword("new-device"); push_str("sd"); fword("device-name"); push_str("block"); fword("device-type"); fword("is-deblocker"); PUSH(id); fword("encode-int"); PUSH(0); fword("encode-int"); fword("encode+"); push_str("reg"); fword("property"); fword("finish-device"); snprintf(nodebuff, sizeof(nodebuff), "/iommu/sbus/espdma/esp/sd@%d,0", id); REGISTER_NODE_METHODS(ob_sd, nodebuff); if (esp->sd[id].media == TYPE_ROM) { counter_ptr = &cdcount; } else { counter_ptr = &diskcount; } if (*counter_ptr == 0) { add_alias(nodebuff, esp->sd[id].media_str[0]); add_alias(nodebuff, esp->sd[id].media_str[1]); } snprintf(aliasbuff, sizeof(aliasbuff), "%s%d", esp->sd[id].media_str[0], *counter_ptr); add_alias(nodebuff, aliasbuff); snprintf(aliasbuff, sizeof(aliasbuff), "%s%d", esp->sd[id].media_str[1], *counter_ptr); add_alias(nodebuff, aliasbuff); snprintf(aliasbuff, sizeof(aliasbuff), "sd(0,%d,0)", id); add_alias(nodebuff, aliasbuff); snprintf(aliasbuff, sizeof(aliasbuff), "sd(0,%d,0)@0,0", id); add_alias(nodebuff, aliasbuff); (*counter_ptr)++; } DPRINTF("done\n"); return 0; }
int main(int argc, char * argv[]) { int skip = 0; int seek = 0; int ibs = 0; int obs = 0; char str[STR_SZ]; char * key; char * buf; char inf[INOUTF_SZ]; char outf[INOUTF_SZ]; int res, k; int in_num_sect = 0; int out_num_sect = 0; int num_threads = DEF_NUM_THREADS; int gen = 0; int do_time = 0; int in_sect_sz, out_sect_sz, first_xfer, qstate, req_index, seek_skip; int blocks, stop_after_write, terminate; char ebuff[EBUFF_SZ]; Rq_elem * rep; struct timeval start_tm, end_tm; memset(&rcoll, 0, sizeof(Rq_coll)); rcoll.bpt = DEF_BLOCKS_PER_TRANSFER; rcoll.in_type = FT_OTHER; rcoll.out_type = FT_OTHER; inf[0] = '\0'; outf[0] = '\0'; if (argc < 2) { usage(); return 1; } for(k = 1; k < argc; k++) { if (argv[k]) strncpy(str, argv[k], STR_SZ); else continue; for(key = str, buf = key; *buf && *buf != '=';) buf++; if (*buf) *buf++ = '\0'; if (strcmp(key,"if") == 0) strncpy(inf, buf, INOUTF_SZ); else if (strcmp(key,"of") == 0) strncpy(outf, buf, INOUTF_SZ); else if (0 == strcmp(key,"ibs")) ibs = sg_get_num(buf); else if (0 == strcmp(key,"obs")) obs = sg_get_num(buf); else if (0 == strcmp(key,"bs")) rcoll.bs = sg_get_num(buf); else if (0 == strcmp(key,"bpt")) rcoll.bpt = sg_get_num(buf); else if (0 == strcmp(key,"skip")) skip = sg_get_num(buf); else if (0 == strcmp(key,"seek")) seek = sg_get_num(buf); else if (0 == strcmp(key,"count")) dd_count = sg_get_num(buf); else if (0 == strcmp(key,"dio")) rcoll.dio = sg_get_num(buf); else if (0 == strcmp(key,"thr")) num_threads = sg_get_num(buf); else if (0 == strcmp(key,"coe")) rcoll.coe = sg_get_num(buf); else if (0 == strcmp(key,"gen")) gen = sg_get_num(buf); else if (0 == strncmp(key,"deb", 3)) rcoll.debug = sg_get_num(buf); else if (0 == strcmp(key,"time")) do_time = sg_get_num(buf); else if (0 == strncmp(key, "--vers", 6)) { fprintf(stderr, "sgq_dd for sg version 3 driver: %s\n", version_str); return 0; } else { fprintf(stderr, "Unrecognized argument '%s'\n", key); usage(); return 1; } } if (rcoll.bs <= 0) { rcoll.bs = DEF_BLOCK_SIZE; fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n", rcoll.bs); } if ((ibs && (ibs != rcoll.bs)) || (obs && (obs != rcoll.bs))) { fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(); return 1; } if ((skip < 0) || (seek < 0)) { fprintf(stderr, "skip and seek cannot be negative\n"); return 1; } if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) { fprintf(stderr, "too few or too many threads requested\n"); usage(); return 1; } if (rcoll.debug) fprintf(stderr, "sgq_dd: if=%s skip=%d of=%s seek=%d count=%d\n", inf, skip, outf, seek, dd_count); install_handler (SIGINT, interrupt_handler); install_handler (SIGQUIT, interrupt_handler); install_handler (SIGPIPE, interrupt_handler); install_handler (SIGUSR1, siginfo_handler); rcoll.infd = STDIN_FILENO; rcoll.outfd = STDOUT_FILENO; if (inf[0] && ('-' != inf[0])) { rcoll.in_type = dd_filetype(inf); if (FT_SG == rcoll.in_type) { if ((rcoll.infd = open(inf, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for sg reading", inf); perror(ebuff); return 1; } } if (FT_SG != rcoll.in_type) { if ((rcoll.infd = open(inf, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for reading", inf); perror(ebuff); return 1; } else if (skip > 0) { loff_t offset = skip; offset *= rcoll.bs; /* could exceed 32 here! */ if (lseek(rcoll.infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: couldn't skip to required position on %s", inf); perror(ebuff); return 1; } } } } if (outf[0] && ('-' != outf[0])) { rcoll.out_type = dd_filetype(outf); if (FT_SG == rcoll.out_type) { if ((rcoll.outfd = open(outf, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for sg writing", outf); perror(ebuff); return 1; } } else { if (FT_OTHER == rcoll.out_type) { if ((rcoll.outfd = open(outf, O_WRONLY | O_CREAT, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for writing", outf); perror(ebuff); return 1; } } else { if ((rcoll.outfd = open(outf, O_WRONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for raw writing", outf); perror(ebuff); return 1; } } if (seek > 0) { loff_t offset = seek; offset *= rcoll.bs; /* could exceed 32 bits here! */ if (lseek(rcoll.outfd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: couldn't seek to required position on %s", outf); perror(ebuff); return 1; } } } } if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) { fprintf(stderr, "Disallow both if and of to be stdin and stdout"); return 1; } if ((FT_OTHER == rcoll.in_type) && (FT_OTHER == rcoll.out_type) && !gen) { fprintf(stderr, "Either 'if' or 'of' must be a sg or raw device\n"); return 1; } if (0 == dd_count) return 0; else if (dd_count < 0) { if (FT_SG == rcoll.in_type) { res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz); if (2 == res) { fprintf(stderr, "Unit attention, media changed(in), repeat\n"); res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz); } if (0 != res) { fprintf(stderr, "Unable to read capacity on %s\n", inf); in_num_sect = -1; } else { if (in_num_sect > skip) in_num_sect -= skip; } } if (FT_SG == rcoll.out_type) { res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz); if (2 == res) { fprintf(stderr, "Unit attention, media changed(out), " "repeat\n"); res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { fprintf(stderr, "Unable to read capacity on %s\n", outf); out_num_sect = -1; } else { if (out_num_sect > seek) out_num_sect -= seek; } } if (in_num_sect > 0) { if (out_num_sect > 0) dd_count = (in_num_sect > out_num_sect) ? out_num_sect : in_num_sect; else dd_count = in_num_sect; } else dd_count = out_num_sect; } if (rcoll.debug > 1) fprintf(stderr, "Start of loop, count=%d, in_num_sect=%d, " "out_num_sect=%d\n", dd_count, in_num_sect, out_num_sect); if (dd_count <= 0) { fprintf(stderr, "Couldn't calculate count, please give one\n"); return 1; } rcoll.in_count = dd_count; rcoll.in_done_count = dd_count; rcoll.skip = skip; rcoll.in_blk = skip; rcoll.out_count = dd_count; rcoll.out_done_count = dd_count; rcoll.seek = seek; rcoll.out_blk = seek; if ((FT_SG == rcoll.in_type) || (FT_SG == rcoll.out_type)) rcoll.num_rq_elems = num_threads; else rcoll.num_rq_elems = 1; if (prepare_rq_elems(&rcoll, inf, outf)) { fprintf(stderr, "Setup failure, perhaps no memory\n"); return 1; } first_xfer = 1; stop_after_write = 0; terminate = 0; seek_skip = rcoll.seek - rcoll.skip; if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); } while (rcoll.out_done_count > 0) { /* >>>>>>>>> main loop */ req_index = -1; qstate = decider(&rcoll, first_xfer, &req_index); rep = (req_index < 0) ? NULL : (rcoll.req_arr + req_index); switch (qstate) { case QS_IDLE: if ((NULL == rep) || (rcoll.in_count <= 0)) { /* usleep(1000); */ /* do_poll(&rcoll, 10, NULL); */ /* do_poll(&rcoll, 0, NULL); */ break; } if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: non-sleeping QS_IDLE state, " "req_index=%d\n", req_index); if (first_xfer >= 2) first_xfer = 0; else if (1 == first_xfer) ++first_xfer; if (stop_after_write) { terminate = 1; break; } blocks = (rcoll.in_count > rcoll.bpt) ? rcoll.bpt : rcoll.in_count; rep->wr = 0; rep->blk = rcoll.in_blk; rep->num_blks = blocks; rcoll.in_blk += blocks; rcoll.in_count -= blocks; if (FT_SG == rcoll.in_type) { res = sg_start_io(rep); if (0 != res) { if (1 == res) fprintf(stderr, "Out of memory starting sg io\n"); terminate = 1; } } else { res = normal_in_operation(&rcoll, rep, blocks); if (res < 0) terminate = 1; else if (res > 0) stop_after_write = 1; } break; case QS_IN_FINISHED: if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: state is QS_IN_FINISHED, " "req_index=%d\n", req_index); if ((rep->blk + seek_skip) != rcoll.out_blk) { /* if write would be out of sequence then wait */ if (rcoll.debug > 4) fprintf(stderr, " sgq_dd: QS_IN_FINISHED, " "out of sequence\n"); usleep(200); break; } rep->wr = 1; rep->blk = rcoll.out_blk; blocks = rep->num_blks; rcoll.out_blk += blocks; rcoll.out_count -= blocks; if (FT_SG == rcoll.out_type) { res = sg_start_io(rep); if (0 != res) { if (1 == res) fprintf(stderr, "Out of memory starting sg io\n"); terminate = 1; } } else { if (normal_out_operation(&rcoll, rep, blocks) < 0) terminate = 1; } break; case QS_IN_POLL: if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: state is QS_IN_POLL, " "req_index=%d\n", req_index); res = sg_fin_in_operation(&rcoll, rep); if (res < 0) terminate = 1; else if (res > 1) { if (first_xfer) { /* only retry on first xfer */ if (0 != sg_start_io(rep)) terminate = 1; } else terminate = 1; } break; case QS_OUT_POLL: if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: state is QS_OUT_POLL, " "req_index=%d\n", req_index); res = sg_fin_out_operation(&rcoll, rep); if (res < 0) terminate = 1; else if (res > 1) { if (first_xfer) { /* only retry on first xfer */ if (0 != sg_start_io(rep)) terminate = 1; } else terminate = 1; } break; default: if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: state is ?????\n"); terminate = 1; break; } if (terminate) break; } /* >>>>>>>>>>>>> end of main loop */ if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) { struct timeval res_tm; double a, b; gettimeofday(&end_tm, NULL); res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec; res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec; if (res_tm.tv_usec < 0) { --res_tm.tv_sec; res_tm.tv_usec += 1000000; } a = res_tm.tv_sec; a += (0.000001 * res_tm.tv_usec); b = (double)rcoll.bs * (dd_count - rcoll.out_done_count); printf("time to transfer data was %d.%06d secs", (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((a > 0.00001) && (b > 511)) printf(", %.2f MB/sec\n", b / (a * 1000000.0)); else printf("\n"); } if (STDIN_FILENO != rcoll.infd) close(rcoll.infd); if (STDOUT_FILENO != rcoll.outfd) close(rcoll.outfd); res = 0; if (0 != rcoll.out_count) { fprintf(stderr, ">>>> Some error occurred,\n"); res = 2; } print_stats(); if (rcoll.dio_incomplete) { int fd; char c; fprintf(stderr, ">> Direct IO requested but incomplete %d times\n", rcoll.dio_incomplete); if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) fprintf(stderr, ">>> %s set to '0' but should be set " "to '1' for direct IO\n", proc_allow_dio); } close(fd); } } if (rcoll.sum_of_resids) fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", rcoll.sum_of_resids); return res; }