/*
* 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 <asm/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);
#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)
{
unsigned flush = 0;
if (sdkp->WCE) {
flush |= REQ_FLUSH;
if (sdkp->DPOFUA)
flush |= REQ_FUA;
}
blk_queue_flush(sdkp->disk->queue, flush);
}
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)
/* 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;
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;
}
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);
}
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;
}
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);
}
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_de
sd.rar_The Majors
版权申诉
102 浏览量
2022-09-21
19:52:00
上传
评论
收藏 25KB RAR 举报
我虽横行却不霸道
- 粉丝: 72
- 资源: 1万+
最新资源
- 上市公司-股票性质数据-工具变量(民企、国企、央企)2003-2022年.dta
- 上市公司-股票性质数据-工具变量(民企、国企、央企)2003-2022年.xlsx
- Reeds+Shepp曲线算法讲解和实现.pdf
- 毕业设计基于SpringBoot+MyBatisPlus+MySQL+Vue的外卖配送信息系统源代码+数据库
- 词向量(Word Embeddings)是自然语言处理(NLP)领域的一种重要技术.txt
- Surfer,线性函数
- MyBatis 的动态 SQL 是其核心特性之一.txt
- 时代的sdddsddsddsd
- 基于哈希链表的简单人员信息管理系统
- 其他类别JdonFramework开源框架 v5.1 Build20071025-jdonframework-5.1.rar
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
评论0