⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libata-scsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  libata-scsi.c - helper library for ATA * *  Maintained by:  Jeff Garzik <jgarzik@pobox.com> *    		    Please ALWAYS copy linux-ide@vger.kernel.org *		    on emails. * *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved. *  Copyright 2003-2004 Jeff Garzik * * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * *  libata documentation is available via 'make {ps|pdf}docs', *  as Documentation/DocBook/libata.* * *  Hardware documentation available from *  - http://www.t10.org/ *  - http://www.t13.org/ * */#include <linux/kernel.h>#include <linux/blkdev.h>#include <linux/spinlock.h>#include <scsi/scsi.h>#include <scsi/scsi_host.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_eh.h>#include <scsi/scsi_device.h>#include <scsi/scsi_tcq.h>#include <scsi/scsi_transport.h>#include <linux/libata.h>#include <linux/hdreg.h>#include <linux/uaccess.h>#include "libata.h"#define SECTOR_SIZE	512typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,					const struct scsi_device *scsidev);static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,					    const struct scsi_device *scsidev);static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,			      unsigned int id, unsigned int lun);#define RW_RECOVERY_MPAGE 0x1#define RW_RECOVERY_MPAGE_LEN 12#define CACHE_MPAGE 0x8#define CACHE_MPAGE_LEN 20#define CONTROL_MPAGE 0xa#define CONTROL_MPAGE_LEN 12#define ALL_MPAGES 0x3f#define ALL_SUB_MPAGES 0xffstatic const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {	RW_RECOVERY_MPAGE,	RW_RECOVERY_MPAGE_LEN - 2,	(1 << 7),	/* AWRE */	0,		/* read retry count */	0, 0, 0, 0,	0,		/* write retry count */	0, 0, 0};static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = {	CACHE_MPAGE,	CACHE_MPAGE_LEN - 2,	0,		/* contains WCE, needs to be 0 for logic */	0, 0, 0, 0, 0, 0, 0, 0, 0,	0,		/* contains DRA, needs to be 0 for logic */	0, 0, 0, 0, 0, 0, 0};static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {	CONTROL_MPAGE,	CONTROL_MPAGE_LEN - 2,	2,	/* DSENSE=0, GLTSD=1 */	0,	/* [QAM+QERR may be 1, see 05-359r1] */	0, 0, 0, 0, 0xff, 0xff,	0, 30	/* extended self test time, see 05-359r1 */};/* * libata transport template.  libata doesn't do real transport stuff. * It just needs the eh_timed_out hook. */static struct scsi_transport_template ata_scsi_transport_template = {	.eh_strategy_handler	= ata_scsi_error,	.eh_timed_out		= ata_scsi_timed_out,	.user_scan		= ata_scsi_user_scan,};static const struct {	enum link_pm	value;	const char	*name;} link_pm_policy[] = {	{ NOT_AVAILABLE, "max_performance" },	{ MIN_POWER, "min_power" },	{ MAX_PERFORMANCE, "max_performance" },	{ MEDIUM_POWER, "medium_power" },};static const char *ata_scsi_lpm_get(enum link_pm policy){	int i;	for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++)		if (link_pm_policy[i].value == policy)			return link_pm_policy[i].name;	return NULL;}static ssize_t ata_scsi_lpm_put(struct class_device *class_dev,	const char *buf, size_t count){	struct Scsi_Host *shost = class_to_shost(class_dev);	struct ata_port *ap = ata_shost_to_port(shost);	enum link_pm policy = 0;	int i;	/*	 * we are skipping array location 0 on purpose - this	 * is because a value of NOT_AVAILABLE is displayed	 * to the user as max_performance, but when the user	 * writes "max_performance", they actually want the	 * value to match MAX_PERFORMANCE.	 */	for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {		const int len = strlen(link_pm_policy[i].name);		if (strncmp(link_pm_policy[i].name, buf, len) == 0 &&		   buf[len] == '\n') {			policy = link_pm_policy[i].value;			break;		}	}	if (!policy)		return -EINVAL;	ata_lpm_schedule(ap, policy);	return count;}static ssize_tata_scsi_lpm_show(struct class_device *class_dev, char *buf){	struct Scsi_Host *shost = class_to_shost(class_dev);	struct ata_port *ap = ata_shost_to_port(shost);	const char *policy =		ata_scsi_lpm_get(ap->pm_policy);	if (!policy)		return -EINVAL;	return snprintf(buf, 23, "%s\n", policy);}CLASS_DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,		ata_scsi_lpm_show, ata_scsi_lpm_put);EXPORT_SYMBOL_GPL(class_device_attr_link_power_management_policy);static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,				   void (*done)(struct scsi_cmnd *)){	ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);	/* "Invalid field in cbd" */	done(cmd);}/** *	ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. *	@sdev: SCSI device for which BIOS geometry is to be determined *	@bdev: block device associated with @sdev *	@capacity: capacity of SCSI device *	@geom: location to which geometry will be output * *	Generic bios head/sector/cylinder calculator *	used by sd. Most BIOSes nowadays expect a XXX/255/16  (CHS) *	mapping. Some situations may arise where the disk is not *	bootable if this is not used. * *	LOCKING: *	Defined by the SCSI layer.  We don't really care. * *	RETURNS: *	Zero. */int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,		       sector_t capacity, int geom[]){	geom[0] = 255;	geom[1] = 63;	sector_div(capacity, 255*63);	geom[2] = capacity;	return 0;}/** *	ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl *	@sdev: SCSI device to get identify data for *	@arg: User buffer area for identify data * *	LOCKING: *	Defined by the SCSI layer.  We don't really care. * *	RETURNS: *	Zero on success, negative errno on error. */static int ata_get_identity(struct scsi_device *sdev, void __user *arg){	struct ata_port *ap = ata_shost_to_port(sdev->host);	struct ata_device *dev = ata_scsi_find_dev(ap, sdev);	u16 __user *dst = arg;	char buf[40];	if (!dev)		return -ENOMSG;	if (copy_to_user(dst, dev->id, ATA_ID_WORDS * sizeof(u16)))		return -EFAULT;	ata_id_string(dev->id, buf, ATA_ID_PROD, ATA_ID_PROD_LEN);	if (copy_to_user(dst + ATA_ID_PROD, buf, ATA_ID_PROD_LEN))		return -EFAULT;	ata_id_string(dev->id, buf, ATA_ID_FW_REV, ATA_ID_FW_REV_LEN);	if (copy_to_user(dst + ATA_ID_FW_REV, buf, ATA_ID_FW_REV_LEN))		return -EFAULT;	ata_id_string(dev->id, buf, ATA_ID_SERNO, ATA_ID_SERNO_LEN);	if (copy_to_user(dst + ATA_ID_SERNO, buf, ATA_ID_SERNO_LEN))		return -EFAULT;	return 0;}/** *	ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl *	@scsidev: Device to which we are issuing command *	@arg: User provided data for issuing command * *	LOCKING: *	Defined by the SCSI layer.  We don't really care. * *	RETURNS: *	Zero on success, negative errno on error. */int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg){	int rc = 0;	u8 scsi_cmd[MAX_COMMAND_SIZE];	u8 args[4], *argbuf = NULL, *sensebuf = NULL;	int argsize = 0;	enum dma_data_direction data_dir;	int cmd_result;	if (arg == NULL)		return -EINVAL;	if (copy_from_user(args, arg, sizeof(args)))		return -EFAULT;	sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);	if (!sensebuf)		return -ENOMEM;	memset(scsi_cmd, 0, sizeof(scsi_cmd));	if (args[3]) {		argsize = SECTOR_SIZE * args[3];		argbuf = kmalloc(argsize, GFP_KERNEL);		if (argbuf == NULL) {			rc = -ENOMEM;			goto error;		}		scsi_cmd[1]  = (4 << 1); /* PIO Data-in */		scsi_cmd[2]  = 0x0e;     /* no off.line or cc, read from dev,					    block count in sector count field */		data_dir = DMA_FROM_DEVICE;	} else {		scsi_cmd[1]  = (3 << 1); /* Non-data */		scsi_cmd[2]  = 0x20;     /* cc but no off.line or data xfer */		data_dir = DMA_NONE;	}	scsi_cmd[0] = ATA_16;	scsi_cmd[4] = args[2];	if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */		scsi_cmd[6]  = args[3];		scsi_cmd[8]  = args[1];		scsi_cmd[10] = 0x4f;		scsi_cmd[12] = 0xc2;	} else {		scsi_cmd[6]  = args[1];	}	scsi_cmd[14] = args[0];	/* Good values for timeout and retries?  Values below	   from scsi_ioctl_send_command() for default case... */	cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,				  sensebuf, (10*HZ), 5, 0);	if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */		u8 *desc = sensebuf + 8;		cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */		/* If we set cc then ATA pass-through will cause a		 * check condition even if no error. Filter that. */		if (cmd_result & SAM_STAT_CHECK_CONDITION) {			struct scsi_sense_hdr sshdr;			scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,					     &sshdr);			if (sshdr.sense_key == 0 &&			    sshdr.asc == 0 && sshdr.ascq == 0)				cmd_result &= ~SAM_STAT_CHECK_CONDITION;		}		/* Send userspace a few ATA registers (same as drivers/ide) */		if (sensebuf[0] == 0x72 &&	/* format is "descriptor" */		    desc[0] == 0x09) {		/* code is "ATA Descriptor" */			args[0] = desc[13];	/* status */			args[1] = desc[3];	/* error */			args[2] = desc[5];	/* sector count (0:7) */			if (copy_to_user(arg, args, sizeof(args)))				rc = -EFAULT;		}	}	if (cmd_result) {		rc = -EIO;		goto error;	}	if ((argbuf)	 && copy_to_user(arg + sizeof(args), argbuf, argsize))		rc = -EFAULT;error:	kfree(sensebuf);	kfree(argbuf);	return rc;}/** *	ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl *	@scsidev: Device to which we are issuing command *	@arg: User provided data for issuing command * *	LOCKING: *	Defined by the SCSI layer.  We don't really care. * *	RETURNS: *	Zero on success, negative errno on error. */int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg){	int rc = 0;	u8 scsi_cmd[MAX_COMMAND_SIZE];	u8 args[7], *sensebuf = NULL;	int cmd_result;	if (arg == NULL)		return -EINVAL;	if (copy_from_user(args, arg, sizeof(args)))		return -EFAULT;	sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);	if (!sensebuf)		return -ENOMEM;	memset(scsi_cmd, 0, sizeof(scsi_cmd));	scsi_cmd[0]  = ATA_16;	scsi_cmd[1]  = (3 << 1); /* Non-data */	scsi_cmd[2]  = 0x20;     /* cc but no off.line or data xfer */	scsi_cmd[4]  = args[1];	scsi_cmd[6]  = args[2];	scsi_cmd[8]  = args[3];	scsi_cmd[10] = args[4];	scsi_cmd[12] = args[5];	scsi_cmd[13] = args[6] & 0x4f;	scsi_cmd[14] = args[0];	/* Good values for timeout and retries?  Values below	   from scsi_ioctl_send_command() for default case... */	cmd_result = scsi_execute(scsidev, scsi_cmd, DMA_NONE, NULL, 0,				sensebuf, (10*HZ), 5, 0);	if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */		u8 *desc = sensebuf + 8;		cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */		/* If we set cc then ATA pass-through will cause a		 * check condition even if no error. Filter that. */		if (cmd_result & SAM_STAT_CHECK_CONDITION) {			struct scsi_sense_hdr sshdr;			scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,						&sshdr);			if (sshdr.sense_key == 0 &&				sshdr.asc == 0 && sshdr.ascq == 0)				cmd_result &= ~SAM_STAT_CHECK_CONDITION;		}		/* Send userspace ATA registers */		if (sensebuf[0] == 0x72 &&	/* format is "descriptor" */				desc[0] == 0x09) {/* code is "ATA Descriptor" */			args[0] = desc[13];	/* status */			args[1] = desc[3];	/* error */			args[2] = desc[5];	/* sector count (0:7) */			args[3] = desc[7];	/* lbal */			args[4] = desc[9];	/* lbam */			args[5] = desc[11];	/* lbah */			args[6] = desc[12];	/* select */			if (copy_to_user(arg, args, sizeof(args)))				rc = -EFAULT;		}	}	if (cmd_result) {		rc = -EIO;		goto error;	} error:	kfree(sensebuf);	return rc;}int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg){	int val = -EINVAL, rc = -EINVAL;	switch (cmd) {	case ATA_IOC_GET_IO32:		val = 0;		if (copy_to_user(arg, &val, 1))			return -EFAULT;		return 0;	case ATA_IOC_SET_IO32:		val = (unsigned long) arg;		if (val != 0)			return -EINVAL;		return 0;	case HDIO_GET_IDENTITY:		return ata_get_identity(scsidev, arg);	case HDIO_DRIVE_CMD:		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))			return -EACCES;		return ata_cmd_ioctl(scsidev, arg);	case HDIO_DRIVE_TASK:		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))			return -EACCES;		return ata_task_ioctl(scsidev, arg);	default:		rc = -ENOTTY;		break;	}	return rc;}/** *	ata_scsi_qc_new - acquire new ata_queued_cmd reference *	@dev: ATA device to which the new command is attached *	@cmd: SCSI command that originated this ATA command *	@done: SCSI command completion function * *	Obtain a reference to an unused ata_queued_cmd structure, *	which is the basic libata structure representing a single *	ATA command sent to the hardware. * *	If a command was available, fill in the SCSI-specific *	portions of the structure with information on the

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -