static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, int timeout, int retries) { struct scsi_request *sreq; int result; SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); sreq = scsi_allocate_request(sdev, GFP_KERNEL); if (!sreq) { printk("SCSI internal ioctl failed, no memory\n"); return -ENOMEM; } sreq->sr_data_direction = DMA_NONE; scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); if (driver_byte(sreq->sr_result)) { switch (sreq->sr_sense_buffer[2] & 0xf) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) sdev->lockable = 0; else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); break; case NOT_READY: /* This happens if there is no disc in drive */ if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); break; } case UNIT_ATTENTION: if (sdev->removable) { sdev->changed = 1; sreq->sr_result = 0; /* This is no longer considered an error */ break; } default: /* Fall through for non-removable media */ printk("SCSI error: host %d id %d lun %d return code = %x\n", sdev->host->host_no, sdev->id, sdev->lun, sreq->sr_result); printk("\tSense class %x, sense error %x, extended sense %x\n", sense_class(sreq->sr_sense_buffer[0]), sense_error(sreq->sr_sense_buffer[0]), sreq->sr_sense_buffer[2] & 0xf); } } result = sreq->sr_result; SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); scsi_release_request(sreq); return result; }
static int ioctl_internal_command(Scsi_Device * dev, char *cmd, int timeout, int retries) { int result; Scsi_Request *SRpnt; Scsi_Device *SDpnt; SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0])); if (NULL == (SRpnt = scsi_allocate_request(dev))) { printk("SCSI internal ioctl failed, no memory\n"); return -ENOMEM; } SRpnt->sr_data_direction = SCSI_DATA_NONE; scsi_wait_req(SRpnt, cmd, NULL, 0, timeout, retries); SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SRpnt->sr_result)); if (driver_byte(SRpnt->sr_result) != 0) switch (SRpnt->sr_sense_buffer[2] & 0xf) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0; else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); break; case NOT_READY: /* This happens if there is no disc in drive */ if (dev->removable && (cmd[0] != TEST_UNIT_READY)) { printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); break; } case UNIT_ATTENTION: if (dev->removable) { dev->changed = 1; SRpnt->sr_result = 0; /* This is no longer considered an error */ /* gag this error, VFS will log it anyway /axboe */ /* printk(KERN_INFO "Disc change detected.\n"); */ break; }; default: /* Fall through for non-removable media */ printk("SCSI error: host %d id %d lun %d return code = %x\n", dev->host->host_no, dev->id, dev->lun, SRpnt->sr_result); printk("\tSense class %x, sense error %x, extended sense %x\n", sense_class(SRpnt->sr_sense_buffer[0]), sense_error(SRpnt->sr_sense_buffer[0]), SRpnt->sr_sense_buffer[2] & 0xf); }; result = SRpnt->sr_result; SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); SDpnt = SRpnt->sr_device; scsi_release_request(SRpnt); SRpnt = NULL; return result; }
int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) { char *buf; unsigned char cmd[MAX_COMMAND_SIZE]; char *cmd_in; Scsi_Request *SRpnt; Scsi_Device *SDpnt; unsigned char opcode; unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; int timeout, retries, result; int data_direction, gfp_mask = GFP_KERNEL; if (!sic) return -EINVAL; if (dev->host->unchecked_isa_dma) gfp_mask |= GFP_DMA; /* * Verify that we can read at least this much. */ if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) return -EFAULT; if(__get_user(inlen, &sic->inlen)) return -EFAULT; if(__get_user(outlen, &sic->outlen)) return -EFAULT; /* * We do not transfer more than MAX_BUF with this interface. * If the user needs to transfer more data than this, they * should use scsi_generics (sg) instead. */ if (inlen > MAX_BUF) return -EINVAL; if (outlen > MAX_BUF) return -EINVAL; cmd_in = sic->data; if(get_user(opcode, cmd_in)) return -EFAULT; needed = buf_needed = (inlen > outlen ? inlen : outlen); if (buf_needed) { buf_needed = (buf_needed + 511) & ~511; if (buf_needed > MAX_BUF) buf_needed = MAX_BUF; buf = (char *) kmalloc(buf_needed, gfp_mask); if (!buf) return -ENOMEM; memset(buf, 0, buf_needed); if( inlen == 0 ) { data_direction = SCSI_DATA_READ; } else if (outlen == 0 ) { data_direction = SCSI_DATA_WRITE; } else { /* * Can this ever happen? */ data_direction = SCSI_DATA_UNKNOWN; } } else { buf = NULL; data_direction = SCSI_DATA_NONE; } /* * Obtain the command from the user's address space. */ cmdlen = COMMAND_SIZE(opcode); result = -EFAULT; if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen)) goto error; if(__copy_from_user(cmd, cmd_in, cmdlen)) goto error; /* * Obtain the data to be sent to the device (if any). */ if(copy_from_user(buf, cmd_in + cmdlen, inlen)) goto error; /* * Set the lun field to the correct value. */ if (dev->scsi_level <= SCSI_2) cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5); switch (opcode) { case FORMAT_UNIT: timeout = FORMAT_UNIT_TIMEOUT; retries = 1; break; case START_STOP: timeout = START_STOP_TIMEOUT; retries = NORMAL_RETRIES; break; case MOVE_MEDIUM: timeout = MOVE_MEDIUM_TIMEOUT; retries = NORMAL_RETRIES; break; case READ_ELEMENT_STATUS: timeout = READ_ELEMENT_STATUS_TIMEOUT; retries = NORMAL_RETRIES; break; case READ_DEFECT_DATA: timeout = READ_DEFECT_DATA_TIMEOUT; retries = 1; break; default: timeout = IOCTL_NORMAL_TIMEOUT; retries = NORMAL_RETRIES; break; } #ifndef DEBUG_NO_CMD SRpnt = scsi_allocate_request(dev); if( SRpnt == NULL ) { result = -EINTR; goto error; } SRpnt->sr_data_direction = data_direction; scsi_wait_req(SRpnt, cmd, buf, needed, timeout, retries); /* * If there was an error condition, pass the info back to the user. */ result = SRpnt->sr_result; if (SRpnt->sr_result) { int sb_len = sizeof(SRpnt->sr_sense_buffer); sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; if (copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len)) result = -EFAULT; } else { if (copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; } SDpnt = SRpnt->sr_device; scsi_release_request(SRpnt); SRpnt = NULL; error: if (buf) kfree(buf); return result; #else { int i; printk("scsi_ioctl : device %d. command = ", dev->id); for (i = 0; i < cmdlen; ++i) printk("%02x ", cmd[i]); printk("\nbuffer ="); for (i = 0; i < 20; ++i) printk("%02x ", buf[i]); printk("\n"); printk("inlen = %d, outlen = %d, cmdlen = %d\n", inlen, outlen, cmdlen); printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); } return 0; #endif }
static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, int timeout, int retries) { struct scsi_request *sreq; int result; struct scsi_sense_hdr sshdr; SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); sreq = scsi_allocate_request(sdev, GFP_KERNEL); if (!sreq) { printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n"); return -ENOMEM; } sreq->sr_data_direction = DMA_NONE; scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && (scsi_request_normalize_sense(sreq, &sshdr))) { switch (sshdr.sense_key) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) sdev->lockable = 0; else printk(KERN_INFO "ioctl_internal_command: " "ILLEGAL REQUEST asc=0x%x ascq=0x%x\n", sshdr.asc, sshdr.ascq); break; case NOT_READY: /* This happens if there is no disc in drive */ if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { printk(KERN_INFO "Device not ready. Make sure" " there is a disc in the drive.\n"); break; } case UNIT_ATTENTION: if (sdev->removable) { sdev->changed = 1; sreq->sr_result = 0; /* This is no longer considered an error */ break; } default: /* Fall through for non-removable media */ printk(KERN_INFO "ioctl_internal_command: <%d %d %d " "%d> return code = %x\n", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun, sreq->sr_result); scsi_print_req_sense(" ", sreq); break; } } result = sreq->sr_result; SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); scsi_release_request(sreq); return result; }
int scsi_ioctl_send_command(struct scsi_device *sdev, struct scsi_ioctl_command __user *sic) { char *buf; unsigned char cmd[MAX_COMMAND_SIZE]; char __user *cmd_in; struct scsi_request *sreq; unsigned char opcode; unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; int timeout, retries, result; int data_direction, gfp_mask = GFP_KERNEL; if (!sic) return -EINVAL; if (sdev->host->unchecked_isa_dma) gfp_mask |= GFP_DMA; /* * Verify that we can read at least this much. */ if (!access_ok(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) return -EFAULT; if(__get_user(inlen, &sic->inlen)) return -EFAULT; if(__get_user(outlen, &sic->outlen)) return -EFAULT; /* * We do not transfer more than MAX_BUF with this interface. * If the user needs to transfer more data than this, they * should use scsi_generics (sg) instead. */ if (inlen > MAX_BUF) return -EINVAL; if (outlen > MAX_BUF) return -EINVAL; cmd_in = sic->data; if(get_user(opcode, cmd_in)) return -EFAULT; needed = buf_needed = (inlen > outlen ? inlen : outlen); if (buf_needed) { buf_needed = (buf_needed + 511) & ~511; if (buf_needed > MAX_BUF) buf_needed = MAX_BUF; buf = kmalloc(buf_needed, gfp_mask); if (!buf) return -ENOMEM; memset(buf, 0, buf_needed); if (inlen == 0) { data_direction = DMA_FROM_DEVICE; } else if (outlen == 0 ) { data_direction = DMA_TO_DEVICE; } else { /* * Can this ever happen? */ data_direction = DMA_BIDIRECTIONAL; } } else { buf = NULL; data_direction = DMA_NONE; } /* * Obtain the command from the user's address space. */ cmdlen = COMMAND_SIZE(opcode); result = -EFAULT; if (!access_ok(VERIFY_READ, cmd_in, cmdlen + inlen)) goto error; if(__copy_from_user(cmd, cmd_in, cmdlen)) goto error; /* * Obtain the data to be sent to the device (if any). */ if(copy_from_user(buf, cmd_in + cmdlen, inlen)) goto error; switch (opcode) { case SEND_DIAGNOSTIC: case FORMAT_UNIT: timeout = FORMAT_UNIT_TIMEOUT; retries = 1; break; case START_STOP: timeout = START_STOP_TIMEOUT; retries = NORMAL_RETRIES; break; case MOVE_MEDIUM: timeout = MOVE_MEDIUM_TIMEOUT; retries = NORMAL_RETRIES; break; case READ_ELEMENT_STATUS: timeout = READ_ELEMENT_STATUS_TIMEOUT; retries = NORMAL_RETRIES; break; case READ_DEFECT_DATA: timeout = READ_DEFECT_DATA_TIMEOUT; retries = 1; break; default: timeout = IOCTL_NORMAL_TIMEOUT; retries = NORMAL_RETRIES; break; } sreq = scsi_allocate_request(sdev, GFP_KERNEL); if (!sreq) { result = -EINTR; goto error; } sreq->sr_data_direction = data_direction; scsi_wait_req(sreq, cmd, buf, needed, timeout, retries); /* * If there was an error condition, pass the info back to the user. */ result = sreq->sr_result; if (result) { int sb_len = sizeof(sreq->sr_sense_buffer); sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; if (copy_to_user(cmd_in, sreq->sr_sense_buffer, sb_len)) result = -EFAULT; } else { if (copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; } scsi_release_request(sreq); error: kfree(buf); return result; }
int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) { struct scsi_request *SRpnt; struct scsi_device *SDev; struct request *req; int result, err = 0, retries = 0; SDev = cd->device; SRpnt = scsi_allocate_request(SDev, GFP_KERNEL); if (!SRpnt) { printk(KERN_ERR "Unable to allocate SCSI request in sr_do_ioctl"); err = -ENOMEM; goto out; } SRpnt->sr_data_direction = cgc->data_direction; retry: if (!scsi_block_when_processing_errors(SDev)) { err = -ENODEV; goto out_free; } scsi_wait_req(SRpnt, cgc->cmd, cgc->buffer, cgc->buflen, cgc->timeout, IOCTL_RETRIES); req = SRpnt->sr_request; if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) { memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen); kfree(SRpnt->sr_buffer); SRpnt->sr_buffer = req->buffer; } result = SRpnt->sr_result; /* Minimal error checking. Ignore cases we know about, and report the rest. */ if (driver_byte(result) != 0) { switch (SRpnt->sr_sense_buffer[2] & 0xf) { case UNIT_ATTENTION: SDev->changed = 1; if (!cgc->quiet) printk(KERN_INFO "%s: disc change detected.\n", cd->cdi.name); if (retries++ < 10) goto retry; err = -ENOMEDIUM; break; case NOT_READY: /* This happens if there is no disc in drive */ if (SRpnt->sr_sense_buffer[12] == 0x04 && SRpnt->sr_sense_buffer[13] == 0x01) { /* sense: Logical unit is in process of becoming ready */ if (!cgc->quiet) printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name); if (retries++ < 10) { /* sleep 2 sec and try again */ ssleep(2); goto retry; } else { /* 20 secs are enough? */ err = -ENOMEDIUM; break; } } if (!cgc->quiet) printk(KERN_INFO "%s: CDROM not ready. Make sure there is a disc in the drive.\n", cd->cdi.name); #ifdef DEBUG scsi_print_req_sense("sr", SRpnt); #endif err = -ENOMEDIUM; break; case ILLEGAL_REQUEST: err = -EIO; if (SRpnt->sr_sense_buffer[12] == 0x20 && SRpnt->sr_sense_buffer[13] == 0x00) /* sense: Invalid command operation code */ err = -EDRIVE_CANT_DO_THIS; #ifdef DEBUG __scsi_print_command(cgc->cmd); scsi_print_req_sense("sr", SRpnt); #endif break; default: printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name); __scsi_print_command(cgc->cmd); scsi_print_req_sense("sr", SRpnt); err = -EIO; } } if (cgc->sense) memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense)); /* Wake up a process waiting for device */ out_free: scsi_release_request(SRpnt); SRpnt = NULL; out: cgc->stat = err; return err; }