X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=include%2Fscsi%2Fscsi_host.h;h=7f1f411d07af04c47f1faf7ce6400b57c197fef2;hb=refs%2Fheads%2Fvserver;hp=84a7065995dc914bbec71972bf76acb526cdbe0b;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 84a706599..7f1f411d0 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -4,14 +4,20 @@ #include #include #include +#include +#include +struct request_queue; struct block_device; +struct completion; struct module; struct scsi_cmnd; struct scsi_device; +struct scsi_target; struct Scsi_Host; struct scsi_host_cmd_pool; struct scsi_transport_template; +struct blk_queue_tags; /* @@ -30,6 +36,12 @@ struct scsi_transport_template; #define DISABLE_CLUSTERING 0 #define ENABLE_CLUSTERING 1 +enum scsi_eh_timer_return { + EH_NOT_HANDLED, + EH_HANDLED, + EH_RESET_TIMER, +}; + struct scsi_host_template { struct module *module; @@ -64,8 +76,19 @@ struct scsi_host_template { * * Status: OPTIONAL */ - int (* ioctl)(struct scsi_device *dev, int cmd, void *arg); - + int (* ioctl)(struct scsi_device *dev, int cmd, void __user *arg); + + +#ifdef CONFIG_COMPAT + /* + * Compat handler. Handle 32bit ABI. + * When unknown ioctl is passed return -ENOIOCTLCMD. + * + * Status: OPTIONAL + */ + int (* compat_ioctl)(struct scsi_device *dev, int cmd, void __user *arg); +#endif + /* * The queuecommand function is used to queue up a scsi * command block to the LLDD. When the driver finished @@ -101,6 +124,39 @@ struct scsi_host_template { int (* queuecommand)(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *)); + /* + * The transfer functions are used to queue a scsi command to + * the LLD. When the driver is finished processing the command + * the done callback is invoked. + * + * return values: see queuecommand + * + * If the LLD accepts the cmd, it should set the result to an + * appropriate value when completed before calling the done function. + * + * STATUS: REQUIRED FOR TARGET DRIVERS + */ + /* TODO: rename */ + int (* transfer_response)(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); + /* + * This is called to inform the LLD to transfer cmd->request_bufflen + * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg + * speciefies the number of scatterlist entried in the command + * and cmd->request_buffer contains the scatterlist. + * + * If the command cannot be processed in one transfer_data call + * becuase a scatterlist within the LLD's limits cannot be + * created then transfer_data will be called multiple times. + * It is initially called from process context, and later + * calls are from the interrup context. + */ + int (* transfer_data)(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); + + /* Used as callback for the completion of task management request. */ + int (* tsk_mgmt_response)(u64 mid, int result); + /* * This is an error handling strategy routine. You don't need to * define one of these if you don't want to - there is a default @@ -119,21 +175,11 @@ struct scsi_host_template { * * Status: REQUIRED (at least one of them) */ - int (* eh_strategy_handler)(struct Scsi_Host *); int (* eh_abort_handler)(struct scsi_cmnd *); int (* eh_device_reset_handler)(struct scsi_cmnd *); int (* eh_bus_reset_handler)(struct scsi_cmnd *); int (* eh_host_reset_handler)(struct scsi_cmnd *); - /* - * Old EH handlers, no longer used. Make them warn the user of old - * drivers by using a wrong type - * - * Status: MORE THAN OBSOLETE - */ - int (* abort)(int); - int (* reset)(int, int); - /* * Before the mid layer attempts to scan for a new device where none * currently exists, it will call this entry in your driver. Should @@ -151,7 +197,7 @@ struct scsi_host_template { * here then you will get a call to slave_configure(), then the * device will be used for however long it is kept around, then when * the device is removed from the system (or * possibly at reboot - * time), you will then get a call to slave_detach(). This is + * time), you will then get a call to slave_destroy(). This is * assuming you implement slave_configure and slave_destroy. * However, if you allocate memory and hang it off the device struct, * then you must implement the slave_destroy() routine at a minimum @@ -185,7 +231,7 @@ struct scsi_host_template { * specific setup basis... * 6. Return 0 on success, non-0 on error. The device will be marked * as offline on error so that no access will occur. If you return - * non-0, your slave_detach routine will never get called for this + * non-0, your slave_destroy routine will never get called for this * device, so don't leave any loose memory hanging around, clean * up after yourself before returning non-0 * @@ -204,14 +250,78 @@ struct scsi_host_template { */ void (* slave_destroy)(struct scsi_device *); + /* + * Before the mid layer attempts to scan for a new device attached + * to a target where no target currently exists, it will call this + * entry in your driver. Should your driver need to allocate any + * structs or perform any other init items in order to send commands + * to a currently unused target, then this is where you can perform + * those allocations. + * + * Return values: 0 on success, non-0 on failure + * + * Status: OPTIONAL + */ + int (* target_alloc)(struct scsi_target *); + + /* + * Immediately prior to deallocating the target structure, and + * after all activity to attached scsi devices has ceased, the + * midlayer calls this point so that the driver may deallocate + * and terminate any references to the target. + * + * Status: OPTIONAL + */ + void (* target_destroy)(struct scsi_target *); + + /* + * If a host has the ability to discover targets on its own instead + * of scanning the entire bus, it can fill in this function and + * call scsi_scan_host(). This function will be called periodically + * until it returns 1 with the scsi_host and the elapsed time of + * the scan in jiffies. + * + * Status: OPTIONAL + */ + int (* scan_finished)(struct Scsi_Host *, unsigned long); + + /* + * If the host wants to be called before the scan starts, but + * after the midlayer has set up ready for the scan, it can fill + * in this function. + */ + void (* scan_start)(struct Scsi_Host *); + + /* + * fill in this function to allow the queue depth of this host + * to be changeable (on a per device basis). returns either + * the current queue depth setting (may be different from what + * was passed in) or an error. An error should only be + * returned if the requested depth is legal but the driver was + * unable to set it. If the requested depth is illegal, the + * driver should set and return the closest legal queue depth. + * + */ + int (* change_queue_depth)(struct scsi_device *, int); + + /* + * fill in this function to allow the changing of tag types + * (this also allows the enabling/disabling of tag command + * queueing). An error should only be returned if something + * went wrong in the driver while trying to set the tag type. + * If the driver doesn't support the requested tag type, then + * it should set the closest type it does support without + * returning an error. Returns the actual tag type set. + */ + int (* change_queue_type)(struct scsi_device *, int); + /* * This function determines the bios parameters for a given * harddisk. These tend to be numbers that are made up by * the host adapter. Parameters: * size, device, list (heads, sectors, cylinders) * - * Status: OPTIONAL - */ + * Status: OPTIONAL */ int (* bios_param)(struct scsi_device *, struct block_device *, sector_t, int []); @@ -224,6 +334,12 @@ struct scsi_host_template { */ int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); + /* + * suspend support + */ + int (*resume)(struct scsi_device *); + int (*suspend)(struct scsi_device *, pm_message_t state); + /* * Name of proc directory */ @@ -313,6 +429,16 @@ struct scsi_host_template { */ unsigned emulated:1; + /* + * True if the low-level driver performs its own reset-settle delays. + */ + unsigned skip_settle_delay:1; + + /* + * ordered write support + */ + unsigned ordered_tag:1; + /* * Countdown for host blocking with no commands outstanding */ @@ -348,13 +474,18 @@ struct scsi_host_template { }; /* - * shost states + * shost state: If you alter this, you also need to alter scsi_sysfs.c + * (for the ascii descriptions) and the state model enforcer: + * scsi_host_set_state() */ -enum { - SHOST_ADD, - SHOST_DEL, +enum scsi_host_state { + SHOST_CREATED = 1, + SHOST_RUNNING, SHOST_CANCEL, + SHOST_DEL, SHOST_RECOVERY, + SHOST_CANCEL_RECOVERY, + SHOST_DEL_RECOVERY, }; struct Scsi_Host { @@ -367,6 +498,7 @@ struct Scsi_Host { * access this list directly from a driver. */ struct list_head __devices; + struct list_head __targets; struct scsi_host_cmd_pool *cmd_pool; spinlock_t free_list_lock; @@ -376,23 +508,30 @@ struct Scsi_Host { spinlock_t default_lock; spinlock_t *host_lock; - struct semaphore scan_mutex;/* serialize scanning activity */ + struct mutex scan_mutex;/* serialize scanning activity */ struct list_head eh_cmd_q; struct task_struct * ehandler; /* Error recovery thread. */ - struct semaphore * eh_wait; /* The error recovery thread waits - on this. */ - struct completion * eh_notify; /* wait for eh to begin or end */ - struct semaphore * eh_action; /* Wait for specific actions on the - host. */ - unsigned int eh_active:1; /* Indicates the eh thread is awake and active if - this is true. */ - unsigned int eh_kill:1; /* set when killing the eh thread */ + struct completion * eh_action; /* Wait for specific actions on the + host. */ wait_queue_head_t host_wait; struct scsi_host_template *hostt; struct scsi_transport_template *transportt; - volatile unsigned short host_busy; /* commands actually active on low-level */ - volatile unsigned short host_failed; /* commands that failed. */ + + /* + * area to keep a shared tag map (if needed, will be + * NULL if not) + */ + struct blk_queue_tag *bqt; + + /* + * The following two fields are protected with host_lock; + * however, eh routines can safely access during eh processing + * without acquiring the lock. + */ + unsigned int host_busy; /* commands actually active on low-level */ + unsigned int host_failed; /* commands that failed. */ + unsigned int host_eh_scheduled; /* EH scheduled without command */ unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ int resetting; /* if set, it means that last_reset is a valid value */ @@ -434,7 +573,12 @@ struct Scsi_Host { short unsigned int sg_tablesize; short unsigned int max_sectors; unsigned long dma_boundary; - + /* + * Used to assign serial numbers to the cmds. + * Protected by the host lock. + */ + unsigned long cmd_serial_number, cmd_pid; + unsigned unchecked_isa_dma:1; unsigned use_clustering:1; unsigned use_blk_tcq:1; @@ -452,6 +596,23 @@ struct Scsi_Host { */ unsigned reverse_ordering:1; + /* + * ordered write support + */ + unsigned ordered_tag:1; + + /* task mgmt function in progress */ + unsigned tmf_in_progress:1; + + /* Asynchronous scan in progress */ + unsigned async_scan:1; + + /* + * Optional work queue to be utilized by the transport + */ + char work_q_name[KOBJ_NAME_LEN]; + struct workqueue_struct *work_q; + /* * Host has rejected a command because it was busy. */ @@ -462,6 +623,12 @@ struct Scsi_Host { */ unsigned int max_host_blocked; + /* + * q used for scsi_tgt msgs, async events or any other requests that + * need to be processed in userspace + */ + struct request_queue *uspace_req_q; + /* legacy crap */ unsigned long base; unsigned long io_port; @@ -470,7 +637,7 @@ struct Scsi_Host { unsigned int irq; - unsigned long shost_state; + enum scsi_host_state shost_state; /* ldm bits */ struct device shost_gendev; @@ -485,6 +652,12 @@ struct Scsi_Host { */ struct list_head sht_legacy_list; + /* + * Points to the transport data (if any) which is allocated + * separately + */ + void *shost_data; + /* * We should ensure that this is aligned, both for better performance * and also because some compilers (m68k) don't automatically force @@ -493,40 +666,70 @@ struct Scsi_Host { unsigned long hostdata[0] /* Used for storage of host specific stuff */ __attribute__ ((aligned (sizeof(unsigned long)))); }; -#define dev_to_shost(d) \ - container_of(d, struct Scsi_Host, shost_gendev) + #define class_to_shost(d) \ container_of(d, struct Scsi_Host, shost_classdev) +#define shost_printk(prefix, shost, fmt, a...) \ + dev_printk(prefix, &(shost)->shost_gendev, fmt, ##a) + + +int scsi_is_host_device(const struct device *); + +static inline struct Scsi_Host *dev_to_shost(struct device *dev) +{ + while (!scsi_is_host_device(dev)) { + if (!dev->parent) + return NULL; + dev = dev->parent; + } + return container_of(dev, struct Scsi_Host, shost_gendev); +} + +static inline int scsi_host_in_recovery(struct Scsi_Host *shost) +{ + return shost->shost_state == SHOST_RECOVERY || + shost->shost_state == SHOST_CANCEL_RECOVERY || + shost->shost_state == SHOST_DEL_RECOVERY || + shost->tmf_in_progress; +} + +extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *); +extern void scsi_flush_work(struct Scsi_Host *); + extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); -extern int scsi_add_host(struct Scsi_Host *, struct device *); +extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *); extern void scsi_scan_host(struct Scsi_Host *); +extern void scsi_rescan_device(struct device *); extern void scsi_remove_host(struct Scsi_Host *); extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *); extern void scsi_host_put(struct Scsi_Host *t); extern struct Scsi_Host *scsi_host_lookup(unsigned short); +extern const char *scsi_host_state_name(enum scsi_host_state); extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); -static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) -{ - shost->host_lock = lock; -} - -static inline void scsi_set_device(struct Scsi_Host *shost, - struct device *dev) +static inline struct device *scsi_get_device(struct Scsi_Host *shost) { - shost->shost_gendev.parent = dev; + return shost->shost_gendev.parent; } -static inline struct device *scsi_get_device(struct Scsi_Host *shost) +/** + * scsi_host_scan_allowed - Is scanning of this host allowed + * @shost: Pointer to Scsi_Host. + **/ +static inline int scsi_host_scan_allowed(struct Scsi_Host *shost) { - return shost->shost_gendev.parent; + return shost->shost_state == SHOST_RUNNING; } extern void scsi_unblock_requests(struct Scsi_Host *); extern void scsi_block_requests(struct Scsi_Host *); +struct class_container; + +extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, + void (*) (struct request_queue *)); /* * These two functions are used to allocate and free a pseudo device * which will connect to the host adapter itself rather than any @@ -540,5 +743,6 @@ extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *); /* legacy interfaces */ extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int); extern void scsi_unregister(struct Scsi_Host *); +extern int scsi_host_set_state(struct Scsi_Host *, enum scsi_host_state); #endif /* _SCSI_SCSI_HOST_H */