static int sg_io(struct file *file, request_queue_t *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time, timeout; int writing = 0, ret = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char cmd[BLK_MAX_CDB]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; if (copy_from_user(cmd, hdr->cmdp, hdr->cmd_len)) return -EFAULT; if (verify_command(file, cmd)) return -EPERM; if (hdr->dxfer_len > (q->max_hw_sectors << 9)) return -EIO; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (!rq) return -ENOMEM; /* * fill in request structure */ rq->cmd_len = hdr->cmd_len; memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ memcpy(rq->cmd, cmd, hdr->cmd_len); memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->cmd_type = REQ_TYPE_BLOCK_PC; timeout = msecs_to_jiffies(hdr->timeout); rq->timeout = (timeout < INT_MAX) ? timeout : INT_MAX; if (!rq->timeout) rq->timeout = q->sg_timeout; if (!rq->timeout) rq->timeout = BLK_DEFAULT_TIMEOUT; if (hdr->iovec_count) { const int size = sizeof(struct sg_iovec) * hdr->iovec_count; struct sg_iovec *iov; iov = kmalloc(size, GFP_KERNEL); if (!iov) { ret = -ENOMEM; goto out; } if (copy_from_user(iov, hdr->dxferp, size)) { kfree(iov); ret = -EFAULT; goto out; } ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count, hdr->dxfer_len); kfree(iov); } else if (hdr->dxfer_len) ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); if (ret) goto out; bio = rq->bio; rq->retries = 0; start_time = jiffies; /* ignore return value. All information is passed back to caller * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ blk_execute_rq(q, bd_disk, rq, 0); /* write to all output members */ hdr->status = 0xff & rq->errors; hdr->masked_status = status_byte(rq->errors); hdr->msg_status = msg_byte(rq->errors); hdr->host_status = host_byte(rq->errors); hdr->driver_status = driver_byte(rq->errors); hdr->info = 0; if (hdr->masked_status || hdr->host_status || hdr->driver_status) hdr->info |= SG_INFO_CHECK; hdr->resid = rq->data_len; hdr->duration = ((jiffies - start_time) * 1000) / HZ; hdr->sb_len_wr = 0; if (rq->sense_len && hdr->sbp) { int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len); if (!copy_to_user(hdr->sbp, rq->sense, len)) hdr->sb_len_wr = len; } if (blk_rq_unmap_user(bio)) ret = -EFAULT; /* may not have succeeded, but output values written to control * structure (struct sg_io_hdr). */ out: blk_put_request(rq); return ret; }
void scsi_print_hostbyte(int scsiresult) { printk("Hostbyte=0x%02x ", host_byte(scsiresult)); }
void scsi_show_result(int result) { printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n", host_byte(result), driver_byte(result)); }
/* Convert the result to success code */ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) { char *name = tape_name(STp); int result = SRpnt->result; u8 * sense = SRpnt->sense, scode; #if DEBUG const char *stp; #endif struct st_cmdstatus *cmdstatp; if (!result) return 0; cmdstatp = &STp->buffer->cmdstat; osst_analyze_sense(SRpnt, cmdstatp); if (cmdstatp->have_sense) scode = STp->buffer->cmdstat.sense_hdr.sense_key; else scode = 0; #if DEBUG if (debugging) { printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n", name, result, SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2], SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]); if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n", name, scode, sense[12], sense[13]); if (cmdstatp->have_sense) __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE); } else #endif if (cmdstatp->have_sense && ( scode != NO_SENSE && scode != RECOVERED_ERROR && /* scode != UNIT_ATTENTION && */ scode != BLANK_CHECK && scode != VOLUME_OVERFLOW && SRpnt->cmd[0] != MODE_SENSE && SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ if (cmdstatp->have_sense) { printk(KERN_WARNING "%s:W: Command with sense data:\n", name); __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE); } else { static int notyetprinted = 1; printk(KERN_WARNING "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n", name, result, driver_byte(result), host_byte(result)); if (notyetprinted) { notyetprinted = 0; printk(KERN_INFO "%s:I: This warning may be caused by your scsi controller,\n", name); printk(KERN_INFO "%s:I: it has been reported with some Buslogic cards.\n", name); } } } STp->pos_unknown |= STp->device->was_reset; if (cmdstatp->have_sense && scode == RECOVERED_ERROR) { STp->recover_count++; STp->recover_erreg++; #if DEBUG if (debugging) { if (SRpnt->cmd[0] == READ_6) stp = "read"; else if (SRpnt->cmd[0] == WRITE_6) stp = "write"; else stp = "ioctl"; printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp, STp->recover_count); } #endif if ((sense[2] & 0xe0) == 0) return 0; } return (-EIO); }