#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/string_helpers.h>
+#include <linux/async.h>
#include <asm/uaccess.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
static void sd_print_result(struct scsi_disk *, int);
+static DEFINE_SPINLOCK(sd_index_lock);
static DEFINE_IDA(sd_index_ida);
/* This semaphore is used to mediate the 0->1 reference get in the
struct scsi_device *sdp = q->queuedata;
struct gendisk *disk = rq->rq_disk;
struct scsi_disk *sdkp;
- sector_t block = rq->sector;
+ sector_t block = blk_rq_pos(rq);
sector_t threshold;
- unsigned int this_count = rq->nr_sectors;
+ unsigned int this_count = blk_rq_sectors(rq);
int ret, host_dif;
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
this_count));
if (!sdp || !scsi_device_online(sdp) ||
- block + rq->nr_sectors > get_capacity(disk)) {
+ block + blk_rq_sectors(rq) > get_capacity(disk)) {
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
- "Finishing %ld sectors\n",
- rq->nr_sectors));
+ "Finishing %u sectors\n",
+ blk_rq_sectors(rq)));
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
"Retry with 0x%p\n", SCpnt));
goto out;
* for this.
*/
if (sdp->sector_size == 1024) {
- if ((block & 1) || (rq->nr_sectors & 1)) {
+ if ((block & 1) || (blk_rq_sectors(rq) & 1)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
goto out;
}
}
if (sdp->sector_size == 2048) {
- if ((block & 3) || (rq->nr_sectors & 3)) {
+ if ((block & 3) || (blk_rq_sectors(rq) & 3)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
goto out;
}
}
if (sdp->sector_size == 4096) {
- if ((block & 7) || (rq->nr_sectors & 7)) {
+ if ((block & 7) || (blk_rq_sectors(rq) & 7)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
goto out;
}
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
- "%s %d/%ld 512 byte blocks.\n",
+ "%s %d/%u 512 byte blocks.\n",
(rq_data_dir(rq) == WRITE) ?
"writing" : "reading", this_count,
- rq->nr_sectors));
+ blk_rq_sectors(rq)));
/* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */
host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
* In the latter case @inode and @filp carry an abridged amount
* of information as noted above.
**/
-static int sd_open(struct inode *inode, struct file *filp)
+static int sd_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct scsi_disk *sdkp;
+ struct scsi_disk *sdkp = scsi_disk_get(bdev->bd_disk);
struct scsi_device *sdev;
int retval;
- if (!(sdkp = scsi_disk_get(disk)))
+ if (!sdkp)
return -ENXIO;
-
SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n"));
sdev = sdkp->device;
goto error_out;
if (sdev->removable || sdkp->write_prot)
- check_disk_change(inode->i_bdev);
+ check_disk_change(bdev);
/*
* If the drive is empty, just let the open fail.
*/
retval = -ENOMEDIUM;
- if (sdev->removable && !sdkp->media_present &&
- !(filp->f_flags & O_NDELAY))
+ if (sdev->removable && !sdkp->media_present && !(mode & FMODE_NDELAY))
goto error_out;
/*
* if the user expects to be able to write to the thing.
*/
retval = -EROFS;
- if (sdkp->write_prot && (filp->f_mode & FMODE_WRITE))
+ if (sdkp->write_prot && (mode & FMODE_WRITE))
goto error_out;
/*
* Note: may block (uninterruptible) if error recovery is underway
* on this disk.
**/
-static int sd_release(struct inode *inode, struct file *filp)
+static int sd_release(struct gendisk *disk, fmode_t mode)
{
- struct gendisk *disk = inode->i_bdev->bd_disk;
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdev = sdkp->device;
* Note: most ioctls are forward onto the block subsystem or further
* down in the scsi subsystem.
**/
-static int sd_ioctl(struct inode * inode, struct file * filp,
+static int sd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
struct scsi_device *sdp = scsi_disk(disk)->device;
void __user *p = (void __user *)arg;
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- error = scsi_nonblockable_ioctl(sdp, cmd, p, filp);
+ error = scsi_nonblockable_ioctl(sdp, cmd, p,
+ (mode & FMODE_NDELAY) != 0);
if (!scsi_block_when_processing_errors(sdp) || !error)
return error;
case SCSI_IOCTL_GET_BUS_NUMBER:
return scsi_ioctl(sdp, cmd, p);
default:
- error = scsi_cmd_ioctl(filp, disk->queue, disk, cmd, p);
+ error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p);
if (error != -ENOTTY)
return error;
}
* flush everything.
*/
res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES);
+ SD_TIMEOUT, SD_MAX_RETRIES, NULL);
if (res == 0)
break;
}
* This gets directly called from VFS. When the ioctl
* is not recognized we go back to the other translation paths.
*/
-static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev;
- struct gendisk *disk = bdev->bd_disk;
- struct scsi_device *sdev = scsi_disk(disk)->device;
+ struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
/*
* If we are in the middle of error recovery, don't let anyone
.owner = THIS_MODULE,
.open = sd_open,
.release = sd_release,
- .ioctl = sd_ioctl,
+ .locked_ioctl = sd_ioctl,
.getgeo = sd_getgeo,
#ifdef CONFIG_COMPAT
.compat_ioctl = sd_compat_ioctl,
static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
{
- u64 start_lba = scmd->request->sector;
- u64 end_lba = scmd->request->sector + (scsi_bufflen(scmd) / 512);
+ u64 start_lba = blk_rq_pos(scmd->request);
+ u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512);
u64 bad_lba;
int info_valid;
good_bytes = sd_completed_bytes(SCpnt);
break;
case RECOVERED_ERROR:
- /* Inform the user, but make sure that it's not treated
- * as a hard error.
- */
- scsi_print_sense("sd", SCpnt);
- SCpnt->result = 0;
- memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
good_bytes = scsi_bufflen(SCpnt);
break;
case NO_SENSE:
the_result = scsi_execute_req(sdkp->device, cmd,
DMA_NONE, NULL, 0,
&sshdr, SD_TIMEOUT,
- SD_MAX_RETRIES);
+ SD_MAX_RETRIES, NULL);
/*
* If the drive has indicated to us that it
/*
* The device does not want the automatic start to be issued.
*/
- if (sdkp->device->no_start_on_add) {
+ if (sdkp->device->no_start_on_add)
break;
- }
- /*
- * If manual intervention is required, or this is an
- * absent USB storage device, a spinup is meaningless.
- */
- if (sense_valid &&
- sshdr.sense_key == NOT_READY &&
- sshdr.asc == 4 && sshdr.ascq == 3) {
- break; /* manual intervention required */
-
- /*
- * Issue command to spin up drive when not ready
- */
- } else if (sense_valid && sshdr.sense_key == NOT_READY) {
+ if (sense_valid && sshdr.sense_key == NOT_READY) {
+ if (sshdr.asc == 4 && sshdr.ascq == 3)
+ break; /* manual intervention required */
+ if (sshdr.asc == 4 && sshdr.ascq == 0xb)
+ break; /* standby */
+ if (sshdr.asc == 4 && sshdr.ascq == 0xc)
+ break; /* unavailable */
+ /*
+ * Issue command to spin up drive when not ready
+ */
if (!spintime) {
sd_printk(KERN_NOTICE, sdkp, "Spinning up disk...");
cmd[0] = START_STOP;
cmd[4] |= 1 << 4;
scsi_execute_req(sdkp->device, cmd, DMA_NONE,
NULL, 0, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES);
+ SD_TIMEOUT, SD_MAX_RETRIES,
+ NULL);
spintime_expire = jiffies + 100 * HZ;
spintime = 1;
}
sdkp->capacity = 0;
}
-/*
- * read disk capacity
- */
-static void
-sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
+static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
+ struct scsi_sense_hdr *sshdr, int sense_valid,
+ int the_result)
+{
+ sd_print_result(sdkp, the_result);
+ if (driver_byte(the_result) & DRIVER_SENSE)
+ sd_print_sense_hdr(sdkp, sshdr);
+ else
+ sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n");
+
+ /*
+ * Set dirty bit for removable devices if not ready -
+ * sometimes drives will not report this properly.
+ */
+ if (sdp->removable &&
+ sense_valid && sshdr->sense_key == NOT_READY)
+ sdp->changed = 1;
+
+ /*
+ * We used to set media_present to 0 here to indicate no media
+ * in the drive, but some drives fail read capacity even with
+ * media present, so we can't do that.
+ */
+ sdkp->capacity = 0; /* unknown mapped to zero - as usual */
+}
+
+#define RC16_LEN 32
+#if RC16_LEN > SD_BUF_SIZE
+#error RC16_LEN must not be more than SD_BUF_SIZE
+#endif
+
+static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
+ unsigned char *buffer)
{
unsigned char cmd[16];
- int the_result, retries;
- int sector_size = 0;
- /* Force READ CAPACITY(16) when PROTECT=1 */
- int longrc = scsi_device_protection(sdkp->device) ? 1 : 0;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
- struct scsi_device *sdp = sdkp->device;
+ int the_result;
+ int retries = 3;
+ unsigned int alignment;
+ unsigned long long lba;
+ unsigned sector_size;
-repeat:
- retries = 3;
do {
- if (longrc) {
- memset((void *) cmd, 0, 16);
- cmd[0] = SERVICE_ACTION_IN;
- cmd[1] = SAI_READ_CAPACITY_16;
- cmd[13] = 13;
- memset((void *) buffer, 0, 13);
- } else {
- cmd[0] = READ_CAPACITY;
- memset((void *) &cmd[1], 0, 9);
- memset((void *) buffer, 0, 8);
+ memset(cmd, 0, 16);
+ cmd[0] = SERVICE_ACTION_IN;
+ cmd[1] = SAI_READ_CAPACITY_16;
+ cmd[13] = RC16_LEN;
+ memset(buffer, 0, RC16_LEN);
+
+ the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
+ buffer, RC16_LEN, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES, NULL);
+
+ if (media_not_present(sdkp, &sshdr))
+ return -ENODEV;
+
+ if (the_result) {
+ sense_valid = scsi_sense_valid(&sshdr);
+ if (sense_valid &&
+ sshdr.sense_key == ILLEGAL_REQUEST &&
+ (sshdr.asc == 0x20 || sshdr.asc == 0x24) &&
+ sshdr.ascq == 0x00)
+ /* Invalid Command Operation Code or
+ * Invalid Field in CDB, just retry
+ * silently with RC10 */
+ return -EINVAL;
}
-
+ retries--;
+
+ } while (the_result && retries);
+
+ if (the_result) {
+ sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n");
+ read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result);
+ return -EINVAL;
+ }
+
+ sector_size = get_unaligned_be32(&buffer[8]);
+ lba = get_unaligned_be64(&buffer[0]);
+
+ sd_read_protection_type(sdkp, buffer);
+
+ if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) {
+ sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
+ "kernel compiled with support for large block "
+ "devices.\n");
+ sdkp->capacity = 0;
+ return -EOVERFLOW;
+ }
+
+ /* Logical blocks per physical block exponent */
+ sdkp->hw_sector_size = (1 << (buffer[13] & 0xf)) * sector_size;
+
+ /* Lowest aligned logical block */
+ alignment = ((buffer[14] & 0x3f) << 8 | buffer[15]) * sector_size;
+ blk_queue_alignment_offset(sdp->request_queue, alignment);
+ if (alignment && sdkp->first_scan)
+ sd_printk(KERN_NOTICE, sdkp,
+ "physical block alignment offset: %u\n", alignment);
+
+ sdkp->capacity = lba + 1;
+ return sector_size;
+}
+
+static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
+ unsigned char *buffer)
+{
+ unsigned char cmd[16];
+ struct scsi_sense_hdr sshdr;
+ int sense_valid = 0;
+ int the_result;
+ int retries = 3;
+ sector_t lba;
+ unsigned sector_size;
+
+ do {
+ cmd[0] = READ_CAPACITY;
+ memset(&cmd[1], 0, 9);
+ memset(buffer, 0, 8);
+
the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
- buffer, longrc ? 13 : 8, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES);
+ buffer, 8, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES, NULL);
if (media_not_present(sdkp, &sshdr))
- return;
+ return -ENODEV;
if (the_result)
sense_valid = scsi_sense_valid(&sshdr);
} while (the_result && retries);
- if (the_result && !longrc) {
+ if (the_result) {
sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n");
- sd_print_result(sdkp, the_result);
- if (driver_byte(the_result) & DRIVER_SENSE)
- sd_print_sense_hdr(sdkp, &sshdr);
- else
- sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n");
+ read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result);
+ return -EINVAL;
+ }
- /* Set dirty bit for removable devices if not ready -
- * sometimes drives will not report this properly. */
- if (sdp->removable &&
- sense_valid && sshdr.sense_key == NOT_READY)
- sdp->changed = 1;
+ sector_size = get_unaligned_be32(&buffer[4]);
+ lba = get_unaligned_be32(&buffer[0]);
- /* Either no media are present but the drive didn't tell us,
- or they are present but the read capacity command fails */
- /* sdkp->media_present = 0; -- not always correct */
- sdkp->capacity = 0; /* unknown mapped to zero - as usual */
+ if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) {
+ sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
+ "kernel compiled with support for large block "
+ "devices.\n");
+ sdkp->capacity = 0;
+ return -EOVERFLOW;
+ }
- return;
- } else if (the_result && longrc) {
- /* READ CAPACITY(16) has been failed */
- sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n");
- sd_print_result(sdkp, the_result);
- sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n");
+ sdkp->capacity = lba + 1;
+ sdkp->hw_sector_size = sector_size;
+ return sector_size;
+}
- sdkp->capacity = 1 + (sector_t) 0xffffffff;
- goto got_data;
- }
-
- if (!longrc) {
- sector_size = (buffer[4] << 24) |
- (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
- if (buffer[0] == 0xff && buffer[1] == 0xff &&
- buffer[2] == 0xff && buffer[3] == 0xff) {
- if(sizeof(sdkp->capacity) > 4) {
- sd_printk(KERN_NOTICE, sdkp, "Very big device. "
- "Trying to use READ CAPACITY(16).\n");
- longrc = 1;
- goto repeat;
- }
- sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use "
- "a kernel compiled with support for large "
- "block devices.\n");
- sdkp->capacity = 0;
+static int sd_try_rc16_first(struct scsi_device *sdp)
+{
+ if (sdp->scsi_level > SCSI_SPC_2)
+ return 1;
+ if (scsi_device_protection(sdp))
+ return 1;
+ return 0;
+}
+
+/*
+ * read disk capacity
+ */
+static void
+sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
+{
+ int sector_size;
+ struct scsi_device *sdp = sdkp->device;
+ sector_t old_capacity = sdkp->capacity;
+
+ if (sd_try_rc16_first(sdp)) {
+ sector_size = read_capacity_16(sdkp, sdp, buffer);
+ if (sector_size == -EOVERFLOW)
goto got_data;
- }
- sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) |
- (buffer[1] << 16) |
- (buffer[2] << 8) |
- buffer[3]);
+ if (sector_size == -ENODEV)
+ return;
+ if (sector_size < 0)
+ sector_size = read_capacity_10(sdkp, sdp, buffer);
+ if (sector_size < 0)
+ return;
} else {
- sdkp->capacity = 1 + (((u64)buffer[0] << 56) |
- ((u64)buffer[1] << 48) |
- ((u64)buffer[2] << 40) |
- ((u64)buffer[3] << 32) |
- ((sector_t)buffer[4] << 24) |
- ((sector_t)buffer[5] << 16) |
- ((sector_t)buffer[6] << 8) |
- (sector_t)buffer[7]);
-
- sector_size = (buffer[8] << 24) |
- (buffer[9] << 16) | (buffer[10] << 8) | buffer[11];
-
- sd_read_protection_type(sdkp, buffer);
- }
-
- /* Some devices return the total number of sectors, not the
- * highest sector number. Make the necessary adjustment. */
- if (sdp->fix_capacity) {
- --sdkp->capacity;
+ sector_size = read_capacity_10(sdkp, sdp, buffer);
+ if (sector_size == -EOVERFLOW)
+ goto got_data;
+ if (sector_size < 0)
+ return;
+ if ((sizeof(sdkp->capacity) > 4) &&
+ (sdkp->capacity > 0xffffffffULL)) {
+ int old_sector_size = sector_size;
+ sd_printk(KERN_NOTICE, sdkp, "Very big device. "
+ "Trying to use READ CAPACITY(16).\n");
+ sector_size = read_capacity_16(sdkp, sdp, buffer);
+ if (sector_size < 0) {
+ sd_printk(KERN_NOTICE, sdkp,
+ "Using 0xffffffff as device size\n");
+ sdkp->capacity = 1 + (sector_t) 0xffffffff;
+ sector_size = old_sector_size;
+ goto got_data;
+ }
+ }
+ }
- /* Some devices have version which report the correct sizes
- * and others which do not. We guess size according to a heuristic
- * and err on the side of lowering the capacity. */
- } else {
- if (sdp->guess_capacity)
- if (sdkp->capacity & 0x01) /* odd sizes are odd */
- --sdkp->capacity;
+ /* Some devices are known to return the total number of blocks,
+ * not the highest block number. Some devices have versions
+ * which do this and others which do not. Some devices we might
+ * suspect of doing this but we don't know for certain.
+ *
+ * If we know the reported capacity is wrong, decrement it. If
+ * we can only guess, then assume the number of blocks is even
+ * (usually true but not always) and err on the side of lowering
+ * the capacity.
+ */
+ if (sdp->fix_capacity ||
+ (sdp->guess_capacity && (sdkp->capacity & 0x01))) {
+ sd_printk(KERN_INFO, sdkp, "Adjusting the sector count "
+ "from its reported value: %llu\n",
+ (unsigned long long) sdkp->capacity);
+ --sdkp->capacity;
}
got_data:
*/
sector_size = 512;
}
- blk_queue_hardsect_size(sdp->request_queue, sector_size);
+ blk_queue_logical_block_size(sdp->request_queue, sector_size);
{
char cap_str_2[10], cap_str_10[10];
string_get_size(sz, STRING_UNITS_10, cap_str_10,
sizeof(cap_str_10));
- sd_printk(KERN_NOTICE, sdkp,
- "%llu %d-byte hardware sectors: (%s/%s)\n",
- (unsigned long long)sdkp->capacity,
- sector_size, cap_str_10, cap_str_2);
+ if (sdkp->first_scan || old_capacity != sdkp->capacity) {
+ sd_printk(KERN_NOTICE, sdkp,
+ "%llu %d-byte logical blocks: (%s/%s)\n",
+ (unsigned long long)sdkp->capacity,
+ sector_size, cap_str_10, cap_str_2);
+
+ if (sdkp->hw_sector_size != sector_size)
+ sd_printk(KERN_NOTICE, sdkp,
+ "%u-byte physical blocks\n",
+ sdkp->hw_sector_size);
+ }
}
/* Rescale capacity to 512-byte units */
else if (sector_size == 256)
sdkp->capacity >>= 1;
+ blk_queue_physical_block_size(sdp->request_queue, sdkp->hw_sector_size);
sdkp->device->sector_size = sector_size;
}
int res;
struct scsi_device *sdp = sdkp->device;
struct scsi_mode_data data;
+ int old_wp = sdkp->write_prot;
set_disk_ro(sdkp->disk, 0);
if (sdp->skip_ms_page_3f) {
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
set_disk_ro(sdkp->disk, sdkp->write_prot);
- sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
- sdkp->write_prot ? "on" : "off");
- sd_printk(KERN_DEBUG, sdkp,
- "Mode Sense: %02x %02x %02x %02x\n",
- buffer[0], buffer[1], buffer[2], buffer[3]);
+ if (sdkp->first_scan || old_wp != sdkp->write_prot) {
+ sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
+ sdkp->write_prot ? "on" : "off");
+ sd_printk(KERN_DEBUG, sdkp,
+ "Mode Sense: %02x %02x %02x %02x\n",
+ buffer[0], buffer[1], buffer[2], buffer[3]);
+ }
}
}
int modepage;
struct scsi_mode_data data;
struct scsi_sense_hdr sshdr;
+ int old_wce = sdkp->WCE;
+ int old_rcd = sdkp->RCD;
+ int old_dpofua = sdkp->DPOFUA;
if (sdp->skip_ms_page_8)
goto defaults;
sdkp->DPOFUA = 0;
}
- sd_printk(KERN_NOTICE, sdkp,
- "Write cache: %s, read cache: %s, %s\n",
- sdkp->WCE ? "enabled" : "disabled",
- sdkp->RCD ? "disabled" : "enabled",
- sdkp->DPOFUA ? "supports DPO and FUA"
- : "doesn't support DPO or FUA");
+ if (sdkp->first_scan || old_wce != sdkp->WCE ||
+ old_rcd != sdkp->RCD || old_dpofua != sdkp->DPOFUA)
+ sd_printk(KERN_NOTICE, sdkp,
+ "Write cache: %s, read cache: %s, %s\n",
+ sdkp->WCE ? "enabled" : "disabled",
+ sdkp->RCD ? "disabled" : "enabled",
+ sdkp->DPOFUA ? "supports DPO and FUA"
+ : "doesn't support DPO or FUA");
return;
}
}
/**
+ * sd_read_block_limits - Query disk device for preferred I/O sizes.
+ * @disk: disk to query
+ */
+static void sd_read_block_limits(struct scsi_disk *sdkp)
+{
+ unsigned int sector_sz = sdkp->device->sector_size;
+ char *buffer;
+
+ /* Block Limits VPD */
+ buffer = scsi_get_vpd_page(sdkp->device, 0xb0);
+
+ if (buffer == NULL)
+ return;
+
+ blk_queue_io_min(sdkp->disk->queue,
+ get_unaligned_be16(&buffer[6]) * sector_sz);
+ blk_queue_io_opt(sdkp->disk->queue,
+ get_unaligned_be32(&buffer[12]) * sector_sz);
+
+ kfree(buffer);
+}
+
+/**
+ * sd_read_block_characteristics - Query block dev. characteristics
+ * @disk: disk to query
+ */
+static void sd_read_block_characteristics(struct scsi_disk *sdkp)
+{
+ char *buffer;
+ u16 rot;
+
+ /* Block Device Characteristics VPD */
+ buffer = scsi_get_vpd_page(sdkp->device, 0xb1);
+
+ if (buffer == NULL)
+ return;
+
+ rot = get_unaligned_be16(&buffer[4]);
+
+ if (rot == 1)
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue);
+
+ kfree(buffer);
+}
+
+/**
* sd_revalidate_disk - called the first time a new disk is seen,
* performs disk spin up, read_capacity, etc.
* @disk: struct gendisk we care about
goto out;
}
- /* defaults, until the device tells us otherwise */
- sdp->sector_size = 512;
- sdkp->capacity = 0;
- sdkp->media_present = 1;
- sdkp->write_prot = 0;
- sdkp->WCE = 0;
- sdkp->RCD = 0;
- sdkp->ATO = 0;
-
sd_spinup_disk(sdkp);
/*
*/
if (sdkp->media_present) {
sd_read_capacity(sdkp, buffer);
+ sd_read_block_limits(sdkp);
+ sd_read_block_characteristics(sdkp);
sd_read_write_protect_flag(sdkp, buffer);
sd_read_cache_type(sdkp, buffer);
sd_read_app_tag_own(sdkp, buffer);
}
+ sdkp->first_scan = 0;
+
/*
* We now have all cache related info, determine how we deal
* with ordered requests. Note that as the current SCSI
return 0;
}
+/*
+ * The asynchronous part of sd_probe
+ */
+static void sd_probe_async(void *data, async_cookie_t cookie)
+{
+ struct scsi_disk *sdkp = data;
+ struct scsi_device *sdp;
+ struct gendisk *gd;
+ u32 index;
+ struct device *dev;
+
+ sdp = sdkp->device;
+ gd = sdkp->disk;
+ index = sdkp->index;
+ dev = &sdp->sdev_gendev;
+
+ if (index < SD_MAX_DISKS) {
+ gd->major = sd_major((index & 0xf0) >> 4);
+ gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+ gd->minors = SD_MINORS;
+ }
+ gd->fops = &sd_fops;
+ gd->private_data = &sdkp->driver;
+ gd->queue = sdkp->device->request_queue;
+
+ /* defaults, until the device tells us otherwise */
+ sdp->sector_size = 512;
+ sdkp->capacity = 0;
+ sdkp->media_present = 1;
+ sdkp->write_prot = 0;
+ sdkp->WCE = 0;
+ sdkp->RCD = 0;
+ sdkp->ATO = 0;
+ sdkp->first_scan = 1;
+
+ sd_revalidate_disk(gd);
+
+ blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
+
+ gd->driverfs_dev = &sdp->sdev_gendev;
+ gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
+ if (sdp->removable)
+ gd->flags |= GENHD_FL_REMOVABLE;
+
+ dev_set_drvdata(dev, sdkp);
+ add_disk(gd);
+ sd_dif_config_host(sdkp);
+
+ sd_revalidate_disk(gd);
+
+ sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
+ sdp->removable ? "removable " : "");
+}
+
/**
* sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
goto out_put;
+ spin_lock(&sd_index_lock);
error = ida_get_new(&sd_index_ida, &index);
+ spin_unlock(&sd_index_lock);
} while (error == -EAGAIN);
if (error)
device_initialize(&sdkp->dev);
sdkp->dev.parent = &sdp->sdev_gendev;
sdkp->dev.class = &sd_disk_class;
- strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
+ dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
if (device_add(&sdkp->dev))
goto out_free_index;
get_device(&sdp->sdev_gendev);
- if (index < SD_MAX_DISKS) {
- gd->major = sd_major((index & 0xf0) >> 4);
- gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
- gd->minors = SD_MINORS;
- }
- gd->fops = &sd_fops;
- gd->private_data = &sdkp->driver;
- gd->queue = sdkp->device->request_queue;
-
- sd_revalidate_disk(gd);
-
- blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
-
- gd->driverfs_dev = &sdp->sdev_gendev;
- gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
- if (sdp->removable)
- gd->flags |= GENHD_FL_REMOVABLE;
-
- dev_set_drvdata(dev, sdkp);
- add_disk(gd);
- sd_dif_config_host(sdkp);
-
- sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
- sdp->removable ? "removable " : "");
+ async_schedule(sd_probe_async, sdkp);
return 0;
out_free_index:
+ spin_lock(&sd_index_lock);
ida_remove(&sd_index_ida, index);
+ spin_unlock(&sd_index_lock);
out_put:
put_disk(gd);
out_free:
**/
static int sd_remove(struct device *dev)
{
- struct scsi_disk *sdkp = dev_get_drvdata(dev);
+ struct scsi_disk *sdkp;
+ async_synchronize_full();
+ sdkp = dev_get_drvdata(dev);
+ blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn);
device_del(&sdkp->dev);
del_gendisk(sdkp->disk);
sd_shutdown(dev);
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct gendisk *disk = sdkp->disk;
+ spin_lock(&sd_index_lock);
ida_remove(&sd_index_ida, sdkp->index);
+ spin_unlock(&sd_index_lock);
disk->private_data = NULL;
put_disk(disk);
return -ENODEV;
res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES);
+ SD_TIMEOUT, SD_MAX_RETRIES, NULL);
if (res) {
sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n");
sd_print_result(sdkp, res);