diff --git a/scst/ToDo b/scst/ToDo index 76c404cde..1ce2f4892 100644 --- a/scst/ToDo +++ b/scst/ToDo @@ -3,6 +3,8 @@ To be done - See http://scst.sourceforge.net/contributing.html + - Remove cmd->data_len + - Reimplement VDISK handler with usage of async. read/write operations (in order to avoid unnecessary context switches) and direct access to the page cache (in order to avoid data copy between it and internal @@ -27,12 +29,10 @@ To be done - Small ToDo's spread all over the code. - - Investigate possible missed emulated UA cases. - - Additional ability for target drivers to ask for command's retry also after xmit_response() and rdy_to_xfer() returned (for example, if a command was successfully sent to the target card, but later it was returned by the card with BUSY completion status). - - Advanced SCSI commands support: COPY, EXTENDED COPY, PERSISTENT - RESERVE IN/OUT, third party RESERVE, etc. + - Advanced SCSI commands support: COPY, EXTENDED COPY, third party + RESERVE, etc. diff --git a/scst/include/scst.h b/scst/include/scst.h index 12659bc17..d7a0a8c3e 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -552,24 +552,11 @@ struct scst_aen; typedef enum dma_data_direction scst_data_direction; /* - * Scsi_Target_Template: defines what functions a target driver will - * have to provide in order to work with the target mid-level. - * MUST HAVEs define functions that are expected to be in order to work. - * OPTIONAL says that there is a choice. + * SCST target template: defines target driver's parameters and callback + * functions. * - * Also, pay attention to the fact that a command is BLOCKING or NON-BLOCKING. - * NON-BLOCKING means that a function returns immediately and will not wait - * for actual data transfer to finish. Blocking in such command could have - * negative impact on overall system performance. If blocking is necessary, - * it is worth to consider creating dedicated thread(s) in target driver, to - * which the commands would be passed and which would perform blocking - * operations instead of SCST. - * - * If the function allowed to sleep or not is determined by its last - * argument, which is true, if sleeping is not allowed. In this case, - * if the function requires sleeping, it can return - * SCST_TGT_RES_NEED_THREAD_CTX, and it will be recalled in the thread context, - * where sleeping is allowed. + * MUST HAVEs define functions that are expected to be defined in order to + * work. OPTIONAL says that there is a choice. */ struct scst_tgt_template { /* public: */ @@ -968,6 +955,13 @@ enum scst_dev_type_threads_pool_type { SCST_THREADS_POOL_TYPE_INVALID, }; +/* + * SCST dev handler template: defines dev handler's parameters and callback + * functions. + * + * MUST HAVEs define functions that are expected to be defined in order to + * work. OPTIONAL says that there is a choice. + */ struct scst_dev_type { /* SCSI type of the supported device. MUST HAVE */ int type; @@ -1216,6 +1210,9 @@ struct scst_dev_type { struct completion devt_kobj_release_compl; }; +/* + * An SCST target, analog of SCSI target port. + */ struct scst_tgt { /* List of remote sessions per target, protected by scst_mutex */ struct list_head sess_list; @@ -1230,7 +1227,7 @@ struct scst_tgt { /* * Device ACG groups */ - struct list_head acg_list; + struct list_head tgt_acg_list; /* * Maximum SG table size. Needed here, since different cards on the @@ -1324,6 +1321,9 @@ struct scst_ext_latency_stat { #endif /* CONFIG_SCST_MEASURE_LATENCY */ +/* + * SCST session, analog of SCSI I_T nexus + */ struct scst_session { /* * Initialization phase, one of SCST_SESS_IPH_* constants, protected by @@ -1440,12 +1440,15 @@ struct scst_session { #endif }; +/* + * Structure to control commands' queuing and threads pool processing the queue + */ struct scst_cmd_threads { spinlock_t cmd_list_lock; - struct list_head active_cmd_list; + struct list_head active_cmd_list; /* commands queue */ wait_queue_head_t cmd_list_waitQ; - struct io_context *io_context; + struct io_context *io_context; /* IO context of the threads pool */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) /* @@ -1455,12 +1458,15 @@ struct scst_cmd_threads { struct kref *io_context_kref; #endif - int nr_threads; - struct list_head threads_list; + int nr_threads; /* number of processing threads */ + struct list_head threads_list; /* processing threads */ struct list_head lists_list_entry; }; +/* + * SCST command, analog of I_T_L_Q nexus or task + */ struct scst_cmd { /* List entry for below *_cmd_threads */ struct list_head cmd_list_entry; @@ -1756,6 +1762,9 @@ struct scst_cmd { #endif }; +/* + * Parameters for SCST management commands + */ struct scst_rx_mgmt_params { int fn; uint64_t tag; @@ -1769,6 +1778,9 @@ struct scst_rx_mgmt_params { unsigned char cmd_sn_set; }; +/* + * A stub structure to link an management command and affected regular commands + */ struct scst_mgmt_cmd_stub { struct scst_mgmt_cmd *mcmd; @@ -1779,6 +1791,9 @@ struct scst_mgmt_cmd_stub { unsigned int done_counted:1; }; +/* + * SCST task management structure + */ struct scst_mgmt_cmd { /* List entry for *_mgmt_cmd_list */ struct list_head mgmt_cmd_list_entry; @@ -1788,7 +1803,7 @@ struct scst_mgmt_cmd { /* Mgmt cmd state, one of SCST_MCMD_STATE_* constants */ int state; - int fn; + int fn; /* task management function */ unsigned int completed:1; /* set, if the mcmd is completed */ /* Set if device(s) should be unblocked after mcmd's finish */ @@ -1832,6 +1847,9 @@ struct scst_mgmt_cmd { void *tgt_priv; }; +/* + * SCST device + */ struct scst_device { struct scst_dev_type *handler; /* corresponding dev handler */ @@ -1981,7 +1999,8 @@ struct scst_async_io_context_keeper { }; /* - * Used to store per-session specific device information + * Used to store per-session specific device information, analog of + * SCSI I_T_L nexus. */ struct scst_tgt_dev { /* List entry in sess->sess_tgt_dev_list_hash */ @@ -2125,7 +2144,7 @@ struct scst_acg { /* List of attached acn's, protected by scst_mutex */ struct list_head acn_list; - /* List entry in tgt acg_list */ + /* List entry in acg_lists */ struct list_head acg_list_entry; /* Name of this acg */ @@ -2218,133 +2237,34 @@ static inline int scst_register_target_template(struct scst_tgt_template *vtt) return __scst_register_target_template(vtt, SCST_INTERFACE_VERSION); } -/* - * Unregisters target template - */ void scst_unregister_target_template(struct scst_tgt_template *vtt); -/* - * Registers and returns target adapter - * Returns new target structure on success or NULL otherwise. - * - * If parameter "target_name" isn't NULL, then security group with name - * "Default_##target_name", if created, will be used as the default - * instead of "Default" one for all initiators not assigned to any other group. - */ struct scst_tgt *scst_register(struct scst_tgt_template *vtt, const char *target_name); - -/* - * Unregisters target adapter - */ void scst_unregister(struct scst_tgt *tgt); -/* - * Registers and returns a session - * - * Returns new session on success or NULL otherwise - * - * Parameters: - * tgt - target - * atomic - true, if the function called in the atomic context. If false, - * this function will block until the session registration is completed. - * initiator_name - remote initiator's name, any NULL-terminated string, - * e.g. iSCSI name, which used as the key to found appropriate access - * control group. Could be NULL, then the default target's LUNs are used. - * data - any target driver supplied data - * result_fn - pointer to the function that will be - * asynchronously called when session initialization finishes. - * Can be NULL. Parameters: - * - sess - session - * - data - target driver supplied to scst_register_session() data - * - result - session initialization result, 0 on success or - * appropriate error code otherwise - * - * Note: A session creation and initialization is a complex task, - * which requires sleeping state, so it can't be fully done - * in interrupt context. Therefore the "bottom half" of it, if - * scst_register_session() is called from atomic context, will be - * done in SCST thread context. In this case scst_register_session() - * will return not completely initialized session, but the target - * driver can supply commands to this session via scst_rx_cmd(). - * Those commands processing will be delayed inside SCST until - * the session initialization is finished, then their processing - * will be restarted. The target driver will be notified about - * finish of the session initialization by function result_fn(). - * On success the target driver could do nothing, but if the - * initialization fails, the target driver must ensure that - * no more new commands being sent or will be sent to SCST after - * result_fn() returns. All already sent to SCST commands for - * failed session will be returned in xmit_response() with BUSY status. - * In case of failure the driver shall call scst_unregister_session() - * inside result_fn(), it will NOT be called automatically. - */ struct scst_session *scst_register_session(struct scst_tgt *tgt, int atomic, const char *initiator_name, void *data, void (*result_fn) (struct scst_session *sess, void *data, int result)); - -/* - * Unregisters a session. - * Parameters: - * sess - session to be unregistered - * wait - if true, instructs to wait until all commands, which - * currently is being executed and belonged to the session, finished. - * Otherwise, target driver should be prepared to receive - * xmit_response() for the session's command after - * scst_unregister_session() returns. - * unreg_done_fn - pointer to the function that will be - * asynchronously called when the last session's command finishes and - * the session is about to be completely freed. Can be NULL. - * Parameter: - * - sess - session - * - * Notes: - * - * - All outstanding commands will be finished regularly. After - * scst_unregister_session() returned no new commands must be sent to - * SCST via scst_rx_cmd(). - * - * - The caller must ensure that no scst_rx_cmd() or scst_rx_mgmt_fn_*() is - * called in paralell with scst_unregister_session(). - * - * - Can be called before result_fn() of scst_register_session() called, - * i.e. during the session registration/initialization. - * - * - It is highly recommended to call scst_unregister_session() as soon as it - * gets clear that session will be unregistered and not to wait until all - * related commands finished. This function provides the wait functionality, - * but it also starts recovering stuck commands, if there are any. - * Otherwise, your target driver could wait for those commands forever. - */ void scst_unregister_session(struct scst_session *sess, int wait, void (*unreg_done_fn) (struct scst_session *sess)); -/* - * Registers dev handler driver. - * Returns 0 on success or appropriate error code otherwise. - * - * Note: *dev_type must be static! - */ int __scst_register_dev_driver(struct scst_dev_type *dev_type, const char *version); static inline int scst_register_dev_driver(struct scst_dev_type *dev_type) { return __scst_register_dev_driver(dev_type, SCST_INTERFACE_VERSION); } - -/* - * Unregisters dev handler driver - */ void scst_unregister_dev_driver(struct scst_dev_type *dev_type); +int __scst_register_virtual_dev_driver(struct scst_dev_type *dev_type, + const char *version); /* * Registers dev handler driver for virtual devices (eg VDISK). * Returns 0 on success or appropriate error code otherwise. * * Note: *dev_type must be static! */ -int __scst_register_virtual_dev_driver(struct scst_dev_type *dev_type, - const char *version); static inline int scst_register_virtual_dev_driver( struct scst_dev_type *dev_type) { @@ -2352,38 +2272,11 @@ static inline int scst_register_virtual_dev_driver( SCST_INTERFACE_VERSION); } -/* - * Unregisters dev handler driver for virtual devices - */ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type); -/* - * Creates and sends new command to SCST. - * Must not be called in parallel with scst_unregister_session() for the - * same sess. Returns the command on success or NULL otherwise - */ struct scst_cmd *scst_rx_cmd(struct scst_session *sess, const uint8_t *lun, int lun_len, const uint8_t *cdb, int cdb_len, int atomic); - -/* - * Notifies SCST that the driver finished its part of the command - * initialization, and the command is ready for execution. - * The second argument sets preferred command execition context. - * See SCST_CONTEXT_* constants for details. - * - * !!IMPORTANT!! - * - * If cmd->set_sn_on_restart_cmd not set, this function, as well as - * scst_cmd_init_stage1_done() and scst_restart_cmd(), must not be - * called simultaneously for the same session (more precisely, - * for the same session/LUN, i.e. tgt_dev), i.e. they must be - * somehow externally serialized. This is needed to have lock free fast path in - * scst_cmd_set_sn(). For majority of targets those functions are naturally - * serialized by the single source of commands. Only iSCSI immediate commands - * with multiple connections per session seems to be an exception. For it, some - * mutex/lock shall be used for the serialization. - */ void scst_cmd_init_done(struct scst_cmd *cmd, enum scst_exec_context pref_context); @@ -2394,7 +2287,7 @@ void scst_cmd_init_done(struct scst_cmd *cmd, * should be called. The second argument sets preferred command execition * context. See SCST_CONTEXT_* constants for details. * - * See also scst_cmd_init_done() comment for the serialization requirements. + * See comment for scst_cmd_init_done() for the serialization requirements. */ static inline void scst_cmd_init_stage1_done(struct scst_cmd *cmd, enum scst_exec_context pref_context, int set_sn) @@ -2404,45 +2297,15 @@ static inline void scst_cmd_init_stage1_done(struct scst_cmd *cmd, scst_cmd_init_done(cmd, pref_context); } -/* - * Notifies SCST that the driver finished its part of the command's - * preprocessing and it is ready for further processing. - * The second argument sets data receiving completion status - * (see SCST_PREPROCESS_STATUS_* constants for details) - * The third argument sets preferred command execition context - * (see SCST_CONTEXT_* constants for details). - * - * See also scst_cmd_init_done() comment for the serialization requirements. - */ void scst_restart_cmd(struct scst_cmd *cmd, int status, enum scst_exec_context pref_context); -/* - * Notifies SCST that the driver received all the necessary data - * and the command is ready for further processing. - * The second argument sets data receiving completion status - * (see SCST_RX_STATUS_* constants for details) - * The third argument sets preferred command execition context - * (see SCST_CONTEXT_* constants for details) - */ void scst_rx_data(struct scst_cmd *cmd, int status, enum scst_exec_context pref_context); -/* - * Notifies SCST that the driver sent the response and the command - * can be freed now. Don't forget to set the delivery status, if it - * isn't success, using scst_set_delivery_status() before calling - * this function. The third argument sets preferred command execition - * context (see SCST_CONTEXT_* constants for details) - */ void scst_tgt_cmd_done(struct scst_cmd *cmd, enum scst_exec_context pref_context); -/* - * Creates new management command sends it for execution. - * Must not be called in parallel with scst_unregister_session() for the - * same sess. Returns 0 for success, error code otherwise. - */ int scst_rx_mgmt_fn(struct scst_session *sess, const struct scst_rx_mgmt_params *params); @@ -2495,74 +2358,24 @@ static inline int scst_rx_mgmt_fn_lun(struct scst_session *sess, int fn, return scst_rx_mgmt_fn(sess, ¶ms); } -/* - * Provides various info about command's CDB. - * - * Returns: 0 on success, <0 if command is unknown, >0 if command is invalid. - */ int scst_get_cdb_info(struct scst_cmd *cmd); -/* - * Set error SCSI status in the command and prepares it for returning it. - * - * Returns 0 on success, error code otherwise. - */ int scst_set_cmd_error_status(struct scst_cmd *cmd, int status); - -/* - * Set error in the command and fill the sense buffer. - * - * Returns 0 on success, error code otherwise. - */ int scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq); - -/* - * Sets BUSY or TASK QUEUE FULL status - */ void scst_set_busy(struct scst_cmd *cmd); -/* - * Check if sense in the sense buffer, if any, in the correct format. If not, - * convert it to the correct format. - */ void scst_check_convert_sense(struct scst_cmd *cmd); -/* - * Sets initial Unit Attention for sess, replacing default scst_sense_reset_UA - */ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq); -/* - * Notifies SCST core that dev changed its capacity - */ void scst_capacity_data_changed(struct scst_device *dev); -/* - * Finds a command based on the supplied tag comparing it with one - * that previously set by scst_cmd_set_tag(). - * Returns the command on success or NULL otherwise - */ struct scst_cmd *scst_find_cmd_by_tag(struct scst_session *sess, uint64_t tag); - -/* - * Finds a command based on user supplied data and comparision - * callback function, that should return true, if the command is found. - * Returns the command on success or NULL otherwise - */ struct scst_cmd *scst_find_cmd(struct scst_session *sess, void *data, int (*cmp_fn) (struct scst_cmd *cmd, void *data)); -/* - * Translates SCST's data direction to DMA one from backend storage - * perspective. - */ enum dma_data_direction scst_to_dma_dir(int scst_dir); - -/* - * Translates SCST data direction to DMA data direction from the perspective - * of the target device. - */ enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir); /* @@ -2589,24 +2402,8 @@ static inline bool scst_is_ua_command(struct scst_cmd *cmd) return (cmd->op_flags & SCST_SKIP_UA) == 0; } -/* - * Registers a virtual device. - * Parameters: - * dev_type - the device's device handler - * dev_name - the new device name, NULL-terminated string. Must be uniq - * among all virtual devices in the system. The value isn't - * copied, only the reference is stored, so the value must - * remain valid during the device lifetime. - * Returns assinged to the device ID on success, or negative value otherwise - */ int scst_register_virtual_device(struct scst_dev_type *dev_handler, const char *dev_name); - -/* - * Unegisters a virtual device. - * Parameters: - * id - the device's ID, returned by the registration function - */ void scst_unregister_virtual_device(int id); /* @@ -2949,9 +2746,6 @@ static inline void scst_cmd_set_tgt_priv(struct scst_cmd *cmd, void *val) cmd->tgt_priv = val; } -void *scst_cmd_get_tgt_priv_lock(struct scst_cmd *cmd); -void scst_cmd_set_tgt_priv_lock(struct scst_cmd *cmd, void *val); - /* * Get/Set functions for tgt_need_alloc_data_buf flag */ @@ -3192,12 +2986,6 @@ static inline void scst_set_aen_delivery_status(struct scst_aen *aen, aen->delivery_status = status; } -/* - * Notifies SCST that the driver has sent the AEN and it - * can be freed now. Don't forget to set the delivery status, if it - * isn't success, using scst_set_aen_delivery_status() before calling - * this function. - */ void scst_aen_done(struct scst_aen *aen); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) @@ -3264,10 +3052,6 @@ enum scst_sg_copy_dir { SCST_SG_COPY_TO_TARGET }; -/* - * Copies data between cmd->tgt_sg and cmd->sg in direction defined by - * copy_dir parameter. - */ void scst_copy_sg(struct scst_cmd *cmd, enum scst_sg_copy_dir copy_dir); /* @@ -3368,54 +3152,15 @@ static inline int cancel_delayed_work_sync(struct work_struct *work) } #endif -/* - * Suspends and resumes any activity. - * Function scst_suspend_activity() doesn't return 0, until there are any - * active commands (state after SCST_CMD_STATE_INIT). If "interruptible" - * is true, it returns after SCST_SUSPENDING_TIMEOUT or if it was interrupted - * by a signal with the coresponding error status < 0. If "interruptible" - * is false, it will wait virtually forever. - * - * New arriving commands stay in that state until scst_resume_activity() - * is called. - */ int scst_suspend_activity(bool interruptible); void scst_resume_activity(void); -/* - * Main SCST commands processing routing. Must be used only by dev handlers. - * Argument atomic is true if function called in atomic context. - */ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic); - -/* - * SCST commands processing routine, which should be called by dev handler - * after its parse() callback returned SCST_CMD_STATE_STOP. Arguments - * the same as for scst_process_active_cmd(). - */ void scst_post_parse_process_active_cmd(struct scst_cmd *cmd, bool atomic); -/* - * Checks if command can be executed (reservations, etc.) or there are local - * events, like pending UAs. Returns < 0 if command must be aborted, > 0 if - * there is an event and command should be immediately completed, or 0 - * otherwise. - * - * !! Dev handlers implementing exec() callback must call this function there !! - * !! just before the actual command's execution !! - */ int scst_check_local_events(struct scst_cmd *cmd); -/* - * Returns the next state of the SCSI target state machine in case if command's - * completed abnormally. - */ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd); - -/* - * Sets state of the SCSI target state machine in case if command's completed - * abnormally. - */ void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd); struct scst_trace_log { @@ -3423,10 +3168,6 @@ struct scst_trace_log { const char *token; }; -/* - * Main SCST mutex. All targets, devices and dev_types management is done - * under this mutex. - */ extern struct mutex scst_mutex; #ifdef CONFIG_SCST_PROC @@ -3489,7 +3230,6 @@ struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry *root, #else /* CONFIG_SCST_PROC */ -/* Regular SCST sysfs operations */ extern struct sysfs_ops scst_sysfs_ops; /* @@ -3554,78 +3294,32 @@ int scst_alloc_sense(struct scst_cmd *cmd, int atomic); int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic, const uint8_t *sense, unsigned int len); -/* - * Sets the corresponding field in the sense buffer taking sense type - * into account. Returns resulting sense length. - */ int scst_set_sense(uint8_t *buffer, int len, bool d_sense, int key, int asc, int ascq); -/* - * Returns true if the sense is valid and carrying a Unit Attention or - * false otherwise. - */ bool scst_is_ua_sense(const uint8_t *sense, int len); -/* - * Returnes true if sense matches to (key, asc, ascq) and false otherwise. - * Valid_mask is one or several SCST_SENSE_*_VALID constants setting valid - * (key, asc, ascq) values. - */ bool scst_analyze_sense(const uint8_t *sense, int len, unsigned int valid_mask, int key, int asc, int ascq); -/* - * Returnes a pseudo-random number for debugging purposes. Available only in - * the DEBUG build. - */ unsigned long scst_random(void); -/* - * Sets response data length for cmd and truncates its SG vector accordingly. - * The cmd->resp_data_len must not be set directly, it must be set only - * using this function. Value of resp_data_len must be <= cmd->bufflen. - */ void scst_set_resp_data_len(struct scst_cmd *cmd, int resp_data_len); -/* - * Get/put global ref counter that prevents from entering into suspended - * activities stage, so protects from any global management operations. - */ void scst_get(void); void scst_put(void); -/* - * Cmd ref counters - */ void scst_cmd_get(struct scst_cmd *cmd); void scst_cmd_put(struct scst_cmd *cmd); -/* - * Allocates and returns pointer to SG vector with data size "size". - * In *count returned the count of entries in the vector. - * Returns NULL for failure. - */ struct scatterlist *scst_alloc(int size, gfp_t gfp_mask, int *count); - -/* Frees SG vector returned by scst_alloc() */ void scst_free(struct scatterlist *sg, int count); -/* - * Adds local to the current thread data to tgt_dev - * (they will be local for the tgt_dev and current thread). - */ void scst_add_thr_data(struct scst_tgt_dev *tgt_dev, struct scst_thr_data_hdr *data, void (*free_fn) (struct scst_thr_data_hdr *data)); - -/* Deletes all local to threads data from tgt_dev */ void scst_del_all_thr_data(struct scst_tgt_dev *tgt_dev); - -/* Deletes all local to threads data from all tgt_dev's of the dev */ void scst_dev_del_all_thr_data(struct scst_device *dev); - -/* Finds local to the thread data. Returns NULL, if they not found. */ struct scst_thr_data_hdr *__scst_find_thr_data(struct scst_tgt_dev *tgt_dev, struct task_struct *tsk); @@ -3636,84 +3330,42 @@ static inline struct scst_thr_data_hdr *scst_find_thr_data( return __scst_find_thr_data(tgt_dev, current); } +/* Increase ref counter for the thread data */ static inline void scst_thr_data_get(struct scst_thr_data_hdr *data) { atomic_inc(&data->ref); } +/* Decrease ref counter for the thread data */ static inline void scst_thr_data_put(struct scst_thr_data_hdr *data) { if (atomic_dec_and_test(&data->ref)) data->free_fn(data); } -/** - ** Generic parse() support routines. - ** Done via pointer on functions to avoid unneeded dereferences on - ** the fast path. - **/ - -/* Calculates and returns block shift for the given sector size */ int scst_calc_block_shift(int sector_size); - -/* Generic parse() for SBC (disk) devices */ int scst_sbc_generic_parse(struct scst_cmd *cmd, int (*get_block_shift)(struct scst_cmd *cmd)); - -/* Generic parse() for MMC (cdrom) devices */ int scst_cdrom_generic_parse(struct scst_cmd *cmd, int (*get_block_shift)(struct scst_cmd *cmd)); - -/* Generic parse() for MO disk devices */ int scst_modisk_generic_parse(struct scst_cmd *cmd, int (*get_block_shift)(struct scst_cmd *cmd)); - -/* Generic parse() for tape devices */ int scst_tape_generic_parse(struct scst_cmd *cmd, int (*get_block_size)(struct scst_cmd *cmd)); - -/* Generic parse() for changer devices */ int scst_changer_generic_parse(struct scst_cmd *cmd, int (*nothing)(struct scst_cmd *cmd)); - -/* Generic parse() for "processor" devices */ int scst_processor_generic_parse(struct scst_cmd *cmd, int (*nothing)(struct scst_cmd *cmd)); - -/* Generic parse() for RAID devices */ int scst_raid_generic_parse(struct scst_cmd *cmd, int (*nothing)(struct scst_cmd *cmd)); -/** - ** Generic dev_done() support routines. - ** Done via pointer on functions to avoid unneeded dereferences on - ** the fast path. - **/ - -/* Generic dev_done() for block devices */ int scst_block_generic_dev_done(struct scst_cmd *cmd, void (*set_block_shift)(struct scst_cmd *cmd, int block_shift)); - -/* Generic dev_done() for tape devices */ int scst_tape_generic_dev_done(struct scst_cmd *cmd, void (*set_block_size)(struct scst_cmd *cmd, int block_size)); -/* - * Issues a MODE SENSE for control mode page data and sets the corresponding - * dev's parameter from it. Returns 0 on success and not 0 otherwise. - */ int scst_obtain_device_parameters(struct scst_device *dev); -/* - * Returns maximum commands count which can be queued to this LUN in this - * session. - * - * If lun is NO_SUCH_LUN, returns minimum of maximum commands count which - * can be queued to any LUN in this session. - * - * If sess is NULL, returns minimum of maximum commands count which can be - * queued to any SCST device. - */ int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun); /* @@ -3734,12 +3386,9 @@ static inline void add_wait_queue_exclusive_head(wait_queue_head_t *q, #ifndef CONFIG_SCST_PROC -/** - ** Helper functionality to help target drivers and dev handlers support - ** sending events to user space and wait for their completion in a safe - ** manner. See samples how to use it in iscsi-scst or scst_user. - **/ - +/* + * Structure to match events to user space and replies on them + */ struct scst_sysfs_user_info { /* Unique cookie to identify request */ uint32_t info_cookie; @@ -3761,61 +3410,21 @@ struct scst_sysfs_user_info { void *data; }; -/* - * This function creates an info structure and adds it in the info_list. - * Returns 0 and out_info on success, error code otherwise. - */ int scst_sysfs_user_add_info(struct scst_sysfs_user_info **out_info); - -/* This function deletes and frees info */ void scst_sysfs_user_del_info(struct scst_sysfs_user_info *info); - -/* - * This function finds the info based on cookie and set for it flag - * info_being_executed. Returns found entry or NULL. - */ struct scst_sysfs_user_info *scst_sysfs_user_get_info(uint32_t cookie); - -/* - * This function waits for the info request been completed by user space. - * Returns status of the request completion. - */ int scst_wait_info_completion(struct scst_sysfs_user_info *info, unsigned long timeout); -/* - * This function returns SCST setup ID. This ID can be used with multiple - * setups with the same configuration. - */ unsigned int scst_get_setup_id(void); #endif /* CONFIG_SCST_PROC */ -/* - * This function returns pointer to the next lexem from token_str skipping - * spaces and '=' character and using them then as a delimeter. Content - * of token_str is modified by setting '\0' at the delimeter's position. - */ char *scst_get_next_lexem(char **token_str); - -/* - * This function restores token_str modified by scst_get_next_lexem() to the - * previous value before scst_get_next_lexem() was called. Prev_lexem is - * a pointer to lexem returned by scst_get_next_lexem(). - */ void scst_restore_token_str(char *prev_lexem, char *token_str); - -/* - * This function returns pointer to the next token strings from input_str - * using '\n', ';' and '\0' as a delimeter. Content of input_str is - * modified by setting '\0' at the delimeter's position. - */ char *scst_get_next_token_str(char **input_str); -/* Initializes scst_cmd_threads structure */ void scst_init_threads(struct scst_cmd_threads *cmd_threads); - -/* Deinitializes scst_cmd_threads structure */ void scst_deinit_threads(struct scst_cmd_threads *cmd_threads); #endif /* __SCST_H */ diff --git a/scst/include/scst_sgv.h b/scst/include/scst_sgv.h index c1e0c349e..3a7e9ca25 100644 --- a/scst/include/scst_sgv.h +++ b/scst/include/scst_sgv.h @@ -39,6 +39,9 @@ struct sgv_pool_obj; struct sgv_pool; +/* + * Structure to keep a memory limit for an SCST object + */ struct scst_mem_lim { /* How much memory allocated under this object */ atomic_t alloced_pages; @@ -68,131 +71,27 @@ enum sgv_clustering_types { sgv_full_clustering, }; -/** - * sgv_pool_create - creates and initializes an SGV cache - * @name: the name of the SGV cache - * @clustered: sets type of the pages clustering. - * @single_alloc_pages: if 0, then the SGV cache will work in the set of - * power 2 size buffers mode. If >0, then the SGV cache will - * work in the fixed size buffers mode. In this case - * single_alloc_pages sets the size of each buffer in pages. - * @shared: sets if the SGV cache can be shared between devices or not. - * The cache sharing allowed only between devices created inside - * the same address space. If an SGV cache is shared, each - * subsequent call of sgv_pool_create() with the same cache name - * will not create a new cache, but instead return a reference - * to it. - * @purge_interval sets the cache purging interval. I.e., an SG buffer - * will be freed if it's unused for time t - * purge_interval <= t < 2*purge_interval. If purge_interval - * is 0, then the default interval will be used (60 seconds). - * If purge_interval <0, then the automatic purging will be - * disabled. - * - * Description: - * Returns the resulting SGV cache or NULL in case of any error. - */ struct sgv_pool *sgv_pool_create(const char *name, enum sgv_clustering_types clustered, int single_alloc_pages, bool shared, int purge_interval); - -/** - * sgv_pool_del - deletes the corresponding SGV cache - * @:pool the cache to delete. - * - * Description: - * If the cache is shared, it will decrease its reference counter. - * If the reference counter reaches 0, the cache will be destroyed. - */ void sgv_pool_del(struct sgv_pool *pool); -/** - * sgv_pool_get - increases reference counter for the corresponding SGV cache - * @:pool the cache to get. - * - * Description: - */ void sgv_pool_get(struct sgv_pool *pool); - -/** - * sgv_pool_put - decreases reference counter for the corresponding SGV cache - * @:pool the cache to put. - * - * Description: - * If the reference counter reaches 0, the cache will be destroyed. - */ void sgv_pool_put(struct sgv_pool *pool); -/** - * sgv_pool_flush - flushes the SGV cache - * @:pool the cache to flush - * - * Description: - * Flushes, i.e. frees, all the cached entries in the SGV cache. - */ void sgv_pool_flush(struct sgv_pool *pool); -/** - * sgv_pool_set_allocator - allows to set a custom pages allocator - * @:pool the cache - * @:alloc_pages_fn pages allocation function - * @:free_pages_fn pages freeing function - * - * Description: - * See the SGV cache documentation for more details. - */ void sgv_pool_set_allocator(struct sgv_pool *pool, struct page *(*alloc_pages_fn)(struct scatterlist *, gfp_t, void *), void (*free_pages_fn)(struct scatterlist *, int, void *)); -/** - * sgv_pool_alloc - allocates an SG vector from the SGV cache - * @:pool the cache to alloc from - * @:size size of the resulting SG vector in bytes - * @:gfp_mask the allocation mask - * @:flags the allocation flags - * @:count the resulting count of SG entries in the resulting SG vector - * @:sgv the resulting SGV object - * @:mem_lim memory limits - * @:priv pointer to private for this allocation data - * - * Description: - * Returns pointer to the resulting SG vector or NULL in case - * of any error. See the SGV cache documentation for more details. - */ struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, unsigned int size, gfp_t gfp_mask, int flags, int *count, struct sgv_pool_obj **sgv, struct scst_mem_lim *mem_lim, void *priv); - -/** - * sgv_pool_free - frees previously allocated SG vector - * @:sgv the SGV object to free - * @:mem_lim memory limits - * - * Description: - * Frees previously allocated SG vector, referenced by SGV cache object sgv - */ void sgv_pool_free(struct sgv_pool_obj *sgv, struct scst_mem_lim *mem_lim); -/** - * sgv_get_priv - returns the private allocation data - * @:sgv the SGV object - * - * Description: - * Allows to get the allocation private data for this SGV - * cache object sgv. The private data are set by sgv_pool_alloc(). - */ void *sgv_get_priv(struct sgv_pool_obj *sgv); -/** - * scst_init_mem_lim - initializes memory limits - * @:mem_lim memory limits - * - * Description: - * Initializes memory limits structure mem_lim according to - * the current system configuration. This structure should be latter used - * to track and limit allocated by one or more SGV caches memory. - */ void scst_init_mem_lim(struct scst_mem_lim *mem_lim); #endif /* __SCST_SGV_H */ diff --git a/scst/src/scst_debug.c b/scst/src/scst_debug.c index 2d3ab674c..a1967f64a 100644 --- a/scst/src/scst_debug.c +++ b/scst/src/scst_debug.c @@ -46,6 +46,11 @@ static inline int get_current_tid(void) #endif } +/** + * debug_print_prefix() - print debug prefix for a log line + * + * Prints, if requested by trace_flag, debug prefix for each log line + */ int debug_print_prefix(unsigned long trace_flag, const char *prefix, const char *func, int line) { @@ -75,6 +80,11 @@ int debug_print_prefix(unsigned long trace_flag, } EXPORT_SYMBOL(debug_print_prefix); +/** + * debug_print_buffer() - print a buffer + * + * Prints in the log data from the buffer + */ void debug_print_buffer(const void *data, int len) { int z, z1, i; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 0363ead65..f02ee7756 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -585,6 +585,13 @@ static inline void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev) {} static inline void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev) {} #endif /* CONFIG_SCST_DEBUG_TM */ +/** + * scst_alloc_sense() - allocate sense buffer for command + * + * Allocates, if necessary, sense buffer for command. Returns 0 on success + * and error code othrwise. Parameter "atomic" should be non-0 if the + * function called in atomic context. + */ int scst_alloc_sense(struct scst_cmd *cmd, int atomic) { int res = 0; @@ -615,6 +622,13 @@ out: } EXPORT_SYMBOL(scst_alloc_sense); +/** + * scst_alloc_set_sense() - allocate and fill sense buffer for command + * + * Allocates, if necessary, sense buffer for command and copies in + * it data from the supplied sense buffer. Returns 0 on success + * and error code othrwise. + */ int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic, const uint8_t *sense, unsigned int len) { @@ -649,6 +663,15 @@ out: } EXPORT_SYMBOL(scst_alloc_set_sense); +/** + * scst_set_cmd_error_status() - set error SCSI status + * @cmd: SCST command + * @status: SCSI status to set + * + * Description: + * Sets error SCSI status in the command and prepares it for returning it. + * Returns 0 on success, error code otherwise. + */ int scst_set_cmd_error_status(struct scst_cmd *cmd, int status) { int res = 0; @@ -778,6 +801,12 @@ out: return res; } +/** + * scst_set_cmd_error() - set error in the command and fill the sense buffer. + * + * Sets error in the command and fill the sense buffer. Returns 0 on success, + * error code otherwise. + */ int scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq) { int res; @@ -825,6 +854,12 @@ out: } EXPORT_SYMBOL(scst_set_cmd_error); +/** + * scst_set_sense() - set sense from KEY/ASC/ASCQ numbers + * + * Sets the corresponding fields in the sense buffer taking sense type + * into account. Returns resulting sense length. + */ int scst_set_sense(uint8_t *buffer, int len, bool d_sense, int key, int asc, int ascq) { @@ -873,6 +908,13 @@ int scst_set_sense(uint8_t *buffer, int len, bool d_sense, } EXPORT_SYMBOL(scst_set_sense); +/** + * scst_analyze_sense() - analyze sense + * + * Returns true if sense matches to (key, asc, ascq) and false otherwise. + * Valid_mask is one or several SCST_SENSE_*_VALID constants setting valid + * (key, asc, ascq) values. + */ bool scst_analyze_sense(const uint8_t *sense, int len, unsigned int valid_mask, int key, int asc, int ascq) { @@ -942,6 +984,12 @@ out: } EXPORT_SYMBOL(scst_analyze_sense); +/** + * scst_is_ua_sense() - determine if the sense is UA sense + * + * Returns true if the sense is valid and carrying a Unit + * Attention or false otherwise. + */ bool scst_is_ua_sense(const uint8_t *sense, int len) { if (SCST_SENSE_VALID(sense)) @@ -967,6 +1015,12 @@ bool scst_is_ua_global(const uint8_t *sense, int len) return res; } +/** + * scst_check_convert_sense() - check sense type and convert it if needed + * + * Checks if sense in the sense buffer, if any, is in the correct format. + * If not, converts it in the correct format. + */ void scst_check_convert_sense(struct scst_cmd *cmd) { bool d_sense; @@ -1026,6 +1080,12 @@ out: return res; } +/** + * scst_set_busy() - set BUSY or TASK QUEUE FULL status + * + * Sets BUSY or TASK QUEUE FULL status depending on if this session has other + * outstanding commands or not. + */ void scst_set_busy(struct scst_cmd *cmd) { int c = atomic_read(&cmd->sess->sess_cmd_count); @@ -1051,6 +1111,12 @@ void scst_set_busy(struct scst_cmd *cmd) } EXPORT_SYMBOL(scst_set_busy); +/** + * scst_set_initial_UA() - set initial Unit Attention + * + * Sets initial Unit Attention on all devices of the session, + * replacing default scst_sense_reset_UA + */ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq) { int i; @@ -1185,7 +1251,11 @@ out: return; } -/* No locks */ +/** + * scst_capacity_data_changed() - notify SCST about device capacity change + * + * Notifies SCST core that dev has changed its capacity. Called under no locks. + */ void scst_capacity_data_changed(struct scst_device *dev) { struct scst_tgt_dev *tgt_dev; @@ -1376,6 +1446,14 @@ void scst_report_luns_changed(struct scst_acg *acg) return; } +/** + * scst_aen_done() - AEN processing done + * + * Notifies SCST that the driver has sent the AEN and it + * can be freed now. Don't forget to set the delivery status, if it + * isn't success, using scst_set_aen_delivery_status() before calling + * this function. + */ void scst_aen_done(struct scst_aen *aen) { TRACE_ENTRY(); @@ -1605,6 +1683,12 @@ void scst_check_reassign_sessions(void) return; } +/** + * scst_get_cmd_abnormal_done_state() - get command's next abnormal done state + * + * Returns the next state of the SCSI target state machine in case if command's + * completed abnormally. + */ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd) { int res; @@ -1672,6 +1756,12 @@ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd) } EXPORT_SYMBOL(scst_get_cmd_abnormal_done_state); +/** + * scst_set_cmd_abnormal_done_state() - set command's next abnormal done state + * + * Sets state of the SCSI target state machine in case if command's completed + * abnormally. + */ void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd) { TRACE_ENTRY(); @@ -1705,6 +1795,14 @@ void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd) } EXPORT_SYMBOL(scst_set_cmd_abnormal_done_state); +/** + * scst_set_resp_data_len() - set response data length + * + * Sets response data length for cmd and truncates its SG vector accordingly. + * + * The cmd->resp_data_len must not be set directly, it must be set only + * using this function. Value of resp_data_len must be <= cmd->bufflen. + */ void scst_set_resp_data_len(struct scst_cmd *cmd, int resp_data_len) { int i, l; @@ -2066,6 +2164,13 @@ void scst_free_device(struct scst_device *dev) return; } +/** + * scst_init_mem_lim - initialize memory limits structure + * + * Initializes memory limits structure mem_lim according to + * the current system configuration. This structure should be latter used + * to track and limit allocated by one or more SGV pools memory. + */ void scst_init_mem_lim(struct scst_mem_lim *mem_lim) { atomic_set(&mem_lim->alloced_pages, 0); @@ -2173,7 +2278,7 @@ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, if (tgt != NULL) { TRACE_DBG("Adding acg '%s' to device '%s' acg_list", acg_name, tgt->tgt_name); - list_add_tail(&acg->acg_list_entry, &tgt->acg_list); + list_add_tail(&acg->acg_list_entry, &tgt->tgt_acg_list); acg->in_tgt_acg_list = 1; } #endif @@ -2273,7 +2378,7 @@ struct scst_acg *scst_tgt_find_acg(struct scst_tgt *tgt, const char *name) TRACE_ENTRY(); - list_for_each_entry(acg, &tgt->acg_list, acg_list_entry) { + list_for_each_entry(acg, &tgt->tgt_acg_list, acg_list_entry) { if (strcmp(acg->acg_name, name) == 0) { acg_ret = acg; break; @@ -3551,12 +3656,18 @@ void scst_sched_session_free(struct scst_session *sess) return; } +/** + * scst_cmd_get() - increase command's reference counter + */ void scst_cmd_get(struct scst_cmd *cmd) { __scst_cmd_get(cmd); } EXPORT_SYMBOL(scst_cmd_get); +/** + * scst_cmd_put() - decrease command's reference counter + */ void scst_cmd_put(struct scst_cmd *cmd) { __scst_cmd_put(cmd); @@ -4258,6 +4369,12 @@ out_free_sioc: #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) */ +/** + * scst_copy_sg() - copy data between the command's SGs + * + * Copies data between cmd->tgt_sg and cmd->sg in direction defined by + * copy_dir parameter. + */ void scst_copy_sg(struct scst_cmd *cmd, enum scst_sg_copy_dir copy_dir) { struct scatterlist *src_sg, *dst_sg; @@ -4493,6 +4610,16 @@ static int get_trans_len_none(struct scst_cmd *cmd, uint8_t off) return 0; } +/** + * scst_get_cdb_info() - fill various info about the command's CDB + * + * Description: + * Fills various info about the command's CDB in the corresponding fields + * in the command. + * + * Returns: 0 on success, <0 if command is unknown, >0 if command + * is invalid. + */ int scst_get_cdb_info(struct scst_cmd *cmd) { int dev_type = cmd->dev->type; @@ -4676,6 +4803,17 @@ out_err: goto out; } +/** + ** Generic parse() support routines. + ** Done via pointer on functions to avoid unneeded dereferences on + ** the fast path. + **/ + +/** + * scst_calc_block_shift() - calculate block shift + * + * Calculates and returns block shift for the given sector size + */ int scst_calc_block_shift(int sector_size) { int block_shift = 0; @@ -4701,6 +4839,11 @@ int scst_calc_block_shift(int sector_size) } EXPORT_SYMBOL(scst_calc_block_shift); +/** + * scst_sbc_generic_parse() - generic SBC parsing + * + * Generic parse() for SBC (disk) devices + */ int scst_sbc_generic_parse(struct scst_cmd *cmd, int (*get_block_shift)(struct scst_cmd *cmd)) { @@ -4757,6 +4900,11 @@ set_timeout: } EXPORT_SYMBOL(scst_sbc_generic_parse); +/** + * scst_cdrom_generic_parse() - generic MMC parse + * + * Generic parse() for MMC (cdrom) devices + */ int scst_cdrom_generic_parse(struct scst_cmd *cmd, int (*get_block_shift)(struct scst_cmd *cmd)) { @@ -4809,6 +4957,11 @@ set_timeout: } EXPORT_SYMBOL(scst_cdrom_generic_parse); +/** + * scst_modisk_generic_parse() - generic MO parse + * + * Generic parse() for MO disk devices + */ int scst_modisk_generic_parse(struct scst_cmd *cmd, int (*get_block_shift)(struct scst_cmd *cmd)) { @@ -4861,6 +5014,11 @@ set_timeout: } EXPORT_SYMBOL(scst_modisk_generic_parse); +/** + * scst_tape_generic_parse() - generic tape parse + * + * Generic parse() for tape devices + */ int scst_tape_generic_parse(struct scst_cmd *cmd, int (*get_block_size)(struct scst_cmd *cmd)) { @@ -4933,6 +5091,11 @@ static int scst_null_parse(struct scst_cmd *cmd) return res; } +/** + * scst_changer_generic_parse() - generic changer parse + * + * Generic parse() for changer devices + */ int scst_changer_generic_parse(struct scst_cmd *cmd, int (*nothing)(struct scst_cmd *cmd)) { @@ -4947,6 +5110,11 @@ int scst_changer_generic_parse(struct scst_cmd *cmd, } EXPORT_SYMBOL(scst_changer_generic_parse); +/** + * scst_processor_generic_parse - generic SCSI processor parse + * + * Generic parse() for SCSI processor devices + */ int scst_processor_generic_parse(struct scst_cmd *cmd, int (*nothing)(struct scst_cmd *cmd)) { @@ -4961,6 +5129,11 @@ int scst_processor_generic_parse(struct scst_cmd *cmd, } EXPORT_SYMBOL(scst_processor_generic_parse); +/** + * scst_raid_generic_parse() - generic RAID parse + * + * Generic parse() for RAID devices + */ int scst_raid_generic_parse(struct scst_cmd *cmd, int (*nothing)(struct scst_cmd *cmd)) { @@ -4975,6 +5148,17 @@ int scst_raid_generic_parse(struct scst_cmd *cmd, } EXPORT_SYMBOL(scst_raid_generic_parse); +/** + ** Generic dev_done() support routines. + ** Done via pointer on functions to avoid unneeded dereferences on + ** the fast path. + **/ + +/** + * scst_block_generic_dev_done() - generic SBC dev_done + * + * Generic dev_done() for block (SBC) devices + */ int scst_block_generic_dev_done(struct scst_cmd *cmd, void (*set_block_shift)(struct scst_cmd *cmd, int block_shift)) { @@ -5034,6 +5218,11 @@ out: } EXPORT_SYMBOL(scst_block_generic_dev_done); +/** + * scst_tape_generic_dev_done() - generic tape dev done + * + * Generic dev_done() for tape devices + */ int scst_tape_generic_dev_done(struct scst_cmd *cmd, void (*set_block_size)(struct scst_cmd *cmd, int block_shift)) { @@ -5121,6 +5310,12 @@ static void scst_check_internal_sense(struct scst_device *dev, int result, return; } +/** + * scst_to_dma_dir() - translate SCST's data direction to DMA direction + * + * Translates SCST's data direction to DMA one from backend storage + * perspective. + */ enum dma_data_direction scst_to_dma_dir(int scst_dir) { static const enum dma_data_direction tr_tbl[] = { DMA_NONE, @@ -5130,6 +5325,12 @@ enum dma_data_direction scst_to_dma_dir(int scst_dir) } EXPORT_SYMBOL(scst_to_dma_dir); +/* + * scst_to_tgt_dma_dir() - translate SCST data direction to DMA direction + * + * Translates SCST data direction to DMA data direction from the perspective + * of the target device. + */ enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir) { static const enum dma_data_direction tr_tbl[] = { DMA_NONE, @@ -5139,6 +5340,12 @@ enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir) } EXPORT_SYMBOL(scst_to_tgt_dma_dir); +/** + * scst_obtain_device_parameters() - obtain device control parameters + * + * Issues a MODE SENSE for control mode page data and sets the corresponding + * dev's parameter from it. Returns 0 on success and not 0 otherwise. + */ int scst_obtain_device_parameters(struct scst_device *dev) { int rc, i; @@ -5703,6 +5910,18 @@ out_unlock: return res; } +/***************************************************************** + ** The following thr_data functions are necessary, because the + ** kernel doesn't provide a better way to have threads local + ** storage + *****************************************************************/ + +/** + * scst_add_thr_data() - add the current thread's local data + * + * Adds local to the current thread data to tgt_dev + * (they will be local for the tgt_dev and current thread). + */ void scst_add_thr_data(struct scst_tgt_dev *tgt_dev, struct scst_thr_data_hdr *data, void (*free_fn) (struct scst_thr_data_hdr *data)) @@ -5717,6 +5936,11 @@ void scst_add_thr_data(struct scst_tgt_dev *tgt_dev, } EXPORT_SYMBOL(scst_add_thr_data); +/** + * scst_del_all_thr_data() - delete all thread's local data + * + * Deletes all local to threads data from tgt_dev + */ void scst_del_all_thr_data(struct scst_tgt_dev *tgt_dev) { spin_lock(&tgt_dev->thr_data_lock); @@ -5734,6 +5958,11 @@ void scst_del_all_thr_data(struct scst_tgt_dev *tgt_dev) } EXPORT_SYMBOL(scst_del_all_thr_data); +/** + * scst_dev_del_all_thr_data() - delete all thread's local data from device + * + * Deletes all local to threads data from all tgt_dev's of the device + */ void scst_dev_del_all_thr_data(struct scst_device *dev) { struct scst_tgt_dev *tgt_dev; @@ -5770,6 +5999,11 @@ static struct scst_thr_data_hdr *__scst_find_thr_data_locked( return res; } +/** + * __scst_find_thr_data() - find local to the thread data + * + * Finds local to the thread data. Returns NULL, if they not found. + */ struct scst_thr_data_hdr *__scst_find_thr_data(struct scst_tgt_dev *tgt_dev, struct task_struct *tsk) { @@ -6107,12 +6341,31 @@ out: return; } +/** + * scst_get_max_lun_commands() - return maximum supported commands count + * + * Returns maximum commands count which can be queued to this LUN in this + * session. + * + * If lun is NO_SUCH_LUN, returns minimum of maximum commands count which + * can be queued to any LUN in this session. + * + * If sess is NULL, returns minimum of maximum commands count which can be + * queued to any SCST device. + */ int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun) { return SCST_MAX_TGT_DEV_COMMANDS; } EXPORT_SYMBOL(scst_get_max_lun_commands); +/** + * scst_get_next_lexem() - parse and return next lexem in the string + * + * Returns pointer to the next lexem from token_str skipping + * spaces and '=' character and using them then as a delimeter. Content + * of token_str is modified by setting '\0' at the delimeter's position. + */ char *scst_get_next_lexem(char **token_str) { char *p = *token_str; @@ -6136,6 +6389,13 @@ char *scst_get_next_lexem(char **token_str) } EXPORT_SYMBOL(scst_get_next_lexem); +/** + * scst_restore_token_str() - restore string modified by scst_get_next_lexem() + * + * Restores token_str modified by scst_get_next_lexem() to the + * previous value before scst_get_next_lexem() was called. Prev_lexem is + * a pointer to lexem returned by scst_get_next_lexem(). + */ void scst_restore_token_str(char *prev_lexem, char *token_str) { if (&prev_lexem[strlen(prev_lexem)] != token_str) @@ -6144,6 +6404,13 @@ void scst_restore_token_str(char *prev_lexem, char *token_str) } EXPORT_SYMBOL(scst_restore_token_str); +/** + * scst_get_next_token_str() - parse and return next token + * + * This function returns pointer to the next token strings from input_str + * using '\n', ';' and '\0' as a delimeter. Content of input_str is + * modified by setting '\0' at the delimeter's position. + */ char *scst_get_next_token_str(char **input_str) { char *p = *input_str; @@ -6220,7 +6487,15 @@ void scst_lib_exit(void) } #ifdef CONFIG_SCST_DEBUG -/* Original taken from the XFS code */ + +/** + * scst_random() - return a pseudo-random number for debugging purposes. + * + * Returns a pseudo-random number for debugging purposes. Available only in + * the DEBUG build. + * + * Original taken from the XFS code + */ unsigned long scst_random(void) { static int Inited; diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 390cb81a7..17051a395 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -60,7 +60,8 @@ **/ /* - * All targets, devices and dev_types management is done under this mutex. + * Main SCST mutex. All targets, devices and dev_types management is done + * under this mutex. * * It must NOT be used in any works (schedule_work(), etc.), because * otherwise a deadlock (double lock, actually) is possible, e.g., with @@ -161,6 +162,19 @@ struct scst_dev_type scst_null_devtype = { static void __scst_resume_activity(void); +/** + * __scst_register_target_template() - register target template. + * @vtt: target template + * @version: SCST_INTERFACE_VERSION version string to ensure that + * SCST core and the target driver use the same version of + * the SCST interface + * + * Description: + * Registers a target template and returns 0 on success or appropriate + * error code otherwise. + * + * Note: *vtt must be static! + */ int __scst_register_target_template(struct scst_tgt_template *vtt, const char *version) { @@ -291,6 +305,9 @@ out_err: } EXPORT_SYMBOL(__scst_register_target_template); +/** + * scst_unregister_target_template() - unregister target template + */ void scst_unregister_target_template(struct scst_tgt_template *vtt) { struct scst_tgt *tgt; @@ -341,6 +358,12 @@ out_err_up: } EXPORT_SYMBOL(scst_unregister_target_template); +/** + * scst_register_target() - register target + * + * Rgisters a target for template vtt and returns new target structure on + * success or NULL otherwise. + */ struct scst_tgt *scst_register(struct scst_tgt_template *vtt, const char *target_name) { @@ -414,7 +437,7 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt, if (tgt->default_acg == NULL) goto out_free_tgt_name; - INIT_LIST_HEAD(&tgt->acg_list); + INIT_LIST_HEAD(&tgt->tgt_acg_list); #ifdef CONFIG_SCST_PROC rc = scst_build_proc_target_entries(tgt); @@ -492,6 +515,9 @@ static inline int test_sess_list(struct scst_tgt *tgt) return res; } +/** + * scst_unregister_target() - unregister target + */ void scst_unregister(struct scst_tgt *tgt) { struct scst_session *sess; @@ -541,7 +567,8 @@ again: scst_clear_acg(tgt->default_acg); - list_for_each_entry_safe(acg, acg_tmp, &tgt->acg_list, acg_list_entry) { + list_for_each_entry_safe(acg, acg_tmp, &tgt->tgt_acg_list, + acg_list_entry) { scst_acg_sysfs_put(acg); } @@ -585,6 +612,19 @@ static int scst_susp_wait(bool interruptible) return res; } +/** + * scst_suspend_activity() - globally suspend any activity + * + * Description: + * Globally suspends any activity and doesn't return, until there are any + * active commands (state after SCST_CMD_STATE_INIT). If "interruptible" + * is true, it returns after SCST_SUSPENDING_TIMEOUT or if it was interrupted + * by a signal with the corresponding error status < 0. If "interruptible" + * is false, it will wait virtually forever. On success returns 0. + * + * New arriving commands stay in the suspended state until + * scst_resume_activity() is called. + */ int scst_suspend_activity(bool interruptible) { int res = 0; @@ -709,6 +749,11 @@ out: return; } +/** + * scst_resume_activity() - globally resume all activities + * + * Resumes suspended by scst_suspend_activity() activities. + */ void scst_resume_activity(void) { TRACE_ENTRY(); @@ -918,6 +963,15 @@ out: return res; } +/** + * scst_register_virtual_device() - register a virtual device. + * @dev_handler: the device's device handler + * @dev_name: the new device name, NULL-terminated string. Must be uniq + * among all virtual devices in the system. + * + * Registers a virtual device and returns assinged to the device ID on + * success, or negative value otherwise + */ int scst_register_virtual_device(struct scst_dev_type *dev_handler, const char *dev_name) { @@ -1018,6 +1072,10 @@ out_release: } EXPORT_SYMBOL(scst_register_virtual_device); +/** + * scst_unregister_virtual_device() - unegister a virtual device. + * @id: the device's ID, returned by the registration function + */ void scst_unregister_virtual_device(int id) { struct scst_device *d, *dev = NULL; @@ -1063,6 +1121,19 @@ out_unblock: } EXPORT_SYMBOL(scst_unregister_virtual_device); +/** + * __scst_register_dev_driver() - register pass-through dev handler driver + * @dev_type: dev handler template + * @version: SCST_INTERFACE_VERSION version string to ensure that + * SCST core and the dev handler use the same version of + * the SCST interface + * + * Description: + * Registers a pass-through dev handler driver. Returns 0 on success + * or appropriate error code otherwise. + * + * Note: *dev_type must be static! + */ int __scst_register_dev_driver(struct scst_dev_type *dev_type, const char *version) { @@ -1179,6 +1250,9 @@ out_error: } EXPORT_SYMBOL(__scst_register_dev_driver); +/** + * scst_unregister_dev_driver() - unregister pass-through dev handler driver + */ void scst_unregister_dev_driver(struct scst_dev_type *dev_type) { struct scst_device *dev; @@ -1234,6 +1308,19 @@ out_up: } EXPORT_SYMBOL(scst_unregister_dev_driver); +/** + * __scst_register_virtual_dev_driver() - register virtual dev handler driver + * @dev_type: dev handler template + * @version: SCST_INTERFACE_VERSION version string to ensure that + * SCST core and the dev handler use the same version of + * the SCST interface + * + * Description: + * Registers a virtual dev handler driver. Returns 0 on success or + * appropriate error code otherwise. + * + * Note: *dev_type must be static! + */ int __scst_register_virtual_dev_driver(struct scst_dev_type *dev_type, const char *version) { @@ -1292,6 +1379,9 @@ out_err: } EXPORT_SYMBOL(__scst_register_virtual_dev_driver); +/** + * scst_unregister_virtual_dev_driver() - unregister virtual dev driver + */ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type) { TRACE_ENTRY(); @@ -1591,6 +1681,11 @@ out_null: goto out; } +/** + * scst_init_threads() - initialize SCST processing threads pool + * + * Initializes scst_cmd_threads structure + */ void scst_init_threads(struct scst_cmd_threads *cmd_threads) { TRACE_ENTRY(); @@ -1610,6 +1705,11 @@ void scst_init_threads(struct scst_cmd_threads *cmd_threads) } EXPORT_SYMBOL(scst_init_threads); +/** + * scst_deinit_threads() - deinitialize SCST processing threads pool + * + * Deinitializes scst_cmd_threads structure + */ void scst_deinit_threads(struct scst_cmd_threads *cmd_threads) { TRACE_ENTRY(); @@ -1692,12 +1792,25 @@ out_unlock: return res; } +/** + * scst_get() - increase global SCST ref counter + * + * Increases global SCST ref counter that prevents from entering into suspended + * activities stage, so protects from any global management operations. + */ void scst_get(void) { __scst_get(0); } EXPORT_SYMBOL(scst_get); +/** + * scst_put() - decrease global SCST ref counter + * + * Decreses global SCST ref counter that prevents from entering into suspended + * activities stage, so protects from any global management operations. On + * zero, if suspending activities is waiting, they will be suspended. + */ void scst_put(void) { __scst_put(); @@ -1705,6 +1818,12 @@ void scst_put(void) EXPORT_SYMBOL(scst_put); #ifndef CONFIG_SCST_PROC +/** + * scst_get_setup_id() - return SCST setup ID + * + * Returns SCST setup ID. This ID can be used for multiple + * setups with the same configuration. + */ unsigned int scst_get_setup_id(void) { return scst_setup_id; diff --git a/scst/src/scst_mem.c b/scst/src/scst_mem.c index 5cb71283b..4dfb519e0 100644 --- a/scst/src/scst_mem.c +++ b/scst/src/scst_mem.c @@ -883,6 +883,21 @@ static void sgv_uncheck_allowed_mem(struct scst_mem_lim *mem_lim, int pages) return; } +/** + * sgv_pool_alloc - allocate an SG vector from the SGV pool + * @pool: the cache to alloc from + * @size: size of the resulting SG vector in bytes + * @gfp_mask: the allocation mask + * @flags: the allocation flags + * @count: the resulting count of SG entries in the resulting SG vector + * @sgv: the resulting SGV object + * @mem_lim: memory limits + * @priv: pointer to private for this allocation data + * + * Description: + * Allocate an SG vector from the SGV pool and returns pointer to it or + * NULL in case of any error. See the SGV pool documentation for more details. + */ struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, unsigned int size, gfp_t gfp_mask, int flags, int *count, struct sgv_pool_obj **sgv, struct scst_mem_lim *mem_lim, void *priv) @@ -1140,12 +1155,26 @@ out_uncheck: } EXPORT_SYMBOL(sgv_pool_alloc); +/** + * sgv_get_priv - return the private allocation data + * + * Allows to get the allocation private data for this SGV + * cache object. The private data supposed to be set by sgv_pool_alloc(). + */ void *sgv_get_priv(struct sgv_pool_obj *obj) { return obj->allocator_priv; } EXPORT_SYMBOL(sgv_get_priv); +/** + * sgv_pool_free - free previously allocated SG vector + * @sgv: the SGV object to free + * @mem_lim: memory limits + * + * Description: + * Frees previously allocated SG vector and updates memory limits + */ void sgv_pool_free(struct sgv_pool_obj *obj, struct scst_mem_lim *mem_lim) { int pages = (obj->sg_count != 0) ? obj->pages : 0; @@ -1168,6 +1197,13 @@ void sgv_pool_free(struct sgv_pool_obj *obj, struct scst_mem_lim *mem_lim) } EXPORT_SYMBOL(sgv_pool_free); +/** + * scst_alloc() - allocates an SG vector + * + * Allocates and returns pointer to SG vector with data size "size". + * In *count returned the count of entries in the vector. + * Returns NULL for failure. + */ struct scatterlist *scst_alloc(int size, gfp_t gfp_mask, int *count) { struct scatterlist *res; @@ -1230,6 +1266,11 @@ out_uncheck: } EXPORT_SYMBOL(scst_alloc); +/** + * scst_free() - frees SG vector + * + * Frees SG vector returned by scst_alloc(). + */ void scst_free(struct scatterlist *sg, int count) { TRACE_MEM("Freeing sg=%p", sg); @@ -1403,6 +1444,11 @@ static void sgv_evaluate_local_max_pages(void) return; } +/** + * sgv_pool_flush - flushe the SGV pool + * + * Flushes, i.e. frees, all the cached entries in the SGV pool. + */ void sgv_pool_flush(struct sgv_pool *pool) { int i; @@ -1457,6 +1503,16 @@ static void sgv_pool_deinit_put(struct sgv_pool *pool) return; } +/** + * sgv_pool_set_allocator - set custom pages allocator + * @pool: the cache + * @alloc_pages_fn: pages allocation function + * @free_pages_fn: pages freeing function + * + * Description: + * Allows to set custom pages allocator for the SGV pool. + * See the SGV pool documentation for more details. + */ void sgv_pool_set_allocator(struct sgv_pool *pool, struct page *(*alloc_pages_fn)(struct scatterlist *, gfp_t, void *), void (*free_pages_fn)(struct scatterlist *, int, void *)) @@ -1467,6 +1523,30 @@ void sgv_pool_set_allocator(struct sgv_pool *pool, } EXPORT_SYMBOL(sgv_pool_set_allocator); +/** + * sgv_pool_create - creates and initializes an SGV pool + * @name: the name of the SGV pool + * @clustered: sets type of the pages clustering. + * @single_alloc_pages: if 0, then the SGV pool will work in the set of + * power 2 size buffers mode. If >0, then the SGV pool will + * work in the fixed size buffers mode. In this case + * single_alloc_pages sets the size of each buffer in pages. + * @shared: sets if the SGV pool can be shared between devices or not. + * The cache sharing allowed only between devices created inside + * the same address space. If an SGV pool is shared, each + * subsequent call of sgv_pool_create() with the same cache name + * will not create a new cache, but instead return a reference + * to it. + * @purge_interval: sets the cache purging interval. I.e., an SG buffer + * will be freed if it's unused for time t + * purge_interval <= t < 2*purge_interval. If purge_interval + * is 0, then the default interval will be used (60 seconds). + * If purge_interval <0, then the automatic purging will be + * disabled. + * + * Description: + * Returns the resulting SGV pool or NULL in case of any error. + */ struct sgv_pool *sgv_pool_create(const char *name, enum sgv_clustering_types clustering_type, int single_alloc_pages, bool shared, int purge_interval) @@ -1548,6 +1628,11 @@ void sgv_pool_destroy(struct sgv_pool *pool) return; } +/** + * sgv_pool_get - increase ref counter for the corresponding SGV pool + * + * Increases ref counter for the corresponding SGV pool + */ void sgv_pool_get(struct sgv_pool *pool) { atomic_inc(&pool->sgv_pool_ref); @@ -1557,6 +1642,12 @@ void sgv_pool_get(struct sgv_pool *pool) } EXPORT_SYMBOL(sgv_pool_get); +/** + * sgv_pool_put - decrease ref counter for the corresponding SGV pool + * + * Decreases ref counter for the corresponding SGV pool. If the ref + * counter reaches 0, the cache will be destroyed. + */ void sgv_pool_put(struct sgv_pool *pool) { TRACE_MEM("Decrementing sgv pool %p ref (new value %d)", @@ -1567,6 +1658,14 @@ void sgv_pool_put(struct sgv_pool *pool) } EXPORT_SYMBOL(sgv_pool_put); +/** + * sgv_pool_del - deletes the corresponding SGV pool + * @pool: the cache to delete. + * + * Description: + * If the cache is shared, it will decrease its reference counter. + * If the reference counter reaches 0, the cache will be destroyed. + */ void sgv_pool_del(struct sgv_pool *pool) { TRACE_ENTRY(); diff --git a/scst/src/scst_mem.h b/scst/src/scst_mem.h index f59c067c5..81d30ddcc 100644 --- a/scst/src/scst_mem.h +++ b/scst/src/scst_mem.h @@ -30,6 +30,9 @@ struct trans_tbl_ent { unsigned short pg_count; }; +/* + * SGV pool object + */ struct sgv_pool_obj { int cache_num; int pages; @@ -50,11 +53,17 @@ struct sgv_pool_obj { struct scatterlist sg_entries_data[0]; }; +/* + * SGV pool statistics accounting structure + */ struct sgv_pool_cache_acc { atomic_t total_alloc, hit_alloc; atomic_t merged; }; +/* + * SGV pool allocation functions + */ struct sgv_pool_alloc_fns { struct page *(*alloc_pages_fn)(struct scatterlist *sg, gfp_t gfp_mask, void *priv); @@ -62,6 +71,9 @@ struct sgv_pool_alloc_fns { void *priv); }; +/* + * SGV pool + */ struct sgv_pool { enum sgv_clustering_types clustering_type; int single_alloc_pages; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index aaca5caac..9a529fafd 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -35,6 +35,7 @@ static struct kobject *scst_devices_kobj; static struct kobject *scst_sgv_kobj; static struct kobject *scst_handlers_kobj; +/* Regular SCST sysfs operations */ struct sysfs_ops scst_sysfs_ops; EXPORT_SYMBOL(scst_sysfs_ops); @@ -2301,7 +2302,7 @@ static ssize_t scst_ini_group_mgmt_store(struct kobject *kobj, goto out_free_up; } - list_for_each_entry(a, &tgt->acg_list, acg_list_entry) { + list_for_each_entry(a, &tgt->tgt_acg_list, acg_list_entry) { if (strcmp(a->acg_name, p) == 0) { TRACE_DBG("group (acg) %p %s found", a, a->acg_name); @@ -3803,6 +3804,14 @@ static struct scst_sysfs_user_info *scst_sysfs_user_find_info(uint32_t cookie) return res; } +/** + * scst_sysfs_user_get_info() - get user_info + * + * Finds the user_info based on cookie and mark it as received the reply by + * setting for it flag info_being_executed. + * + * Returns found entry or NULL. + */ struct scst_sysfs_user_info *scst_sysfs_user_get_info(uint32_t cookie) { struct scst_sysfs_user_info *res = NULL; @@ -3824,6 +3833,18 @@ struct scst_sysfs_user_info *scst_sysfs_user_get_info(uint32_t cookie) } EXPORT_SYMBOL(scst_sysfs_user_get_info); +/** + ** Helper functionality to help target drivers and dev handlers support + ** sending events to user space and wait for their completion in a safe + ** manner. See samples how to use it in iscsi-scst or scst_user. + **/ + +/** + * scst_sysfs_user_add_info() - create and add user_info in the global list + * + * Creates an info structure and adds it in the info_list. + * Returns 0 and out_info on success, error code otherwise. + */ int scst_sysfs_user_add_info(struct scst_sysfs_user_info **out_info) { int res = 0; @@ -3860,6 +3881,9 @@ out: } EXPORT_SYMBOL(scst_sysfs_user_add_info); +/** + * scst_sysfs_user_del_info - delete and frees user_info + */ void scst_sysfs_user_del_info(struct scst_sysfs_user_info *info) { TRACE_ENTRY(); @@ -3878,6 +3902,11 @@ void scst_sysfs_user_del_info(struct scst_sysfs_user_info *info) } EXPORT_SYMBOL(scst_sysfs_user_del_info); +/* + * Returns true if the reply received and being processed by another part of + * the kernel, false otherwise. Also removes the user_info from the list to + * fix for the user space that it missed the timeout. + */ static bool scst_sysfs_user_info_executing(struct scst_sysfs_user_info *info) { bool res; @@ -3899,6 +3928,16 @@ static bool scst_sysfs_user_info_executing(struct scst_sysfs_user_info *info) return res; } +/** + * scst_wait_info_completion() - wait an user space event's completion + * + * Waits for the info request been completed by user space at most timeout + * jiffies. If the reply received before timeout and being processed by + * another part of the kernel, i.e. scst_sysfs_user_info_executing() + * returned true, waits for it to complete indefinitely. + * + * Returns status of the request completion. + */ int scst_wait_info_completion(struct scst_sysfs_user_info *info, unsigned long timeout) { diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index cdabada3c..0245abb02 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -65,9 +65,21 @@ static inline void scst_schedule_tasklet(struct scst_cmd *cmd) tasklet_schedule(&t->tasklet); } -/* - * Must not be called in parallel with scst_unregister_session() for the - * same sess +/** + * scst_rx_cmd() - create new command + * @sess: SCST session + * @lun: LUN for the command + * @lun_len: length of the LUN in bytes + * @cdb: CDB of the command + * @cdb_len: length of the CDB in bytes + * @atomic: true, if current context is atomic + * + * Description: + * Creates new SCST command. Returns new command on success or + * NULL otherwise. + * + * Must not be called in parallel with scst_unregister_session() for the + * same session. */ struct scst_cmd *scst_rx_cmd(struct scst_session *sess, const uint8_t *lun, int lun_len, @@ -202,6 +214,29 @@ out_redirect: goto out; } +/** + * scst_cmd_init_done() - the command's initialization done + * @cmd: SCST command + * @pref_context: preferred command execution context + * + * Description: + * Notifies SCST that the driver finished its part of the command + * initialization, and the command is ready for execution. + * The second argument sets preferred command execition context. + * See SCST_CONTEXT_* constants for details. + * + * !!IMPORTANT!! + * + * If cmd->set_sn_on_restart_cmd not set, this function, as well as + * scst_cmd_init_stage1_done() and scst_restart_cmd(), must not be + * called simultaneously for the same session (more precisely, + * for the same session/LUN, i.e. tgt_dev), i.e. they must be + * somehow externally serialized. This is needed to have lock free fast + * path in scst_cmd_set_sn(). For majority of targets those functions are + * naturally serialized by the single source of commands. Only iSCSI + * immediate commands with multiple connections per session seems to be an + * exception. For it, some mutex/lock shall be used for the serialization. + */ void scst_cmd_init_done(struct scst_cmd *cmd, enum scst_exec_context pref_context) { @@ -846,6 +881,22 @@ static int scst_preprocessing_done(struct scst_cmd *cmd) return res; } +/** + * scst_restart_cmd() - restart execution of the command + * @cmd: SCST commands + * @status: completion status + * @pref_context: preferred command execition context + * + * Description: + * Notifies SCST that the driver finished its part of the command's + * preprocessing and it is ready for further processing. + * + * The second argument sets completion status + * (see SCST_PREPROCESS_STATUS_* constants for details) + * + * See also comment for scst_cmd_init_done() for the serialization + * requirements. + */ void scst_restart_cmd(struct scst_cmd *cmd, int status, enum scst_exec_context pref_context) { @@ -1089,6 +1140,19 @@ static void scst_process_redirect_cmd(struct scst_cmd *cmd, return; } +/** + * scst_rx_data() - the command's data received + * @cmd: SCST commands + * @status: data receiving completion status + * @pref_context: preferred command execition context + * + * Description: + * Notifies SCST that the driver received all the necessary data + * and the command is ready for further processing. + * + * The second argument sets data receiving completion status + * (see SCST_RX_STATUS_* constants for details) + */ void scst_rx_data(struct scst_cmd *cmd, int status, enum scst_exec_context pref_context) { @@ -1818,7 +1882,20 @@ out_done: goto out; } -/* No locks, no IRQ or IRQ-disabled context allowed */ +/** + * scst_check_local_events() - check if there are any local SCSI events + * + * Description: + * Checks if the command can be executed or there are local events, + * like reservatons, pending UAs, etc. Returns < 0 if command must be + * aborted, > 0 if there is an event and command should be immediately + * completed, or 0 otherwise. + * + * !! Dev handlers implementing exec() callback must call this function there + * !! just before the actual command's execution! + * + * On call no locks, no IRQ or IRQ-disabled context allowed. + */ int scst_check_local_events(struct scst_cmd *cmd) { int res, rc; @@ -3072,6 +3149,18 @@ out_error: goto out; } +/** + * scst_tgt_cmd_done() - the command's processing done + * @cmd: SCST command + * @pref_context: preferred command execution context + * + * Description: + * Notifies SCST that the driver sent the response and the command + * can be freed now. Don't forget to set the delivery status, if it + * isn't success, using scst_set_delivery_status() before calling + * this function. The third argument sets preferred command execition + * context (see SCST_CONTEXT_* constants for details) + */ void scst_tgt_cmd_done(struct scst_cmd *cmd, enum scst_exec_context pref_context) { @@ -3539,7 +3628,16 @@ int scst_init_thread(void *arg) return 0; } -/* Called with no locks held */ +/** + * scst_process_active_cmd() - process active command + * + * Description: + * Main SCST commands processing routing. Must be used only by dev handlers. + * + * Argument atomic is true, if function called in atomic context. + * + * Must be called with no locks held. + */ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic) { int res; @@ -3702,6 +3800,13 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic) } EXPORT_SYMBOL(scst_process_active_cmd); +/** + * scst_post_parse_process_active_cmd() - process command after parse + * + * SCST commands processing routine, which should be called by dev handler + * after its parse() callback returned SCST_CMD_STATE_STOP. Arguments are + * the same as for scst_process_active_cmd(). + */ void scst_post_parse_process_active_cmd(struct scst_cmd *cmd, bool atomic) { scst_set_parse_time(cmd); @@ -3989,7 +4094,14 @@ out: return mcmd->cmd_finish_wait_count; } -/* No locks */ +/** + * scst_prepare_async_mcmd() - prepare async management command + * + * Notifies SCST that management command is going to be async, i.e. + * will be completed in another context. + * + * No SCST locks supposed to be held on entrance. + */ void scst_prepare_async_mcmd(struct scst_mgmt_cmd *mcmd) { unsigned long flags; @@ -4009,7 +4121,14 @@ void scst_prepare_async_mcmd(struct scst_mgmt_cmd *mcmd) } EXPORT_SYMBOL(scst_prepare_async_mcmd); -/* No locks */ +/** + * scst_async_mcmd_completed() - async management command completed + * + * Notifies SCST that async management command, prepared by + * scst_prepare_async_mcmd(), completed. + * + * No SCST locks supposed to be held on entrance. + */ void scst_async_mcmd_completed(struct scst_mgmt_cmd *mcmd, int status) { unsigned long flags; @@ -5316,9 +5435,16 @@ out_unlock: goto out; } -/* - * Must not be called in parallel with scst_unregister_session() for the - * same sess +/** + * scst_rx_mgmt_fn() - create new management command and send it for execution + * + * Description: + * Creates new management command and sends it for execution. + * + * Returns 0 for success, error code otherwise. + * + * Must not be called in parallel with scst_unregister_session() for the + * same sess. */ int scst_rx_mgmt_fn(struct scst_session *sess, const struct scst_rx_mgmt_params *params) @@ -5498,7 +5624,7 @@ static struct scst_acg *scst_find_tgt_acg_by_name_wild(struct scst_tgt *tgt, if (initiator_name == NULL) goto out; - list_for_each_entry(acg, &tgt->acg_list, acg_list_entry) { + list_for_each_entry(acg, &tgt->tgt_acg_list, acg_list_entry) { list_for_each_entry(n, &acg->acn_list, acn_list_entry) { if (wildcmp(n->name, initiator_name)) { TRACE_DBG("Access control group %s found", @@ -5622,6 +5748,48 @@ restart: return res; } +/** + * scst_register_session() - register session + * @tgt: target + * @atomic: true, if the function called in the atomic context. If false, + * this function will block until the session registration is + * completed. + * @initiator_name: remote initiator's name, any NULL-terminated string, + * e.g. iSCSI name, which used as the key to found appropriate + * access control group. Could be NULL, then the default + * target's LUNs are used. + * @data: any target driver supplied data + * @result_fn: pointer to the function that will be asynchronously called + * when session initialization finishes. + * Can be NULL. Parameters: + * - sess - session + * - data - target driver supplied to scst_register_session() + * data + * - result - session initialization result, 0 on success or + * appropriate error code otherwise + * + * Description: + * Registers new session. Returns new session on success or NULL otherwise. + * + * Note: A session creation and initialization is a complex task, + * which requires sleeping state, so it can't be fully done + * in interrupt context. Therefore the "bottom half" of it, if + * scst_register_session() is called from atomic context, will be + * done in SCST thread context. In this case scst_register_session() + * will return not completely initialized session, but the target + * driver can supply commands to this session via scst_rx_cmd(). + * Those commands processing will be delayed inside SCST until + * the session initialization is finished, then their processing + * will be restarted. The target driver will be notified about + * finish of the session initialization by function result_fn(). + * On success the target driver could do nothing, but if the + * initialization fails, the target driver must ensure that + * no more new commands being sent or will be sent to SCST after + * result_fn() returns. All already sent to SCST commands for + * failed session will be returned in xmit_response() with BUSY status. + * In case of failure the driver shall call scst_unregister_session() + * inside result_fn(), it will NOT be called automatically. + */ struct scst_session *scst_register_session(struct scst_tgt *tgt, int atomic, const char *initiator_name, void *data, void (*result_fn) (struct scst_session *sess, void *data, int result)) @@ -5666,9 +5834,38 @@ out_free: } EXPORT_SYMBOL(scst_register_session); -/* - * Must not be called in parallel with scst_rx_cmd() or - * scst_rx_mgmt_fn_*() for the same sess +/** + * scst_unregister_session() - unregister session + * @sess: session to be unregistered + * @wait: if true, instructs to wait until all commands, which + * currently is being executed and belonged to the session, + * finished. Otherwise, target driver should be prepared to + * receive xmit_response() for the session's command after + * scst_unregister_session() returns. + * @unreg_done_fn: pointer to the function that will be asynchronously called + * when the last session's command finishes and + * the session is about to be completely freed. Can be NULL. + * Parameter: + * - sess - session + * + * Unregisters session. + * + * Notes: + * - All outstanding commands will be finished regularly. After + * scst_unregister_session() returned, no new commands must be sent to + * SCST via scst_rx_cmd(). + * + * - The caller must ensure that no scst_rx_cmd() or scst_rx_mgmt_fn_*() is + * called in paralell with scst_unregister_session(). + * + * - Can be called before result_fn() of scst_register_session() called, + * i.e. during the session registration/initialization. + * + * - It is highly recommended to call scst_unregister_session() as soon as it + * gets clear that session will be unregistered and not to wait until all + * related commands finished. This function provides the wait functionality, + * but it also starts recovering stuck commands, if there are any. + * Otherwise, your target driver could wait for those commands forever. */ void scst_unregister_session(struct scst_session *sess, int wait, void (*unreg_done_fn) (struct scst_session *sess)) @@ -5867,6 +6064,13 @@ static struct scst_cmd *__scst_find_cmd_by_tag(struct scst_session *sess, return res; } +/** + * scst_find_cmd() - find command by custom comparison function + * + * Finds a command based on user supplied data and comparision + * callback function, that should return true, if the command is found. + * Returns the command on success or NULL otherwise + */ struct scst_cmd *scst_find_cmd(struct scst_session *sess, void *data, int (*cmp_fn) (struct scst_cmd *cmd, void *data)) @@ -5907,6 +6111,13 @@ out: } EXPORT_SYMBOL(scst_find_cmd); +/** + * scst_find_cmd_by_tag() - find command by tag + * + * Finds a command based on the supplied tag comparing it with one + * that previously set by scst_cmd_set_tag(). Returns the found command on + * success or NULL otherwise + */ struct scst_cmd *scst_find_cmd_by_tag(struct scst_session *sess, uint64_t tag) { @@ -5918,23 +6129,3 @@ struct scst_cmd *scst_find_cmd_by_tag(struct scst_session *sess, return cmd; } EXPORT_SYMBOL(scst_find_cmd_by_tag); - -void *scst_cmd_get_tgt_priv_lock(struct scst_cmd *cmd) -{ - void *res; - unsigned long flags; - spin_lock_irqsave(&scst_main_lock, flags); - res = cmd->tgt_priv; - spin_unlock_irqrestore(&scst_main_lock, flags); - return res; -} -EXPORT_SYMBOL(scst_cmd_get_tgt_priv_lock); - -void scst_cmd_set_tgt_priv_lock(struct scst_cmd *cmd, void *val) -{ - unsigned long flags; - spin_lock_irqsave(&scst_main_lock, flags); - cmd->tgt_priv = val; - spin_unlock_irqrestore(&scst_main_lock, flags); -} -EXPORT_SYMBOL(scst_cmd_set_tgt_priv_lock);