/* * hp_sw_tur - Send TEST UNIT READY * @sdev: sdev command should be sent to * * Use the TEST UNIT READY command to determine * the path state. */ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) { unsigned char cmd[6] = { TEST_UNIT_READY }; struct scsi_sense_hdr sshdr; int ret = SCSI_DH_OK, res; u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; retry: res = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL, &sshdr, HP_SW_TIMEOUT, HP_SW_RETRIES, req_flags, 0, NULL); if (res) { if (scsi_sense_valid(&sshdr)) ret = tur_done(sdev, h, &sshdr); else { sdev_printk(KERN_WARNING, sdev, "%s: sending tur failed with %x\n", HP_SW_NAME, res); ret = SCSI_DH_IO; } } else { h->path_state = HP_SW_PATH_ACTIVE; ret = SCSI_DH_OK; } if (ret == SCSI_DH_IMM_RETRY) goto retry; return ret; }
/* * hp_sw_start_stop - Send START STOP UNIT command * @sdev: sdev command should be sent to * * Sending START STOP UNIT activates the SP. */ static int hp_sw_start_stop(struct hp_sw_dh_data *h) { unsigned char cmd[6] = { START_STOP, 0, 0, 0, 1, 0 }; struct scsi_sense_hdr sshdr; struct scsi_device *sdev = h->sdev; int res, rc = SCSI_DH_OK; int retry_cnt = HP_SW_RETRIES; u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; retry: res = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL, &sshdr, HP_SW_TIMEOUT, HP_SW_RETRIES, req_flags, 0, NULL); if (res) { if (!scsi_sense_valid(&sshdr)) { sdev_printk(KERN_WARNING, sdev, "%s: sending start_stop_unit failed, " "no sense available\n", HP_SW_NAME); return SCSI_DH_IO; } switch (sshdr.sense_key) { case NOT_READY: if (sshdr.asc == 0x04 && sshdr.ascq == 3) { /* * LUN not ready - manual intervention required * * Switch-over in progress, retry. */ if (--retry_cnt) goto retry; rc = SCSI_DH_RETRY; break; } /* fall through */ default: sdev_printk(KERN_WARNING, sdev, "%s: sending start_stop_unit failed, " "sense %x/%x/%x\n", HP_SW_NAME, sshdr.sense_key, sshdr.asc, sshdr.ascq); rc = SCSI_DH_IO; } } return rc; }
int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) { struct scsi_device *SDev; struct scsi_sense_hdr sshdr; int result, err = 0, retries = 0; struct request_sense *sense = cgc->sense; SDev = cd->device; if (!sense) { sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); if (!sense) { err = -ENOMEM; goto out; } } retry: if (!scsi_block_when_processing_errors(SDev)) { err = -ENODEV; goto out; } memset(sense, 0, sizeof(*sense)); result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, cgc->buffer, cgc->buflen, (char *)sense, cgc->timeout, IOCTL_RETRIES, 0, NULL); scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr); /* Minimal error checking. Ignore cases we know about, and report the rest. */ if (driver_byte(result) != 0) { switch (sshdr.sense_key) { case UNIT_ATTENTION: SDev->changed = 1; if (!cgc->quiet) sr_printk(KERN_INFO, cd, "disc change detected.\n"); if (retries++ < 10) goto retry; err = -ENOMEDIUM; break; case NOT_READY: /* This happens if there is no disc in drive */ if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { /* sense: Logical unit is in process of becoming ready */ if (!cgc->quiet) sr_printk(KERN_INFO, cd, "CDROM not ready yet.\n"); if (retries++ < 10) { /* sleep 2 sec and try again */ ssleep(2); goto retry; } else { /* 20 secs are enough? */ err = -ENOMEDIUM; break; } } if (!cgc->quiet) sr_printk(KERN_INFO, cd, "CDROM not ready. Make sure there " "is a disc in the drive.\n"); err = -ENOMEDIUM; break; case ILLEGAL_REQUEST: err = -EIO; if (sshdr.asc == 0x20 && sshdr.ascq == 0x00) /* sense: Invalid command operation code */ err = -EDRIVE_CANT_DO_THIS; break; default: err = -EIO; } } /* Wake up a process waiting for device */ out: if (!cgc->sense) kfree(sense); cgc->stat = err; return err; }
static int modisk_attach(struct scst_device *dev) { int res, rc; uint8_t cmd[10]; const int buffer_size = 512; uint8_t *buffer = NULL; int retries; unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; TRACE_ENTRY(); if (dev->scsi_dev == NULL || dev->scsi_dev->type != dev->type) { PRINT_ERROR("%s", "SCSI device not define or illegal type"); res = -ENODEV; goto out; } dev->block_shift = MODISK_DEF_BLOCK_SHIFT; dev->block_size = 1 << dev->block_shift; /* * If the device is offline, don't try to read capacity or any * of the other stuff */ if (dev->scsi_dev->sdev_state == SDEV_OFFLINE) { TRACE_DBG("%s", "Device is offline"); res = -ENODEV; goto out; } buffer = kmalloc(buffer_size, GFP_KERNEL); if (!buffer) { PRINT_ERROR("Buffer memory allocation (size %d) failure", buffer_size); res = -ENOMEM; goto out; } /* * Clear any existing UA's and get modisk capacity (modisk block * size). */ memset(cmd, 0, sizeof(cmd)); cmd[0] = READ_CAPACITY; cmd[1] = (dev->scsi_dev->scsi_level <= SCSI_2) ? ((dev->scsi_dev->lun << 5) & 0xe0) : 0; retries = SCST_DEV_RETRIES_ON_UA; while (1) { memset(buffer, 0, buffer_size); memset(sense_buffer, 0, sizeof(sense_buffer)); data_dir = SCST_DATA_READ; TRACE_DBG("%s", "Doing READ_CAPACITY"); rc = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer, buffer_size, sense_buffer, SCST_GENERIC_MODISK_REG_TIMEOUT, 3, 0 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) , NULL #endif ); TRACE_DBG("READ_CAPACITY done: %x", rc); if (!rc || !scst_analyze_sense(sense_buffer, sizeof(sense_buffer), SCST_SENSE_KEY_VALID, UNIT_ATTENTION, 0, 0)) break; if (!--retries) { PRINT_ERROR("UA not cleared after %d retries", SCST_DEV_RETRIES_ON_UA); res = -ENODEV; goto out_free_buf; } } if (rc == 0) { uint32_t sector_size = get_unaligned_be32(&buffer[4]); if (sector_size == 0) dev->block_shift = MODISK_DEF_BLOCK_SHIFT; else dev->block_shift = scst_calc_block_shift(sector_size); TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", sector_size, dev->scsi_dev->scsi_level, SCSI_2); if (dev->block_shift < 9) { PRINT_ERROR("READ CAPACITY reported an invalid sector size: %d", sector_size); res = -EINVAL; goto out_free_buf; } } else { dev->block_shift = MODISK_DEF_BLOCK_SHIFT; TRACE(TRACE_MINOR, "Read capacity failed: %x, using default " "sector size %d", rc, dev->block_shift); PRINT_BUFF_FLAG(TRACE_MINOR, "Returned sense", sense_buffer, sizeof(sense_buffer)); } dev->block_size = 1 << dev->block_shift; res = scst_obtain_device_parameters(dev, NULL); if (res != 0) { PRINT_ERROR("Failed to obtain control parameters for device " "%s: %x", dev->virt_name, res); goto out_free_buf; } out_free_buf: kfree(buffer); out: TRACE_EXIT_RES(res); return res; }
int scsi_ioctl_send_command(struct scsi_device *sdev, struct scsi_ioctl_command __user *sic) { char *buf; unsigned char cmd[MAX_COMMAND_SIZE]; unsigned char sense[SCSI_SENSE_BUFFERSIZE]; char __user *cmd_in; unsigned char opcode; unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; int timeout, retries, result; int data_direction; gfp_t 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(inlen && 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; } result = scsi_execute(sdev, cmd, data_direction, buf, needed, sense, timeout, retries, 0); /* * If there was an error condition, pass the info back to the user. */ if (result) { int sb_len = sizeof(*sense); sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; if (copy_to_user(cmd_in, sense, sb_len)) result = -EFAULT; } else { if (outlen && copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; } error: kfree(buf); return result; }