struct request_queue;
struct scsi_cmnd;
-struct scsi_mode_data;
+struct scsi_lun;
+struct scsi_sense_hdr;
+struct scsi_mode_data {
+ __u32 length;
+ __u16 block_descriptor_length;
+ __u8 medium_type;
+ __u8 device_specific;
+ __u8 header_length;
+ __u8 longlba:1;
+};
/*
* sdev state: If you alter this, you also need to alter scsi_sysfs.c
* originate in the mid-layer) */
SDEV_OFFLINE, /* Device offlined (by error handling or
* user request */
+ SDEV_BLOCK, /* Device blocked by scsi lld. No scsi
+ * commands from user or midlayer should be issued
+ * to the scsi lld. */
};
struct scsi_device {
struct list_head siblings; /* list of all devices on this host */
struct list_head same_target_siblings; /* just the devices sharing same target id */
- volatile unsigned short device_busy; /* commands actually active on low-level */
- spinlock_t sdev_lock; /* also the request queue_lock */
+ /* this is now protected by the request_queue->queue_lock */
+ unsigned int device_busy; /* commands actually active on
+ * low-level. protected by queue_lock. */
spinlock_t list_lock;
struct list_head cmd_list; /* queue of in use SCSI Command structures */
struct list_head starved_entry;
char devfs_name[256]; /* devfs junk */
char type;
char scsi_level;
+ char inq_periph_qual; /* PQ from INQUIRY data */
unsigned char inquiry_len; /* valid bytes in 'inquiry' */
unsigned char * inquiry; /* INQUIRY response data */
- char * vendor; /* [back_compat] point into 'inquiry' ... */
- char * model; /* ... after scan; point to static string */
- char * rev; /* ... "nullnullnullnull" before scan */
+ const char * vendor; /* [back_compat] point into 'inquiry' ... */
+ const char * model; /* ... after scan; point to static string */
+ const char * rev; /* ... "nullnullnullnull" before scan */
unsigned char current_tag; /* current tag */
struct scsi_target *sdev_target; /* used only for single_lun */
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 */
+ unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
+ unsigned select_no_atn:1;
+ unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */
+ unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */
unsigned int device_blocked; /* Device returned QUEUE_FULL. */
unsigned int max_device_blocked; /* what device_blocked counts down from */
#define SCSI_DEFAULT_DEVICE_BLOCKED 3
+ atomic_t iorequest_cnt;
+ atomic_t iodone_cnt;
+ atomic_t ioerr_cnt;
+
+ int timeout;
+
struct device sdev_gendev;
struct class_device sdev_classdev;
- struct class_device transport_classdev;
-
enum scsi_device_state sdev_state;
- unsigned long transport_data[0];
+ unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
#define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev)
#define class_to_sdev(d) \
container_of(d, struct scsi_device, sdev_classdev)
#define transport_class_to_sdev(class_dev) \
- container_of(class_dev, struct scsi_device, transport_classdev)
+ to_scsi_device(class_dev->dev)
+
+#define sdev_printk(prefix, sdev, fmt, a...) \
+ dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a)
+
+#define scmd_printk(prefix, scmd, fmt, a...) \
+ dev_printk(prefix, &(scmd)->device->sdev_gendev, fmt, ##a)
+
+/*
+ * scsi_target: representation of a scsi target, for now, this is only
+ * used for single_lun devices. If no one has active IO to the target,
+ * starget_sdev_user is NULL, else it points to the active sdev.
+ */
+struct scsi_target {
+ struct scsi_device *starget_sdev_user;
+ struct list_head siblings;
+ struct list_head devices;
+ struct device dev;
+ unsigned int reap_ref; /* protected by the host lock */
+ unsigned int channel;
+ unsigned int id; /* target id ... replace
+ * scsi_device.id eventually */
+ unsigned long create:1; /* signal that it needs to be added */
+ char scsi_level;
+ void *hostdata; /* available to low-level driver */
+ unsigned long starget_data[0]; /* for the transport */
+ /* starget_data must be the last element!!!! */
+} __attribute__((aligned(sizeof(unsigned long))));
+
+#define to_scsi_target(d) container_of(d, struct scsi_target, dev)
+static inline struct scsi_target *scsi_target(struct scsi_device *sdev)
+{
+ return to_scsi_target(sdev->sdev_gendev.parent);
+}
+#define transport_class_to_starget(class_dev) \
+ to_scsi_target(class_dev->dev)
+
+#define starget_printk(prefix, starget, fmt, a...) \
+ dev_printk(prefix, &(starget)->dev, fmt, ##a)
-extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
- uint, uint, uint);
+extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
+ uint, uint, uint, void *hostdata);
+extern int scsi_add_device(struct Scsi_Host *host, uint channel,
+ uint target, uint lun);
extern void scsi_remove_device(struct scsi_device *);
extern int scsi_device_cancel(struct scsi_device *, int);
uint, uint, uint);
extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *,
uint, uint, uint);
+extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *,
+ uint);
+extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *,
+ uint);
+extern void starget_for_each_device(struct scsi_target *, void *,
+ void (*fn)(struct scsi_device *, void *));
/* only exposed to implement shost_for_each_device */
extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *,
extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
unsigned char *buffer, int len, int timeout,
- int retries, struct scsi_mode_data *data);
+ int retries, struct scsi_mode_data *data,
+ struct scsi_sense_hdr *);
+extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
+ int retries);
extern int scsi_device_set_state(struct scsi_device *sdev,
enum scsi_device_state state);
extern int scsi_device_quiesce(struct scsi_device *sdev);
extern void scsi_device_resume(struct scsi_device *sdev);
+extern void scsi_target_quiesce(struct scsi_target *);
+extern void scsi_target_resume(struct scsi_target *);
+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_remove_target(struct device *);
+extern void int_to_scsilun(unsigned int, struct scsi_lun *);
extern const char *scsi_device_state_name(enum scsi_device_state);
-static int inline scsi_device_online(struct scsi_device *sdev)
+extern int scsi_is_sdev_device(const struct device *);
+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);
+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);
+extern int scsi_execute_async(struct scsi_device *sdev,
+ const unsigned char *cmd, int cmd_len, int data_direction,
+ void *buffer, unsigned bufflen, int use_sg,
+ int timeout, int retries, void *privdata,
+ void (*done)(void *, char *, int, int),
+ gfp_t gfp);
+
+static inline unsigned int sdev_channel(struct scsi_device *sdev)
+{
+ return sdev->channel;
+}
+
+static inline unsigned int sdev_id(struct scsi_device *sdev)
+{
+ return sdev->id;
+}
+
+#define scmd_id(scmd) sdev_id((scmd)->device)
+#define scmd_channel(scmd) sdev_channel((scmd)->device)
+
+static inline int scsi_device_online(struct scsi_device *sdev)
{
return sdev->sdev_state != SDEV_OFFLINE;
}
+
+/* accessor functions for the SCSI parameters */
+static inline int scsi_device_sync(struct scsi_device *sdev)
+{
+ return sdev->sdtr;
+}
+static inline int scsi_device_wide(struct scsi_device *sdev)
+{
+ return sdev->wdtr;
+}
+static inline int scsi_device_dt(struct scsi_device *sdev)
+{
+ return sdev->ppr;
+}
+static inline int scsi_device_dt_only(struct scsi_device *sdev)
+{
+ if (sdev->inquiry_len < 57)
+ return 0;
+ return (sdev->inquiry[56] & 0x0c) == 0x04;
+}
+static inline int scsi_device_ius(struct scsi_device *sdev)
+{
+ if (sdev->inquiry_len < 57)
+ return 0;
+ return sdev->inquiry[56] & 0x01;
+}
+static inline int scsi_device_qas(struct scsi_device *sdev)
+{
+ if (sdev->inquiry_len < 57)
+ return 0;
+ return sdev->inquiry[56] & 0x02;
+}
#endif /* _SCSI_SCSI_DEVICE_H */