Release 4.11 drivers/scsi/sd.c
/*
* sd.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
*
* Linux scsi disk driver
* Initial versions: Drew Eckhardt
* Subsequent revisions: Eric Youngdale
* Modification history:
* - Drew Eckhardt <drew@colorado.edu> original
* - Eric Youngdale <eric@andante.org> add scatter-gather, multiple
* outstanding request, and other enhancements.
* Support loadable low-level scsi drivers.
* - Jirka Hanika <geo@ff.cuni.cz> support more scsi disks using
* eight major numbers.
* - Richard Gooch <rgooch@atnf.csiro.au> support devfs.
* - Torben Mathiasen <tmm@image.dk> Resource allocation fixes in
* sd_init and cleanups.
* - Alex Davis <letmein@erols.com> Fix problem where partition info
* not being read in sd_open. Fix problem where removable media
* could be ejected after sd_open.
* - Douglas Gilbert <dgilbert@interlog.com> cleanup for lk 2.5.x
* - Badari Pulavarty <pbadari@us.ibm.com>, Matthew Wilcox
* <willy@debian.org>, Kurt Garloff <garloff@suse.de>:
* Support 32k/1M disks.
*
* Logging policy (needs CONFIG_SCSI_LOGGING defined):
* - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2
* - end of transfer (bh + scsi_lib): SCSI_LOG_HLCOMPLETE level 1
* - entering sd_ioctl: SCSI_LOG_IOCTL level 1
* - entering other commands: SCSI_LOG_HLQUEUE level 3
* Note: when the logging level is set by the user, it must be greater
* than the level indicated above to trigger output.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/bio.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/errno.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/string_helpers.h>
#include <linux/async.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/pr.h>
#include <linux/t10-pi.h>
#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_driver.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsicam.h>
#include "sd.h"
#include "scsi_priv.h"
#include "scsi_logging.h"
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);
MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);
MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC);
#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
#define SD_MINORS 16
#else
#define SD_MINORS 0
#endif
static void sd_config_discard(struct scsi_disk *, unsigned int);
static void sd_config_write_same(struct scsi_disk *);
static int sd_revalidate_disk(struct gendisk *);
static void sd_unlock_native_capacity(struct gendisk *disk);
static int sd_probe(struct device *);
static int sd_remove(struct device *);
static void sd_shutdown(struct device *);
static int sd_suspend_system(struct device *);
static int sd_suspend_runtime(struct device *);
static int sd_resume(struct device *);
static void sd_rescan(struct device *);
static int sd_init_command(struct scsi_cmnd *SCpnt);
static void sd_uninit_command(struct scsi_cmnd *SCpnt);
static int sd_done(struct scsi_cmnd *);
static int sd_eh_action(struct scsi_cmnd *, int);
static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
static void scsi_disk_release(struct device *cdev);
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
static void sd_print_result(const struct scsi_disk *, const char *, 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
* face of object destruction (i.e. we can't allow a get on an
* object after last put) */
static DEFINE_MUTEX(sd_ref_mutex);
static struct kmem_cache *sd_cdb_cache;
static mempool_t *sd_cdb_pool;
static const char *sd_cache_types[] = {
"write through", "none", "write back",
"write back, no read (daft)"
};
static void sd_set_flush_flag(struct scsi_disk *sdkp)
{
bool wc = false, fua = false;
if (sdkp->WCE) {
wc = true;
if (sdkp->DPOFUA)
fua = true;
}
blk_queue_write_cache(sdkp->disk->queue, wc, fua);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaughan Cao | 38 | 69.09% | 1 | 50.00% |
Jens Axboe | 17 | 30.91% | 1 | 50.00% |
Total | 55 | 100.00% | 2 | 100.00% |
static ssize_t
cache_type_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int i, ct = -1, rcd, wce, sp;
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
char buffer[64];
char *buffer_data;
struct scsi_mode_data data;
struct scsi_sense_hdr sshdr;
static const char temp[] = "temporary ";
int len;
if (sdp->type != TYPE_DISK && sdp->type != TYPE_ZBC)
/* 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;
if (strncmp(buf, temp, sizeof(temp) - 1) == 0) {
buf += sizeof(temp) - 1;
sdkp->cache_override = 1;
} else {
sdkp->cache_override = 0;
}
for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) {
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) && !sdkp->write_prot ? 1 : 0;
if (sdkp->cache_override) {
sdkp->WCE = wce;
sdkp->RCD = rcd;
sd_set_flush_flag(sdkp);
return count;
}
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;
buffer_data[0] &= ~0x80;
if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
SD_MAX_RETRIES, &data, &sshdr)) {
if (scsi_sense_valid(&sshdr))
sd_print_sense_hdr(sdkp, &sshdr);
return -EINVAL;
}
revalidate_disk(sdkp->disk);
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
James Bottomley | 393 | 89.73% | 2 | 14.29% |
Gabriel Krisman Bertazi | 8 | 1.83% | 1 | 7.14% |
Tony Jones | 8 | 1.83% | 1 | 7.14% |
Sujit Reddy Thumma | 7 | 1.60% | 1 | 7.14% |
Hannes Reinecke | 6 | 1.37% | 1 | 7.14% |
Vaughan Cao | 5 | 1.14% | 1 | 7.14% |
Andrew Morton | 3 | 0.68% | 1 | 7.14% |
H Hartley Sweeten | 2 | 0.46% | 1 | 7.14% |
Ben Hutchings | 2 | 0.46% | 1 | 7.14% |
Greg Kroah-Hartman | 1 | 0.23% | 1 | 7.14% |
Martin K. Petersen | 1 | 0.23% | 1 | 7.14% |
Tobias Klauser | 1 | 0.23% | 1 | 7.14% |
Andrew Patterson | 1 | 0.23% | 1 | 7.14% |
Total | 438 | 100.00% | 14 | 100.00% |
static ssize_t
manage_start_stop_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tejun Heo | 37 | 69.81% | 1 | 33.33% |
Greg Kroah-Hartman | 8 | 15.09% | 1 | 33.33% |
Tony Jones | 8 | 15.09% | 1 | 33.33% |
Total | 53 | 100.00% | 3 | 100.00% |
static ssize_t
manage_start_stop_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
sdp->manage_start_stop = simple_strtoul(buf, NULL, 10);
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Brian King | 61 | 85.92% | 1 | 33.33% |
Tony Jones | 8 | 11.27% | 1 | 33.33% |
Greg Kroah-Hartman | 2 | 2.82% | 1 | 33.33% |
Total | 71 | 100.00% | 3 | 100.00% |
static DEVICE_ATTR_RW(manage_start_stop);
static ssize_t
allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
James Bottomley | 25 | 54.35% | 2 | 25.00% |
Tony Jones | 8 | 17.39% | 1 | 12.50% |
Greg Kroah-Hartman | 7 | 15.22% | 1 | 12.50% |
Jens Axboe | 2 | 4.35% | 1 | 12.50% |
Linus Torvalds (pre-git) | 2 | 4.35% | 1 | 12.50% |
Christoph Hellwig | 2 | 4.35% | 2 | 25.00% |
Total | 46 | 100.00% | 8 | 100.00% |
static ssize_t
allow_restart_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (sdp->type != TYPE_DISK && sdp->type != TYPE_ZBC)
return -EINVAL;
sdp->allow_restart = simple_strtoul(buf, NULL, 10);
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 47 | 52.81% | 1 | 14.29% |
James Bottomley | 18 | 20.22% | 1 | 14.29% |
Tony Jones | 8 | 8.99% | 1 | 14.29% |
Hannes Reinecke | 6 | 6.74% | 1 | 14.29% |
Jens Axboe | 6 | 6.74% | 2 | 28.57% |
Alex Tomas | 4 | 4.49% | 1 | 14.29% |
Total | 89 | 100.00% | 7 | 100.00% |
static DEVICE_ATTR_RW(allow_restart);
static ssize_t
cache_type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
int ct = sdkp->RCD + 2*sdkp->WCE;
return snprintf(buf, 40, "%s\n", sd_cache_types[ct]);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tejun Heo | 34 | 58.62% | 1 | 33.33% |
Greg Kroah-Hartman | 16 | 27.59% | 1 | 33.33% |
Tony Jones | 8 | 13.79% | 1 | 33.33% |
Total | 58 | 100.00% | 3 | 100.00% |
static DEVICE_ATTR_RW(cache_type);
static ssize_t
FUA_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Brian King | 32 | 72.73% | 1 | 33.33% |
Tony Jones | 8 | 18.18% | 1 | 33.33% |
Greg Kroah-Hartman | 4 | 9.09% | 1 | 33.33% |
Total | 44 | 100.00% | 3 | 100.00% |
static DEVICE_ATTR_RO(FUA);
static ssize_t
protection_type_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->protection_type);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 43 | 97.73% | 1 | 50.00% |
Greg Kroah-Hartman | 1 | 2.27% | 1 | 50.00% |
Total | 44 | 100.00% | 2 | 100.00% |
static ssize_t
protection_type_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
unsigned int val;
int err;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
err = kstrtouint(buf, 10, &val);
if (err)
return err;
if (val >= 0 && val <= T10_PI_TYPE3_PROTECTION)
sdkp->protection_type = val;
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 89 | 97.80% | 2 | 50.00% |
Christoph Hellwig | 1 | 1.10% | 1 | 25.00% |
Greg Kroah-Hartman | 1 | 1.10% | 1 | 25.00% |
Total | 91 | 100.00% | 4 | 100.00% |
static DEVICE_ATTR_RW(protection_type);
static ssize_t
protection_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
unsigned int dif, dix;
dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
dix = scsi_host_dix_capable(sdp->host, sdkp->protection_type);
if (!dix && scsi_host_dix_capable(sdp->host, T10_PI_TYPE0_PROTECTION)) {
dif = 0;
dix = 1;
}
if (!dif && !dix)
return snprintf(buf, 20, "none\n");
return snprintf(buf, 20, "%s%u\n", dix ? "dix" : "dif", dif);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 129 | 98.47% | 2 | 50.00% |
Greg Kroah-Hartman | 1 | 0.76% | 1 | 25.00% |
Christoph Hellwig | 1 | 0.76% | 1 | 25.00% |
Total | 131 | 100.00% | 4 | 100.00% |
static DEVICE_ATTR_RO(protection_mode);
static ssize_t
app_tag_own_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->ATO);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 43 | 97.73% | 2 | 66.67% |
Greg Kroah-Hartman | 1 | 2.27% | 1 | 33.33% |
Total | 44 | 100.00% | 3 | 100.00% |
static DEVICE_ATTR_RO(app_tag_own);
static ssize_t
thin_provisioning_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->lbpme);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 43 | 97.73% | 2 | 66.67% |
Greg Kroah-Hartman | 1 | 2.27% | 1 | 33.33% |
Total | 44 | 100.00% | 3 | 100.00% |
static DEVICE_ATTR_RO(thin_provisioning);
static const char *lbp_mode[] = {
[SD_LBP_FULL] = "full",
[SD_LBP_UNMAP] = "unmap",
[SD_LBP_WS16] = "writesame_16",
[SD_LBP_WS10] = "writesame_10",
[SD_LBP_ZERO] = "writesame_zero",
[SD_LBP_DISABLE] = "disabled",
};
static ssize_t
provisioning_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%s\n", lbp_mode[sdkp->provisioning_mode]);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 46 | 97.87% | 1 | 50.00% |
Greg Kroah-Hartman | 1 | 2.13% | 1 | 50.00% |
Total | 47 | 100.00% | 2 | 100.00% |
static ssize_t
provisioning_mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (sd_is_zoned(sdkp)) {
sd_config_discard(sdkp, SD_LBP_DISABLE);
return count;
}
if (sdp->type != TYPE_DISK)
return -EINVAL;
if (!strncmp(buf, lbp_mode[SD_LBP_UNMAP], 20))
sd_config_discard(sdkp, SD_LBP_UNMAP);
else if (!strncmp(buf, lbp_mode[SD_LBP_WS16], 20))
sd_config_discard(sdkp, SD_LBP_WS16);
else if (!strncmp(buf, lbp_mode[SD_LBP_WS10], 20))
sd_config_discard(sdkp, SD_LBP_WS10);
else if (!strncmp(buf, lbp_mode[SD_LBP_ZERO], 20))
sd_config_discard(sdkp, SD_LBP_ZERO);
else if (!strncmp(buf, lbp_mode[SD_LBP_DISABLE], 20))
sd_config_discard(sdkp, SD_LBP_DISABLE);
else
return -EINVAL;
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 188 | 90.38% | 1 | 33.33% |
Hannes Reinecke | 19 | 9.13% | 1 | 33.33% |
Greg Kroah-Hartman | 1 | 0.48% | 1 | 33.33% |
Total | 208 | 100.00% | 3 | 100.00% |
static DEVICE_ATTR_RW(provisioning_mode);
static ssize_t
max_medium_access_timeouts_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->max_medium_access_timeouts);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 43 | 97.73% | 1 | 50.00% |
Greg Kroah-Hartman | 1 | 2.27% | 1 | 50.00% |
Total | 44 | 100.00% | 2 | 100.00% |
static ssize_t
max_medium_access_timeouts_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
int err;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
err = kstrtouint(buf, 10, &sdkp->max_medium_access_timeouts);
return err ? err : count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 69 | 98.57% | 1 | 50.00% |
Greg Kroah-Hartman | 1 | 1.43% | 1 | 50.00% |
Total | 70 | 100.00% | 2 | 100.00% |
static DEVICE_ATTR_RW(max_medium_access_timeouts);
static ssize_t
max_write_same_blocks_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->max_ws_blocks);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 43 | 97.73% | 1 | 50.00% |
Greg Kroah-Hartman | 1 | 2.27% | 1 | 50.00% |
Total | 44 | 100.00% | 2 | 100.00% |
static ssize_t
max_write_same_blocks_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
unsigned long max;
int err;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (sdp->type != TYPE_DISK && sdp->type != TYPE_ZBC)
return -EINVAL;
err = kstrtoul(buf, 10, &max);
if (err)
return err;
if (max == 0)
sdp->no_write_same = 1;
else if (max <= SD_MAX_WS16_BLOCKS) {
sdp->no_write_same = 0;
sdkp->max_ws_blocks = max;
}
sd_config_write_same(sdkp);
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin K. Petersen | 133 | 95.00% | 2 | 50.00% |
Hannes Reinecke | 6 | 4.29% | 1 | 25.00% |
Greg Kroah-Hartman | 1 | 0.71% | 1 | 25.00% |
Total | 140 | 100.00% | 4 | 100.00% |
static DEVICE_ATTR_RW(max_write_same_blocks);
static struct attribute *sd_disk_attrs[] = {
&dev_attr_cache_type.attr,
&dev_attr_FUA.attr,
&dev_attr_allow_restart.attr,
&dev_attr_manage_start_stop.attr,
&dev_attr_protection_type.attr,
&dev_attr_protection_mode.attr,
&dev_attr_app_tag_own.attr,
&dev_attr_thin_provisioning.attr,
&dev_attr_provisioning_mode.attr,
&dev_attr_max_write_same_blocks.attr,
&dev_attr_max_medium_access_timeouts.attr,
NULL,
};
ATTRIBUTE_GROUPS(sd_disk);
static struct class sd_disk_class = {
.name = "scsi_disk",
.owner = THIS_MODULE,
.dev_release = scsi_disk_release,
.dev_groups = sd_disk_groups,
};
static const struct dev_pm_ops sd_pm_ops = {
.suspend = sd_suspend_system,
.resume = sd_resume,
.poweroff = sd_suspend_system,
.restore = sd_resume,
.runtime_suspend = sd_suspend_runtime,
.runtime_resume = sd_resume,
};
static struct scsi_driver sd_template = {
.gendrv = {
.name = "sd",
.owner = THIS_MODULE,
.probe = sd_probe,
.remove = sd_remove,
.shutdown = sd_shutdown,
.pm = &sd_pm_ops,
},
.rescan = sd_rescan,
.init_command = sd_init_command,
.uninit_command = sd_uninit_command,
.done = sd_done,
.eh_action = sd_eh_action,
};
/*
* Dummy kobj_map->probe function.
* The default ->probe function will call modprobe, which is
* pointless as this module is already loaded.
*/
static struct kobject *sd_default_probe(dev_t devt, int *partno, void *data)
{
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hannes Reinecke | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
/*
* Device no to disk mapping:
*
* major disc2 disc p1
* |............|.............|....|....| <- dev_t
* 31 20 19 8 7 4 3 0
*
* Inside a major, we have 16k disks, however mapped non-
* contiguously. The first 16 disks are for major0, the next
* ones with major1, ... Disk 256 is for major0 again, disk 272
* for major1, ...
* As we stay compatible with our numbering scheme, we can reuse
* the well-know SCSI majors 8, 65--71, 136--143.
*/
static int sd_major(int major_idx)
{
switch (major_idx) {
case 0:
return SCSI_DISK0_MAJOR;
case 1 ... 7:
return SCSI_DISK1_MAJOR + major_idx - 1;
case 8 ... 15:
return SCSI_DISK8_MAJOR + major_idx - 8;
default:
BUG();
return 0; /* shut up gcc */
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christoph Hellwig | 51 | 96.23% | 1 | 50.00% |
Badari Pulavarty | 2 | 3.77% | 1 | 50.00% |
Total | 53 | 100.00% | 2 | 100.00% |
static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
{
struct scsi_disk *sdkp = NULL;
mutex_lock(&sd_ref_mutex);
if (disk->private_data) {
sdkp = scsi_disk(disk);
if (scsi_device_get(sdkp->device) == 0)
get_device(&sdkp->dev);
else
sdkp = NULL;
}
mutex_unlock(&sd_ref_mutex);
return sdkp;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
James Bottomley | 26 | 35.14% | 1 | 14.29% |
Mike Anderson | 18 | 24.32% | 1 | 14.29% |
Alan Stern | 18 | 24.32% | 1 | 14.29% |
Christoph Hellwig | 7 | 9.46% | 1 | 14.29% |
Arjan van de Ven | 2 | 2.70% | 1 | 14.29% |
Tony Jones | 2 | 2.70% | 1 | 14.29% |
Greg Kroah-Hartman | 1 | 1.35% | 1 | 14.29% |
Total | 74 | 100.00% | 7 | 100.00% |
static void scsi_disk_put(struct scsi_disk *sdkp)
{
struct scsi_device *sdev = sdkp->device;
mutex_lock(&sd_ref_mutex);
put_device(&sdkp->dev);
scsi_device_put(sdev);
mutex_unlock(&sd_ref_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Mike Anderson | 20 | 44.44% | 1 | 16.67% |
Alan Stern | 10 | 22.22% | 1 | 16.67% |
James Bottomley | 9 | 20.00% | 2 | 33.33% |
Arjan van de Ven | 4 | 8.89% | 1 | 16.67% |
Tony Jones | 2 | 4.44% | 1 | 16.67% |
Total | 45 | 100.00% | 6 | 100.00% |
static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
unsigned int dix, unsigned int dif)
{
struct bio *bio = scmd->request->bio;
unsigned int prot_op = sd_prot_op(rq_data_dir(scmd->request), dix, dif);
unsigned int protect = 0;
if (dix) { /* DIX Type 0, 1, 2, 3 */
if (bio_integrity_flagged(bio, BIP_IP_CHECKSUM))
scmd->prot_flags |= SCSI_PROT_IP_CHECKSUM;
if (bio_integrity_flagged(bio, BIP_CTRL_NOCHECK) == false)
scmd->prot_flags |= SCSI_PROT_GUARD_CHECK;
}
if (dif != T10_PI_TYPE3_PROTECTION) { /* DIX/DIF Type 0, 1, 2 */
scmd->prot_flags |= SCSI_PROT_REF_INCREMENT;
if (bio_integrity_flagged(bio, BIP_CTRL_NOCHECK) == false)
scmd->prot_flags |= SCSI_PROT_REF_CHECK;
}
if (dif) { /* DIX/DIF Type 1, 2, 3 */
scmd->prot_flags |= SCSI_PROT_TRANSFER_PI;