diff options
Diffstat (limited to 'include/scsi/scsi_device.h')
| -rw-r--r-- | include/scsi/scsi_device.h | 94 | 
1 files changed, 80 insertions, 14 deletions
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 85867dcde33..27ab31017f0 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -1,14 +1,14 @@  #ifndef _SCSI_SCSI_DEVICE_H  #define _SCSI_SCSI_DEVICE_H -#include <linux/device.h>  #include <linux/list.h>  #include <linux/spinlock.h>  #include <linux/workqueue.h>  #include <linux/blkdev.h>  #include <scsi/scsi.h> -#include <asm/atomic.h> +#include <linux/atomic.h> +struct device;  struct request_queue;  struct scsi_cmnd;  struct scsi_lun; @@ -42,6 +42,7 @@ enum scsi_device_state {  				 * originate in the mid-layer) */  	SDEV_OFFLINE,		/* Device offlined (by error handling or  				 * user request */ +	SDEV_TRANSPORT_OFFLINE,	/* Offlined by transport class error handler */  	SDEV_BLOCK,		/* Device blocked by scsi lld.  No  				 * scsi commands from user or midlayer  				 * should be issued to the scsi @@ -51,8 +52,15 @@ enum scsi_device_state {  enum scsi_device_event {  	SDEV_EVT_MEDIA_CHANGE	= 1,	/* media has changed */ +	SDEV_EVT_INQUIRY_CHANGE_REPORTED,		/* 3F 03  UA reported */ +	SDEV_EVT_CAPACITY_CHANGE_REPORTED,		/* 2A 09  UA reported */ +	SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED,	/* 38 07  UA reported */ +	SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED,	/* 2A 01  UA reported */ +	SDEV_EVT_LUN_CHANGE_REPORTED,			/* 3F 0E  UA reported */ + +	SDEV_EVT_FIRST		= SDEV_EVT_MEDIA_CHANGE, +	SDEV_EVT_LAST		= SDEV_EVT_LUN_CHANGE_REPORTED, -	SDEV_EVT_LAST		= SDEV_EVT_MEDIA_CHANGE,  	SDEV_EVT_MAXBITS	= SDEV_EVT_LAST + 1  }; @@ -105,6 +113,12 @@ struct scsi_device {  	const char * vendor;		/* [back_compat] point into 'inquiry' ... */  	const char * model;		/* ... after scan; point to static string */  	const char * rev;		/* ... "nullnullnullnull" before scan */ + +#define SCSI_VPD_PG_LEN                255 +	int vpd_pg83_len; +	unsigned char *vpd_pg83; +	int vpd_pg80_len; +	unsigned char *vpd_pg80;  	unsigned char current_tag;	/* current tag */  	struct scsi_target      *sdev_target;   /* used only for single_lun */ @@ -112,6 +126,7 @@ struct scsi_device {  				 * scsi_devinfo.[hc]. For now used only to  				 * pass settings from slave_alloc to scsi  				 * core. */ +	unsigned int eh_timeout; /* Error handling timeout */  	unsigned writeable:1;  	unsigned removable:1;  	unsigned changed:1;	/* Data invalid due to media change */ @@ -134,8 +149,12 @@ struct scsi_device {  				     * because we did a bus reset. */  	unsigned use_10_for_rw:1; /* first try 10-byte read / write */  	unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ +	unsigned no_report_opcodes:1;	/* no REPORT SUPPORTED OPERATION CODES */ +	unsigned no_write_same:1;	/* no WRITE SAME command */ +	unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */  	unsigned skip_ms_page_8:1;	/* do not use MODE SENSE page 0x08 */  	unsigned skip_ms_page_3f:1;	/* do not use MODE SENSE page 0x3f */ +	unsigned skip_vpd_pages:1;	/* do not read VPD pages */  	unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */  	unsigned no_start_on_add:1;	/* do not issue start on add */  	unsigned allow_restart:1; /* issue START_UNIT in error handler */ @@ -150,9 +169,16 @@ struct scsi_device {  					   SD_LAST_BUGGY_SECTORS */  	unsigned no_read_disc_info:1;	/* Avoid READ_DISC_INFO cmds */  	unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */ +	unsigned try_rc_10_first:1;	/* Try READ_CAPACACITY_10 first */  	unsigned is_visible:1;	/* is the device visible in sysfs */ +	unsigned wce_default_on:1;	/* Cache is ON by default */ +	unsigned no_dif:1;	/* T10 PI (DIF) should be disabled */ +	unsigned broken_fua:1;		/* Don't set FUA bit */ + +	atomic_t disk_events_disable_depth; /* disable depth for disk events */  	DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ +	DECLARE_BITMAP(pending_events, SDEV_EVT_MAXBITS); /* pending events */  	struct list_head event_list;	/* asserted events */  	struct work_struct event_work; @@ -169,6 +195,7 @@ struct scsi_device {  				sdev_dev;  	struct execute_work	ew; /* used to get process context on put */ +	struct work_struct	requeue_work;  	struct scsi_dh_data	*scsi_dh_data;  	enum scsi_device_state sdev_state; @@ -195,6 +222,7 @@ struct scsi_device_handler {  	int (*activate)(struct scsi_device *, activate_complete, void *);  	int (*prep_fn)(struct scsi_device *, struct request *);  	int (*set_params)(struct scsi_device *, const char *); +	bool (*match)(struct scsi_device *);  };  struct scsi_dh_data { @@ -214,12 +242,24 @@ struct scsi_dh_data {  #define sdev_printk(prefix, sdev, fmt, a...)	\  	dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a) +#define sdev_dbg(sdev, fmt, a...) \ +	dev_dbg(&(sdev)->sdev_gendev, fmt, ##a) +  #define scmd_printk(prefix, scmd, fmt, a...)				\          (scmd)->request->rq_disk ?					\  	sdev_printk(prefix, (scmd)->device, "[%s] " fmt,		\  		    (scmd)->request->rq_disk->disk_name, ##a) :		\  	sdev_printk(prefix, (scmd)->device, fmt, ##a) +#define scmd_dbg(scmd, fmt, a...)					   \ +	do {								   \ +		if ((scmd)->request->rq_disk)				   \ +			sdev_dbg((scmd)->device, "[%s] " fmt,		   \ +				 (scmd)->request->rq_disk->disk_name, ##a);\ +		else							   \ +			sdev_dbg((scmd)->device, fmt, ##a);		   \ +	} while (0) +  enum scsi_target_state {  	STARGET_CREATED = 1,  	STARGET_RUNNING, @@ -236,7 +276,7 @@ struct scsi_target {  	struct list_head	siblings;  	struct list_head	devices;  	struct device		dev; -	unsigned int		reap_ref; /* protected by the host lock */ +	struct kref		reap_ref; /* last put renders target invisible */  	unsigned int		channel;  	unsigned int		id; /* target id ... replace  				     * scsi_device.id eventually */ @@ -244,8 +284,13 @@ struct scsi_target {  	unsigned int		single_lun:1;	/* Indicates we should only  						 * allow I/O to one of the luns  						 * for the device at a time. */ -	unsigned int		pdt_1f_for_no_lun;	/* PDT = 0x1f */ -						/* means no lun present */ +	unsigned int		pdt_1f_for_no_lun:1;	/* PDT = 0x1f +						 * means no lun present. */ +	unsigned int		no_report_luns:1;	/* Don't use +						 * REPORT LUNS for scanning. */ +	unsigned int		expecting_lun_change:1;	/* A device has reported +						 * a 3F/0E UA, other devices on +						 * the same target will also. */  	/* commands actually active on LLD. protected by host lock. */  	unsigned int		target_busy;  	/* @@ -258,7 +303,6 @@ struct scsi_target {  #define SCSI_DEFAULT_TARGET_BLOCKED	3  	char			scsi_level; -	struct execute_work	ew;  	enum scsi_target_state	state;  	void 			*hostdata; /* available to low-level driver */  	unsigned long		starget_data[0]; /* for the transport */ @@ -283,6 +327,7 @@ extern int scsi_add_device(struct Scsi_Host *host, uint channel,  extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);  extern void scsi_remove_device(struct scsi_device *);  extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); +void scsi_attach_vpd(struct scsi_device *sdev);  extern int scsi_device_get(struct scsi_device *);  extern void scsi_device_put(struct scsi_device *); @@ -352,6 +397,8 @@ extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,  				int retries, struct scsi_sense_hdr *sshdr);  extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf,  			     int buf_len); +extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, +			      unsigned int len, unsigned char opcode);  extern int scsi_device_set_state(struct scsi_device *sdev,  				 enum scsi_device_state state);  extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, @@ -367,7 +414,7 @@ extern void scsi_scan_target(struct device *parent, unsigned int channel,  			     unsigned int id, unsigned int lun, int rescan);  extern void scsi_target_reap(struct scsi_target *);  extern void scsi_target_block(struct device *); -extern void scsi_target_unblock(struct device *); +extern void scsi_target_unblock(struct device *, enum scsi_device_state);  extern void scsi_remove_target(struct device *);  extern void int_to_scsilun(unsigned int, struct scsi_lun *);  extern int scsilun_to_int(struct scsi_lun *); @@ -377,11 +424,21 @@ extern int scsi_is_target_device(const struct device *);  extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,  			int data_direction, void *buffer, unsigned bufflen,  			unsigned char *sense, int timeout, int retries, -			int flag, int *resid); -extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, -			    int data_direction, void *buffer, unsigned bufflen, -			    struct scsi_sense_hdr *, int timeout, int retries, -			    int *resid); +			u64 flags, int *resid); +extern int scsi_execute_req_flags(struct scsi_device *sdev, +	const unsigned char *cmd, int data_direction, void *buffer, +	unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout, +	int retries, int *resid, u64 flags); +static inline int scsi_execute_req(struct scsi_device *sdev, +	const unsigned char *cmd, int data_direction, void *buffer, +	unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout, +	int retries, int *resid) +{ +	return scsi_execute_req_flags(sdev, cmd, data_direction, buffer, +		bufflen, sshdr, timeout, retries, resid, 0); +} +extern void sdev_disable_disk_events(struct scsi_device *sdev); +extern void sdev_enable_disk_events(struct scsi_device *sdev);  #ifdef CONFIG_PM_RUNTIME  extern int scsi_autopm_get_device(struct scsi_device *); @@ -415,6 +472,7 @@ static inline unsigned int sdev_id(struct scsi_device *sdev)  static inline int scsi_device_online(struct scsi_device *sdev)  {  	return (sdev->sdev_state != SDEV_OFFLINE && +		sdev->sdev_state != SDEV_TRANSPORT_OFFLINE &&  		sdev->sdev_state != SDEV_DEL);  }  static inline int scsi_device_blocked(struct scsi_device *sdev) @@ -461,14 +519,22 @@ static inline int scsi_device_qas(struct scsi_device *sdev)  }  static inline int scsi_device_enclosure(struct scsi_device *sdev)  { -	return sdev->inquiry[6] & (1<<6); +	return sdev->inquiry ? (sdev->inquiry[6] & (1<<6)) : 1;  }  static inline int scsi_device_protection(struct scsi_device *sdev)  { +	if (sdev->no_dif) +		return 0; +  	return sdev->scsi_level > SCSI_2 && sdev->inquiry[5] & (1<<0);  } +static inline int scsi_device_tpgs(struct scsi_device *sdev) +{ +	return sdev->inquiry ? (sdev->inquiry[5] >> 4) & 0x3 : 0; +} +  #define MODULE_ALIAS_SCSI_DEVICE(type) \  	MODULE_ALIAS("scsi:t-" __stringify(type) "*")  #define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x"  | 
