X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Fsd.c;fp=drivers%2Fscsi%2Fsd.c;h=9d9872347f56a9660c52da7bc76510cd3ec614a1;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=98bd3aab9739114f6b4dd1a538928856929fe7a5;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 98bd3aab9..9d9872347 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -32,6 +32,7 @@ * than the level indicated above to trigger output. */ +#include #include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -69,27 +71,6 @@ */ #define SD_MAJORS 16 -MODULE_AUTHOR("Eric Youngdale"); -MODULE_DESCRIPTION("SCSI disk (sd) driver"); -MODULE_LICENSE("GPL"); - -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK0_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK1_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK2_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK3_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK4_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK5_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK6_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK7_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK8_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK9_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK10_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK11_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); - /* * This is limited by the naming scheme enforced in sd_probe, * add another character to it if you really need more disks. @@ -113,10 +94,12 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); */ #define SD_BUF_SIZE 512 +static void scsi_disk_release(struct kref *kref); + struct scsi_disk { struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; - struct class_device cdev; + struct kref kref; struct gendisk *disk; unsigned int openers; /* protected by BKL for now, yuck */ sector_t capacity; /* size in 512-byte sectors */ @@ -127,7 +110,6 @@ struct scsi_disk { unsigned RCD : 1; /* state of disk RCD bit, unused */ unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ }; -#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev) static DEFINE_IDR(sd_index_idr); static DEFINE_SPINLOCK(sd_index_lock); @@ -149,118 +131,6 @@ static int sd_issue_flush(struct device *, sector_t *); static void sd_prepare_flush(request_queue_t *, struct request *); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, unsigned char *buffer); -static void scsi_disk_release(struct class_device *cdev); - -static const char *sd_cache_types[] = { - "write through", "none", "write back", - "write back, no read (daft)" -}; - -static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, - size_t count) -{ - int i, ct = -1, rcd, wce, sp; - struct scsi_disk *sdkp = to_scsi_disk(cdev); - struct scsi_device *sdp = sdkp->device; - char buffer[64]; - char *buffer_data; - struct scsi_mode_data data; - struct scsi_sense_hdr sshdr; - int len; - - if (sdp->type != TYPE_DISK) - /* no cache control on RBC devices; theoretically they - * can do it, but there's probably so many exceptions - * it's not worth the risk */ - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) { - const int len = strlen(sd_cache_types[i]); - if (strncmp(sd_cache_types[i], buf, len) == 0 && - buf[len] == '\n') { - ct = i; - break; - } - } - if (ct < 0) - return -EINVAL; - rcd = ct & 0x01 ? 1 : 0; - wce = ct & 0x02 ? 1 : 0; - if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT, - SD_MAX_RETRIES, &data, NULL)) - return -EINVAL; - len = min_t(size_t, sizeof(buffer), data.length - data.header_length - - data.block_descriptor_length); - buffer_data = buffer + data.header_length + - data.block_descriptor_length; - buffer_data[2] &= ~0x05; - buffer_data[2] |= wce << 2 | rcd; - sp = buffer_data[0] & 0x80 ? 1 : 0; - - if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, - SD_MAX_RETRIES, &data, &sshdr)) { - if (scsi_sense_valid(&sshdr)) - scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr); - return -EINVAL; - } - sd_revalidate_disk(sdkp->disk); - return count; -} - -static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf, - size_t count) -{ - struct scsi_disk *sdkp = to_scsi_disk(cdev); - struct scsi_device *sdp = sdkp->device; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (sdp->type != TYPE_DISK) - return -EINVAL; - - sdp->allow_restart = simple_strtoul(buf, NULL, 10); - - return count; -} - -static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(cdev); - int ct = sdkp->RCD + 2*sdkp->WCE; - - return snprintf(buf, 40, "%s\n", sd_cache_types[ct]); -} - -static ssize_t sd_show_fua(struct class_device *cdev, char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(cdev); - - return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); -} - -static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(cdev); - - return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); -} - -static struct class_device_attribute sd_disk_attrs[] = { - __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, - sd_store_cache_type), - __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), - __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, - sd_store_allow_restart), - __ATTR_NULL, -}; - -static struct class sd_disk_class = { - .name = "scsi_disk", - .owner = THIS_MODULE, - .release = scsi_disk_release, - .class_dev_attrs = sd_disk_attrs, -}; static struct scsi_driver sd_template = { .owner = THIS_MODULE, @@ -304,6 +174,8 @@ static int sd_major(int major_idx) } } +#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref) + static inline struct scsi_disk *scsi_disk(struct gendisk *disk) { return container_of(disk->private_data, struct scsi_disk, driver); @@ -316,7 +188,7 @@ static struct scsi_disk *__scsi_disk_get(struct gendisk *disk) if (disk->private_data) { sdkp = scsi_disk(disk); if (scsi_device_get(sdkp->device) == 0) - class_device_get(&sdkp->cdev); + kref_get(&sdkp->kref); else sdkp = NULL; } @@ -350,7 +222,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp) struct scsi_device *sdev = sdkp->device; mutex_lock(&sd_ref_mutex); - class_device_put(&sdkp->cdev); + kref_put(&sdkp->kref, scsi_disk_release); scsi_device_put(sdev); mutex_unlock(&sd_ref_mutex); } @@ -502,7 +374,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) SCpnt->cmnd[4] = (unsigned char) this_count; SCpnt->cmnd[5] = 0; } - SCpnt->request_bufflen = this_count * sdp->sector_size; + SCpnt->request_bufflen = SCpnt->bufflen = + this_count * sdp->sector_size; /* * We shouldn't disconnect in the middle of a sector, so with a dumb @@ -915,10 +788,11 @@ static struct block_device_operations sd_fops = { static void sd_rw_intr(struct scsi_cmnd * SCpnt) { int result = SCpnt->result; - unsigned int xfer_size = SCpnt->request_bufflen; - unsigned int good_bytes = result ? 0 : xfer_size; - u64 start_lba = SCpnt->request->sector; - u64 bad_lba; + int this_count = SCpnt->bufflen; + int good_bytes = (result == 0 ? this_count : 0); + sector_t block_sectors = 1; + u64 first_err_block; + sector_t error_sector; struct scsi_sense_hdr sshdr; int sense_valid = 0; int sense_deferred = 0; @@ -929,6 +803,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) if (sense_valid) sense_deferred = scsi_sense_is_deferred(&sshdr); } + #ifdef CONFIG_SCSI_LOGGING SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", SCpnt->request->rq_disk->disk_name, result)); @@ -938,72 +813,89 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) sshdr.sense_key, sshdr.asc, sshdr.ascq)); } #endif - if (driver_byte(result) != DRIVER_SENSE && - (!sense_valid || sense_deferred)) - goto out; + /* + Handle MEDIUM ERRORs that indicate partial success. Since this is a + relatively rare error condition, no care is taken to avoid + unnecessary additional work such as memcpy's that could be avoided. + */ + if (driver_byte(result) != 0 && + sense_valid && !sense_deferred) { + switch (sshdr.sense_key) { + case MEDIUM_ERROR: + if (!blk_fs_request(SCpnt->request)) + break; + info_valid = scsi_get_sense_info_fld( + SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE, + &first_err_block); + /* + * May want to warn and skip if following cast results + * in actual truncation (if sector_t < 64 bits) + */ + error_sector = (sector_t)first_err_block; + if (SCpnt->request->bio != NULL) + block_sectors = bio_sectors(SCpnt->request->bio); + switch (SCpnt->device->sector_size) { + case 1024: + error_sector <<= 1; + if (block_sectors < 2) + block_sectors = 2; + break; + case 2048: + error_sector <<= 2; + if (block_sectors < 4) + block_sectors = 4; + break; + case 4096: + error_sector <<=3; + if (block_sectors < 8) + block_sectors = 8; + break; + case 256: + error_sector >>= 1; + break; + default: + break; + } - switch (sshdr.sense_key) { - case HARDWARE_ERROR: - case MEDIUM_ERROR: - if (!blk_fs_request(SCpnt->request)) - goto out; - info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - &bad_lba); - if (!info_valid) - goto out; - if (xfer_size <= SCpnt->device->sector_size) - goto out; - switch (SCpnt->device->sector_size) { - case 256: - start_lba <<= 1; + error_sector &= ~(block_sectors - 1); + good_bytes = (error_sector - SCpnt->request->sector) << 9; + if (good_bytes < 0 || good_bytes >= this_count) + good_bytes = 0; break; - case 512: - break; - case 1024: - start_lba >>= 1; - break; - case 2048: - start_lba >>= 2; + + case RECOVERED_ERROR: /* an error occurred, but it recovered */ + case NO_SENSE: /* LLDD got sense data */ + /* + * 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 = this_count; break; - case 4096: - start_lba >>= 3; + + case ILLEGAL_REQUEST: + if (SCpnt->device->use_10_for_rw && + (SCpnt->cmnd[0] == READ_10 || + SCpnt->cmnd[0] == WRITE_10)) + SCpnt->device->use_10_for_rw = 0; + if (SCpnt->device->use_10_for_ms && + (SCpnt->cmnd[0] == MODE_SENSE_10 || + SCpnt->cmnd[0] == MODE_SELECT_10)) + SCpnt->device->use_10_for_ms = 0; break; + default: - /* Print something here with limiting frequency. */ - goto out; break; } - /* This computation should always be done in terms of - * the resolution of the device's medium. - */ - good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size; - break; - case RECOVERED_ERROR: - case NO_SENSE: - /* 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 = xfer_size; - break; - case ILLEGAL_REQUEST: - if (SCpnt->device->use_10_for_rw && - (SCpnt->cmnd[0] == READ_10 || - SCpnt->cmnd[0] == WRITE_10)) - SCpnt->device->use_10_for_rw = 0; - if (SCpnt->device->use_10_for_ms && - (SCpnt->cmnd[0] == MODE_SENSE_10 || - SCpnt->cmnd[0] == MODE_SELECT_10)) - SCpnt->device->use_10_for_ms = 0; - break; - default: - break; } - out: - scsi_io_completion(SCpnt, good_bytes); + /* + * This calls the generic completion function, now that we know + * how many actual sectors finished, and how many sectors we need + * to say have failed. + */ + scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); } static int media_not_present(struct scsi_disk *sdkp, @@ -1441,12 +1333,6 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, if (!scsi_status_is_good(res)) goto bad_sense; - if (!data.header_length) { - modepage = 6; - printk(KERN_ERR "%s: missing header in MODE_SENSE response\n", - diskname); - } - /* that went OK, now ask for the proper length */ len = data.length; @@ -1468,6 +1354,10 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); if (scsi_status_is_good(res)) { + const char *types[] = { + "write through", "none", "write back", + "write back, no read (daft)" + }; int ct = 0; int offset = data.header_length + data.block_descriptor_length; @@ -1500,7 +1390,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ct = sdkp->RCD + 2*sdkp->WCE; printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n", - diskname, sd_cache_types[ct], + diskname, types[ct], sdkp->DPOFUA ? " w/ FUA" : ""); return; @@ -1627,10 +1517,13 @@ static int sd_probe(struct device *dev) "sd_attach\n")); error = -ENOMEM; - sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL); + sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL); if (!sdkp) goto out; + memset (sdkp, 0, sizeof(*sdkp)); + kref_init(&sdkp->kref); + gd = alloc_disk(16); if (!gd) goto out_free; @@ -1647,16 +1540,7 @@ static int sd_probe(struct device *dev) if (error) goto out_put; - class_device_initialize(&sdkp->cdev); - sdkp->cdev.dev = &sdp->sdev_gendev; - sdkp->cdev.class = &sd_disk_class; - strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE); - - if (class_device_add(&sdkp->cdev)) - goto out_put; - get_device(&sdp->sdev_gendev); - sdkp->device = sdp; sdkp->driver = &sd_template; sdkp->disk = gd; @@ -1688,6 +1572,8 @@ static int sd_probe(struct device *dev) 'a' + m1, 'a' + m2, 'a' + m3); } + strcpy(gd->devfs_name, sdp->devfs_name); + gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; @@ -1706,11 +1592,11 @@ static int sd_probe(struct device *dev) return 0; - out_put: +out_put: put_disk(gd); - out_free: +out_free: kfree(sdkp); - out: +out: return error; } @@ -1729,13 +1615,12 @@ static int sd_remove(struct device *dev) { struct scsi_disk *sdkp = dev_get_drvdata(dev); - class_device_del(&sdkp->cdev); del_gendisk(sdkp->disk); sd_shutdown(dev); mutex_lock(&sd_ref_mutex); dev_set_drvdata(dev, NULL); - class_device_put(&sdkp->cdev); + kref_put(&sdkp->kref, scsi_disk_release); mutex_unlock(&sd_ref_mutex); return 0; @@ -1743,16 +1628,16 @@ static int sd_remove(struct device *dev) /** * scsi_disk_release - Called to free the scsi_disk structure - * @cdev: pointer to embedded class device + * @kref: pointer to embedded kref * * sd_ref_mutex must be held entering this routine. Because it is * called on last put, you should always use the scsi_disk_get() * scsi_disk_put() helpers which manipulate the semaphore directly - * and never do a direct class_device_put(). + * and never do a direct kref_put(). **/ -static void scsi_disk_release(struct class_device *cdev) +static void scsi_disk_release(struct kref *kref) { - struct scsi_disk *sdkp = to_scsi_disk(cdev); + struct scsi_disk *sdkp = to_scsi_disk(kref); struct gendisk *disk = sdkp->disk; spin_lock(&sd_index_lock); @@ -1806,8 +1691,6 @@ static int __init init_sd(void) if (!majors) return -ENODEV; - class_register(&sd_disk_class); - return scsi_register_driver(&sd_template.gendrv); } @@ -1825,9 +1708,11 @@ static void __exit exit_sd(void) scsi_unregister_driver(&sd_template.gendrv); for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd"); - - class_unregister(&sd_disk_class); } +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Youngdale"); +MODULE_DESCRIPTION("SCSI disk (sd) driver"); + module_init(init_sd); module_exit(exit_sd);