diff options
Diffstat (limited to 'drivers/target/tcm_fc')
| -rw-r--r-- | drivers/target/tcm_fc/Makefile | 17 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tcm_fc.h | 70 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 445 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_conf.c | 209 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_io.c | 295 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_sess.c | 115 |
6 files changed, 461 insertions, 690 deletions
diff --git a/drivers/target/tcm_fc/Makefile b/drivers/target/tcm_fc/Makefile index 7a5c2b64cf6..20b14bb087c 100644 --- a/drivers/target/tcm_fc/Makefile +++ b/drivers/target/tcm_fc/Makefile @@ -1,15 +1,6 @@ -EXTRA_CFLAGS += -I$(srctree)/drivers/target/ \ - -I$(srctree)/drivers/scsi/ \ - -I$(srctree)/include/scsi/ \ - -I$(srctree)/drivers/target/tcm_fc/ - -tcm_fc-y += tfc_cmd.o \ - tfc_conf.o \ - tfc_io.o \ - tfc_sess.o +tcm_fc-y += tfc_cmd.o \ + tfc_conf.o \ + tfc_io.o \ + tfc_sess.o obj-$(CONFIG_TCM_FC) += tcm_fc.o - -ifdef CONFIGFS_TCM_FC_DEBUG -EXTRA_CFLAGS += -DTCM_FC_DEBUG -endif diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index defff32b788..a0bcfd3e7e7 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -17,35 +17,12 @@ #ifndef __TCM_FC_H__ #define __TCM_FC_H__ -#define FT_VERSION "0.3" +#define FT_VERSION "0.4" #define FT_NAMELEN 32 /* length of ASCII WWPNs including pad */ #define FT_TPG_NAMELEN 32 /* max length of TPG name */ #define FT_LUN_NAMELEN 32 /* max length of LUN name */ - -/* - * Debug options. - */ -#define FT_DEBUG_CONF 0x01 /* configuration messages */ -#define FT_DEBUG_SESS 0x02 /* session messages */ -#define FT_DEBUG_TM 0x04 /* TM operations */ -#define FT_DEBUG_IO 0x08 /* I/O commands */ -#define FT_DEBUG_DATA 0x10 /* Data transfer */ - -extern unsigned int ft_debug_logging; /* debug options */ - -#define FT_DEBUG(mask, fmt, args...) \ - do { \ - if (ft_debug_logging & (mask)) \ - printk(KERN_INFO "tcm_fc: %s: " fmt, \ - __func__, ##args); \ - } while (0) - -#define FT_CONF_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_CONF, fmt, ##args) -#define FT_SESS_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_SESS, fmt, ##args) -#define FT_TM_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_TM, fmt, ##args) -#define FT_IO_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_IO, fmt, ##args) -#define FT_DATA_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_DATA, fmt, ##args) +#define TCM_FC_DEFAULT_TAGS 512 /* tags used for per-session preallocation */ struct ft_transport_id { __u8 format; @@ -117,52 +94,43 @@ struct ft_lun { */ struct ft_tpg { u32 index; - struct ft_lport_acl *lport_acl; + struct ft_lport_wwn *lport_wwn; struct ft_tport *tport; /* active tport or NULL */ - struct list_head list; /* linkage in ft_lport_acl tpg_list */ struct list_head lun_list; /* head of LUNs */ struct se_portal_group se_tpg; - struct task_struct *thread; /* processing thread */ - struct se_queue_obj qobj; /* queue for processing thread */ + struct workqueue_struct *workqueue; }; -struct ft_lport_acl { +struct ft_lport_wwn { u64 wwpn; char name[FT_NAMELEN]; - struct list_head list; - struct list_head tpg_list; - struct se_wwn fc_lport_wwn; -}; - -enum ft_cmd_state { - FC_CMD_ST_NEW = 0, - FC_CMD_ST_REJ + struct list_head ft_wwn_node; + struct ft_tpg *tpg; + struct se_wwn se_wwn; }; /* * Commands */ struct ft_cmd { - enum ft_cmd_state state; - u16 lun; /* LUN from request */ struct ft_sess *sess; /* session held for cmd */ struct fc_seq *seq; /* sequence in exchange mgr */ struct se_cmd se_cmd; /* Local TCM I/O descriptor */ struct fc_frame *req_frame; - unsigned char *cdb; /* pointer to CDB inside frame */ u32 write_data_len; /* data received on writes */ - struct se_queue_req se_req; + struct work_struct work; /* Local sense buffer */ unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; u32 was_ddp_setup:1; /* Set only if ddp is setup */ + u32 aborted:1; /* Set if aborted by reset or timeout */ struct scatterlist *sg; /* Set only if DDP is setup */ u32 sg_cnt; /* No. of item in scatterlist */ }; -extern struct list_head ft_lport_list; extern struct mutex ft_lport_lock; extern struct fc4_prov ft_prov; extern struct target_fabric_configfs *ft_configfs; +extern unsigned int ft_debug_logging; /* * Fabric methods. @@ -174,11 +142,8 @@ extern struct target_fabric_configfs *ft_configfs; void ft_sess_put(struct ft_sess *); int ft_sess_shutdown(struct se_session *); void ft_sess_close(struct se_session *); -void ft_sess_stop(struct se_session *, int, int); -int ft_sess_logged_in(struct se_session *); u32 ft_sess_get_index(struct se_session *); u32 ft_sess_get_port_name(struct se_session *, unsigned char *, u32); -void ft_sess_set_erl0(struct se_session *); void ft_lport_add(struct fc_lport *, void *); void ft_lport_del(struct fc_lport *, void *); @@ -187,7 +152,7 @@ int ft_lport_notify(struct notifier_block *, unsigned long, void *); /* * IO methods. */ -void ft_check_stop_free(struct se_cmd *); +int ft_check_stop_free(struct se_cmd *); void ft_release_cmd(struct se_cmd *); int ft_queue_status(struct se_cmd *); int ft_queue_data_in(struct se_cmd *); @@ -195,14 +160,12 @@ int ft_write_pending(struct se_cmd *); int ft_write_pending_status(struct se_cmd *); u32 ft_get_task_tag(struct se_cmd *); int ft_get_cmd_state(struct se_cmd *); -void ft_new_cmd_failure(struct se_cmd *); -int ft_queue_tm_resp(struct se_cmd *); -int ft_is_state_remove(struct se_cmd *); +void ft_queue_tm_resp(struct se_cmd *); +void ft_aborted_task(struct se_cmd *); /* * other internal functions. */ -int ft_thread(void *); void ft_recv_req(struct ft_sess *, struct fc_frame *); struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); @@ -212,4 +175,9 @@ void ft_dump_cmd(struct ft_cmd *, const char *caller); ssize_t ft_format_wwn(char *, size_t, u64); +/* + * Underlying HW specific helper function + */ +void ft_invl_hw_context(struct ft_cmd *); + #endif /* __TCM_FC_H__ */ diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index c056a1132ae..be0c0d08c56 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -19,8 +19,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> -#include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> #include <linux/slab.h> @@ -30,6 +28,7 @@ #include <linux/configfs.h> #include <linux/ctype.h> #include <linux/hash.h> +#include <linux/percpu_ida.h> #include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -40,13 +39,8 @@ #include <scsi/fc_encode.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include <target/target_core_base.h> -#include <target/target_core_tmr.h> #include <target/configfs_macros.h> #include "tcm_fc.h" @@ -54,113 +48,60 @@ /* * Dump cmd state for debugging. */ -void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) +static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller) { struct fc_exch *ep; struct fc_seq *sp; struct se_cmd *se_cmd; - struct se_mem *mem; - struct se_transport_task *task; - - if (!(ft_debug_logging & FT_DEBUG_IO)) - return; + struct scatterlist *sg; + int count; se_cmd = &cmd->se_cmd; - printk(KERN_INFO "%s: cmd %p state %d sess %p seq %p se_cmd %p\n", - caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd); - printk(KERN_INFO "%s: cmd %p cdb %p\n", - caller, cmd, cmd->cdb); - printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun); - - task = T_TASK(se_cmd); - printk(KERN_INFO "%s: cmd %p task %p se_num %u buf %p len %u se_cmd_flags <0x%x>\n", - caller, cmd, task, task->t_tasks_se_num, - task->t_task_buf, se_cmd->data_length, se_cmd->se_cmd_flags); - if (task->t_mem_list) - list_for_each_entry(mem, task->t_mem_list, se_list) - printk(KERN_INFO "%s: cmd %p mem %p page %p " - "len 0x%x off 0x%x\n", - caller, cmd, mem, - mem->se_page, mem->se_len, mem->se_off); + pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n", + caller, cmd, cmd->sess, cmd->seq, se_cmd); + + pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n", + caller, cmd, se_cmd->t_data_nents, + se_cmd->data_length, se_cmd->se_cmd_flags); + + for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, count) + pr_debug("%s: cmd %p sg %p page %p " + "len 0x%x off 0x%x\n", + caller, cmd, sg, + sg_page(sg), sg->length, sg->offset); + sp = cmd->seq; if (sp) { ep = fc_seq_exch(sp); - printk(KERN_INFO "%s: cmd %p sid %x did %x " + pr_debug("%s: cmd %p sid %x did %x " "ox_id %x rx_id %x seq_id %x e_stat %x\n", caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid, sp->id, ep->esb_stat); } - print_hex_dump(KERN_INFO, "ft_dump_cmd ", DUMP_PREFIX_NONE, - 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); -} - -/* - * Get LUN from CDB. - */ -static int ft_get_lun_for_cmd(struct ft_cmd *cmd, u8 *lunp) -{ - u64 lun; - - lun = lunp[1]; - switch (lunp[0] >> 6) { - case 0: - break; - case 1: - lun |= (lunp[0] & 0x3f) << 8; - break; - default: - return -1; - } - if (lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return -1; - cmd->lun = lun; - return transport_get_lun_for_cmd(&cmd->se_cmd, NULL, lun); -} - -static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd) -{ - struct se_queue_obj *qobj; - unsigned long flags; - - qobj = &sess->tport->tpg->qobj; - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - atomic_inc(&qobj->queue_cnt); - wake_up_interruptible(&qobj->thread_wq); } -static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj) +void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) { - unsigned long flags; - struct se_queue_req *qr; - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (list_empty(&qobj->qobj_list)) { - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return NULL; - } - qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list); - list_del(&qr->qr_list); - atomic_dec(&qobj->queue_cnt); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return container_of(qr, struct ft_cmd, se_req); + if (unlikely(ft_debug_logging)) + _ft_dump_cmd(cmd, caller); } static void ft_free_cmd(struct ft_cmd *cmd) { struct fc_frame *fp; struct fc_lport *lport; + struct ft_sess *sess; if (!cmd) return; + sess = cmd->sess; fp = cmd->req_frame; lport = fr_dev(fp); if (fr_seq(fp)) lport->tt.seq_release(fr_seq(fp)); fc_frame_free(fp); - ft_sess_put(cmd->sess); /* undo get from lookup at recv */ - kfree(cmd); + percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); + ft_sess_put(sess); /* undo get from lookup at recv */ } void ft_release_cmd(struct se_cmd *se_cmd) @@ -170,9 +111,10 @@ void ft_release_cmd(struct se_cmd *se_cmd) ft_free_cmd(cmd); } -void ft_check_stop_free(struct se_cmd *se_cmd) +int ft_check_stop_free(struct se_cmd *se_cmd) { - transport_generic_free_cmd(se_cmd, 0, 1, 0); + transport_generic_free_cmd(se_cmd, 0); + return 1; } /* @@ -186,16 +128,20 @@ int ft_queue_status(struct se_cmd *se_cmd) struct fc_lport *lport; struct fc_exch *ep; size_t len; + int rc; + if (cmd->aborted) + return 0; ft_dump_cmd(cmd, __func__); ep = fc_seq_exch(cmd->seq); lport = ep->lp; len = sizeof(*fcp) + se_cmd->scsi_sense_length; fp = fc_frame_alloc(lport, len); if (!fp) { - /* XXX shouldn't just drop it - requeue and retry? */ - return 0; + se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; + return -ENOMEM; } + fcp = fc_frame_payload_get(fp, len); memset(fcp, 0, len); fcp->resp.fr_status = se_cmd->scsi_status; @@ -226,7 +172,18 @@ int ft_queue_status(struct se_cmd *se_cmd) fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); - lport->tt.seq_send(lport, cmd->seq, fp); + rc = lport->tt.seq_send(lport, cmd->seq, fp); + if (rc) { + pr_info_ratelimited("%s: Failed to send response frame %p, " + "xid <0x%x>\n", __func__, fp, ep->xid); + /* + * Generate a TASK_SET_FULL status to notify the initiator + * to reduce it's queue_depth after the se_cmd response has + * been re-queued by target-core. + */ + se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; + return -ENOMEM; + } lport->tt.exch_done(cmd->seq); return 0; } @@ -253,11 +210,13 @@ int ft_write_pending(struct se_cmd *se_cmd) ft_dump_cmd(cmd, __func__); + if (cmd->aborted) + return 0; ep = fc_seq_exch(cmd->seq); lport = ep->lp; fp = fc_frame_alloc(lport, sizeof(*txrdy)); if (!fp) - return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + return -ENOMEM; /* Signal QUEUE_FULL */ txrdy = fc_frame_payload_get(fp, sizeof(*txrdy)); memset(txrdy, 0, sizeof(*txrdy)); @@ -277,20 +236,10 @@ int ft_write_pending(struct se_cmd *se_cmd) */ if ((ep->xid <= lport->lro_xid) && (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { - if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { - /* - * Map se_mem list to scatterlist, so that - * DDP can be setup. DDP setup function require - * scatterlist. se_mem_list is internal to - * TCM/LIO target - */ - transport_do_task_sg_chain(se_cmd); - cmd->sg = T_TASK(se_cmd)->t_tasks_sg_chained; - cmd->sg_cnt = - T_TASK(se_cmd)->t_tasks_sg_chained_no; - } - if (cmd->sg && lport->tt.ddp_setup(lport, ep->xid, - cmd->sg, cmd->sg_cnt)) + if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && + lport->tt.ddp_target(lport, ep->xid, + se_cmd->t_data_sg, + se_cmd->t_data_nents)) cmd->was_ddp_setup = 1; } } @@ -302,25 +251,14 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + if (cmd->aborted) + return ~0; return fc_seq_exch(cmd->seq)->rxid; } int ft_get_cmd_state(struct se_cmd *se_cmd) { - struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); - - return cmd->state; -} - -int ft_is_state_remove(struct se_cmd *se_cmd) -{ - return 0; /* XXX TBD */ -} - -void ft_new_cmd_failure(struct se_cmd *se_cmd) -{ - /* XXX TBD */ - printk(KERN_INFO "%s: se_cmd %p\n", __func__, se_cmd); + return 0; } /* @@ -331,11 +269,10 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) struct ft_cmd *cmd = arg; struct fc_frame_header *fh; - if (IS_ERR(fp)) { + if (unlikely(IS_ERR(fp))) { /* XXX need to find cmd if queued */ - cmd->se_cmd.t_state = TRANSPORT_REMOVE; cmd->seq = NULL; - transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + cmd->aborted = true; return; } @@ -349,10 +286,11 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) case FC_RCTL_DD_SOL_CTL: /* transfer ready */ case FC_RCTL_DD_DATA_DESC: /* transfer ready */ default: - printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", + pr_debug("%s: unhandled frame r_ctl %x\n", __func__, fh->fh_r_ctl); + ft_invl_hw_context(cmd); fc_frame_free(fp); - transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + transport_generic_free_cmd(&cmd->se_cmd, 0); break; } } @@ -374,7 +312,7 @@ static void ft_send_resp_status(struct fc_lport *lport, struct fcp_resp_rsp_info *info; fh = fc_frame_header_get(rx_fp); - FT_IO_DBG("FCP error response: did %x oxid %x status %x code %x\n", + pr_debug("FCP error response: did %x oxid %x status %x code %x\n", ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code); len = sizeof(*fcp); if (status == SAM_STAT_GOOD) @@ -394,20 +332,33 @@ static void ft_send_resp_status(struct fc_lport *lport, fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); sp = fr_seq(fp); - if (sp) + if (sp) { lport->tt.seq_send(lport, sp, fp); - else + lport->tt.exch_done(sp); + } else { lport->tt.frame_send(lport, fp); + } } /* * Send error or task management response. - * Always frees the cmd and associated state. */ -static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) +static void ft_send_resp_code(struct ft_cmd *cmd, + enum fcp_resp_rsp_codes code) { ft_send_resp_status(cmd->sess->tport->lport, cmd->req_frame, SAM_STAT_GOOD, code); +} + + +/* + * Send error or task management response. + * Always frees the cmd and associated state. + */ +static void ft_send_resp_code_and_free(struct ft_cmd *cmd, + enum fcp_resp_rsp_codes code) +{ + ft_send_resp_code(cmd, code); ft_free_cmd(cmd); } @@ -416,8 +367,8 @@ static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) */ static void ft_send_tm(struct ft_cmd *cmd) { - struct se_tmr_req *tmr; struct fcp_cmnd *fcp; + int rc; u8 tm_func; fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); @@ -425,13 +376,6 @@ static void ft_send_tm(struct ft_cmd *cmd) switch (fcp->fc_tm_flags) { case FCP_TMF_LUN_RESET: tm_func = TMR_LUN_RESET; - if (ft_get_lun_for_cmd(cmd, fcp->fc_lun) < 0) { - ft_dump_cmd(cmd, __func__); - transport_send_check_condition_and_sense(&cmd->se_cmd, - cmd->se_cmd.scsi_sense_reason, 0); - ft_sess_put(cmd->sess); - return; - } break; case FCP_TMF_TGT_RESET: tm_func = TMR_TARGET_WARM_RESET; @@ -450,31 +394,30 @@ static void ft_send_tm(struct ft_cmd *cmd) * FCP4r01 indicates having a combination of * tm_flags set is invalid. */ - FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); - ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); + pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); + ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); return; } - FT_TM_DBG("alloc tm cmd fn %d\n", tm_func); - tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); - if (!tmr) { - FT_TM_DBG("alloc failed\n"); - ft_send_resp_code(cmd, FCP_TMF_FAILED); - return; - } - cmd->se_cmd.se_tmr_req = tmr; - transport_generic_handle_tmr(&cmd->se_cmd); + /* FIXME: Add referenced task tag for ABORT_TASK */ + rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess, + &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), + cmd, tm_func, GFP_KERNEL, 0, 0); + if (rc < 0) + ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED); } /* * Send status from completed task management request. */ -int ft_queue_tm_resp(struct se_cmd *se_cmd) +void ft_queue_tm_resp(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); struct se_tmr_req *tmr = se_cmd->se_tmr_req; enum fcp_resp_rsp_codes code; + if (cmd->aborted) + return; switch (tmr->response) { case TMR_FUNCTION_COMPLETE: code = FCP_TMF_CMPL; @@ -486,20 +429,23 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd) code = FCP_TMF_REJECTED; break; case TMR_TASK_DOES_NOT_EXIST: - case TMR_TASK_STILL_ALLEGIANT: - case TMR_TASK_FAILOVER_NOT_SUPPORTED: case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: - case TMR_FUNCTION_AUTHORIZATION_FAILED: default: code = FCP_TMF_FAILED; break; } - FT_TM_DBG("tmr fn %d resp %d fcp code %d\n", + pr_debug("tmr fn %d resp %d fcp code %d\n", tmr->function, tmr->response, code); ft_send_resp_code(cmd, code); - return 0; } +void ft_aborted_task(struct se_cmd *se_cmd) +{ + return; +} + +static void ft_send_work(struct work_struct *work); + /* * Handle incoming FCP command. */ @@ -507,22 +453,31 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) { struct ft_cmd *cmd; struct fc_lport *lport = sess->tport->lport; + struct se_session *se_sess = sess->se_sess; + int tag; - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); - if (!cmd) + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + if (tag < 0) goto busy; + + cmd = &((struct ft_cmd *)se_sess->sess_cmd_map)[tag]; + memset(cmd, 0, sizeof(struct ft_cmd)); + + cmd->se_cmd.map_tag = tag; cmd->sess = sess; cmd->seq = lport->tt.seq_assign(lport, fp); if (!cmd->seq) { - kfree(cmd); + percpu_ida_free(&se_sess->sess_tag_pool, tag); goto busy; } cmd->req_frame = fp; /* hold frame during cmd */ - ft_queue_cmd(sess, cmd); + + INIT_WORK(&cmd->work, ft_send_work); + queue_work(sess->tport->tpg->workqueue, &cmd->work); return; busy: - FT_IO_DBG("cmd or seq allocation failure - sending BUSY\n"); + pr_debug("cmd or seq allocation failure - sending BUSY\n"); ft_send_resp_status(lport, fp, SAM_STAT_BUSY, 0); fc_frame_free(fp); ft_sess_put(sess); /* undo get from lookup */ @@ -547,7 +502,7 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) case FC_RCTL_DD_DATA_DESC: /* transfer ready */ case FC_RCTL_ELS4_REQ: /* SRR, perhaps */ default: - printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", + pr_debug("%s: unhandled frame r_ctl %x\n", __func__, fh->fh_r_ctl); fc_frame_free(fp); ft_sess_put(sess); /* undo get from lookup */ @@ -558,15 +513,13 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) /* * Send new command to target. */ -static void ft_send_cmd(struct ft_cmd *cmd) +static void ft_send_work(struct work_struct *work) { + struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); - struct se_cmd *se_cmd; struct fcp_cmnd *fcp; - int data_dir; - u32 data_len; + int data_dir = 0; int task_attr; - int ret; fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); if (!fcp) @@ -575,56 +528,6 @@ static void ft_send_cmd(struct ft_cmd *cmd) if (fcp->fc_flags & FCP_CFL_LEN_MASK) goto err; /* not handling longer CDBs yet */ - if (fcp->fc_tm_flags) { - task_attr = FCP_PTA_SIMPLE; - data_dir = DMA_NONE; - data_len = 0; - } else { - switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { - case 0: - data_dir = DMA_NONE; - break; - case FCP_CFL_RDDATA: - data_dir = DMA_FROM_DEVICE; - break; - case FCP_CFL_WRDATA: - data_dir = DMA_TO_DEVICE; - break; - case FCP_CFL_WRDATA | FCP_CFL_RDDATA: - goto err; /* TBD not supported by tcm_fc yet */ - } - /* - * Locate the SAM Task Attr from fc_pri_ta - */ - switch (fcp->fc_pri_ta & FCP_PTA_MASK) { - case FCP_PTA_HEADQ: - task_attr = MSG_HEAD_TAG; - break; - case FCP_PTA_ORDERED: - task_attr = MSG_ORDERED_TAG; - break; - case FCP_PTA_ACA: - task_attr = MSG_ACA_TAG; - break; - case FCP_PTA_SIMPLE: /* Fallthrough */ - default: - task_attr = MSG_SIMPLE_TAG; - } - - - task_attr = fcp->fc_pri_ta & FCP_PTA_MASK; - data_len = ntohl(fcp->fc_dl); - cmd->cdb = fcp->fc_cdb; - } - - se_cmd = &cmd->se_cmd; - /* - * Initialize struct se_cmd descriptor from target_core_mod - * infrastructure - */ - transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess, - data_len, data_dir, task_attr, - &cmd->ft_sense_buffer[0]); /* * Check for FCP task management flags */ @@ -633,82 +536,50 @@ static void ft_send_cmd(struct ft_cmd *cmd) return; } - fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); - - ret = ft_get_lun_for_cmd(cmd, fcp->fc_lun); - if (ret < 0) { - ft_dump_cmd(cmd, __func__); - transport_send_check_condition_and_sense(&cmd->se_cmd, - cmd->se_cmd.scsi_sense_reason, 0); - return; - } - - ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb); - - FT_IO_DBG("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret); - ft_dump_cmd(cmd, __func__); - - if (ret == -1) { - transport_send_check_condition_and_sense(se_cmd, - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); - transport_generic_free_cmd(se_cmd, 0, 1, 0); - return; - } - if (ret == -2) { - if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) - ft_queue_status(se_cmd); - else - transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); - transport_generic_free_cmd(se_cmd, 0, 1, 0); - return; + switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { + case 0: + data_dir = DMA_NONE; + break; + case FCP_CFL_RDDATA: + data_dir = DMA_FROM_DEVICE; + break; + case FCP_CFL_WRDATA: + data_dir = DMA_TO_DEVICE; + break; + case FCP_CFL_WRDATA | FCP_CFL_RDDATA: + goto err; /* TBD not supported by tcm_fc yet */ } - transport_generic_handle_cdb(se_cmd); - return; - -err: - ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); - return; -} - -/* - * Handle request in the command thread. - */ -static void ft_exec_req(struct ft_cmd *cmd) -{ - FT_IO_DBG("cmd state %x\n", cmd->state); - switch (cmd->state) { - case FC_CMD_ST_NEW: - ft_send_cmd(cmd); + /* + * Locate the SAM Task Attr from fc_pri_ta + */ + switch (fcp->fc_pri_ta & FCP_PTA_MASK) { + case FCP_PTA_HEADQ: + task_attr = MSG_HEAD_TAG; break; - default: + case FCP_PTA_ORDERED: + task_attr = MSG_ORDERED_TAG; break; + case FCP_PTA_ACA: + task_attr = MSG_ACA_TAG; + break; + case FCP_PTA_SIMPLE: /* Fallthrough */ + default: + task_attr = MSG_SIMPLE_TAG; } -} -/* - * Processing thread. - * Currently one thread per tpg. - */ -int ft_thread(void *arg) -{ - struct ft_tpg *tpg = arg; - struct se_queue_obj *qobj = &tpg->qobj; - struct ft_cmd *cmd; - int ret; - - set_user_nice(current, -20); - - while (!kthread_should_stop()) { - ret = wait_event_interruptible(qobj->thread_wq, - atomic_read(&qobj->queue_cnt) || kthread_should_stop()); - if (ret < 0 || kthread_should_stop()) - goto out; - cmd = ft_dequeue_cmd(qobj); - if (cmd) - ft_exec_req(cmd); - } + fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); + /* + * Use a single se_cmd->cmd_kref as we expect to release se_cmd + * directly from ft_check_stop_free callback in response path. + */ + if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, + &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), + ntohl(fcp->fc_dl), task_attr, data_dir, 0)) + goto err; -out: - return 0; + pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); + return; + +err: + ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); } diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 84e868c255d..efdcb9663a1 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> @@ -32,6 +31,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/configfs.h> +#include <linux/kernel.h> #include <linux/ctype.h> #include <asm/unaligned.h> #include <scsi/scsi.h> @@ -41,21 +41,16 @@ #include <scsi/libfc.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_fabric_configfs.h> -#include <target/target_core_fabric_lib.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> #include <target/target_core_configfs.h> -#include <target/target_core_base.h> #include <target/configfs_macros.h> #include "tcm_fc.h" struct target_fabric_configfs *ft_configfs; -LIST_HEAD(ft_lport_list); +static LIST_HEAD(ft_wwn_list); DEFINE_MUTEX(ft_lport_lock); unsigned int ft_debug_logging; @@ -72,10 +67,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict) { const char *cp; char c; - u32 nibble; u32 byte = 0; u32 pos = 0; u32 err; + int val; *wwn = 0; for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) { @@ -96,17 +91,14 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict) return cp - name; } err = 3; - if (isdigit(c)) - nibble = c - '0'; - else if (isxdigit(c) && (islower(c) || !strict)) - nibble = tolower(c) - 'a' + 10; - else + val = hex_to_bin(c); + if (val < 0 || (strict && isupper(c))) goto fail; - *wwn = (*wwn << 4) | nibble; + *wwn = (*wwn << 4) | val; } err = 4; fail: - FT_CONF_DBG("err %u len %zu pos %u byte %u\n", + pr_debug("err %u len %zu pos %u byte %u\n", err, cp - name, pos, byte); return -1; } @@ -216,14 +208,14 @@ static struct se_node_acl *ft_add_acl( u64 wwpn; u32 q_depth; - FT_CONF_DBG("add acl %s\n", name); + pr_debug("add acl %s\n", name); tpg = container_of(se_tpg, struct ft_tpg, se_tpg); if (ft_parse_wwn(name, &wwpn, 1) < 0) return ERR_PTR(-EINVAL); acl = kzalloc(sizeof(struct ft_node_acl), GFP_KERNEL); - if (!(acl)) + if (!acl) return ERR_PTR(-ENOMEM); acl->node_auth.port_name = wwpn; @@ -239,11 +231,11 @@ static void ft_del_acl(struct se_node_acl *se_acl) struct ft_node_acl *acl = container_of(se_acl, struct ft_node_acl, se_node_acl); - FT_CONF_DBG("del acl %s\n", + pr_debug("del acl %s\n", config_item_name(&se_acl->acl_group.cg_item)); tpg = container_of(se_tpg, struct ft_tpg, se_tpg); - FT_CONF_DBG("del acl %p se_acl %p tpg %p se_tpg %p\n", + pr_debug("del acl %p se_acl %p tpg %p se_tpg %p\n", acl, se_acl, tpg, &tpg->se_tpg); core_tpg_del_initiator_node_acl(&tpg->se_tpg, se_acl, 1); @@ -257,34 +249,34 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) struct se_portal_group *se_tpg = &tpg->se_tpg; struct se_node_acl *se_acl; - spin_lock_bh(&se_tpg->acl_node_lock); + spin_lock_irq(&se_tpg->acl_node_lock); list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) { acl = container_of(se_acl, struct ft_node_acl, se_node_acl); - FT_CONF_DBG("acl %p port_name %llx\n", + pr_debug("acl %p port_name %llx\n", acl, (unsigned long long)acl->node_auth.port_name); if (acl->node_auth.port_name == rdata->ids.port_name || acl->node_auth.node_name == rdata->ids.node_name) { - FT_CONF_DBG("acl %p port_name %llx matched\n", acl, + pr_debug("acl %p port_name %llx matched\n", acl, (unsigned long long)rdata->ids.port_name); found = acl; /* XXX need to hold onto ACL */ break; } } - spin_unlock_bh(&se_tpg->acl_node_lock); + spin_unlock_irq(&se_tpg->acl_node_lock); return found; } -struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg) +static struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg) { struct ft_node_acl *acl; acl = kzalloc(sizeof(*acl), GFP_KERNEL); - if (!(acl)) { - printk(KERN_ERR "Unable to allocate struct ft_node_acl\n"); + if (!acl) { + pr_err("Unable to allocate struct ft_node_acl\n"); return NULL; } - FT_CONF_DBG("acl %p\n", acl); + pr_debug("acl %p\n", acl); return &acl->se_node_acl; } @@ -294,7 +286,7 @@ static void ft_tpg_release_fabric_acl(struct se_portal_group *se_tpg, struct ft_node_acl *acl = container_of(se_acl, struct ft_node_acl, se_node_acl); - FT_CONF_DBG(KERN_INFO "acl %p\n", acl); + pr_debug("acl %p\n", acl); kfree(acl); } @@ -306,45 +298,56 @@ static struct se_portal_group *ft_add_tpg( struct config_group *group, const char *name) { - struct ft_lport_acl *lacl; + struct ft_lport_wwn *ft_wwn; struct ft_tpg *tpg; + struct workqueue_struct *wq; unsigned long index; int ret; - FT_CONF_DBG("tcm_fc: add tpg %s\n", name); + pr_debug("tcm_fc: add tpg %s\n", name); /* * Name must be "tpgt_" followed by the index. */ if (strstr(name, "tpgt_") != name) return NULL; - if (strict_strtoul(name + 5, 10, &index) || index > UINT_MAX) + + ret = kstrtoul(name + 5, 10, &index); + if (ret) + return NULL; + if (index > UINT_MAX) return NULL; - lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn); + if ((index != 1)) { + pr_err("Error, a single TPG=1 is used for HW port mappings\n"); + return ERR_PTR(-ENOSYS); + } + + ft_wwn = container_of(wwn, struct ft_lport_wwn, se_wwn); tpg = kzalloc(sizeof(*tpg), GFP_KERNEL); if (!tpg) return NULL; tpg->index = index; - tpg->lport_acl = lacl; + tpg->lport_wwn = ft_wwn; INIT_LIST_HEAD(&tpg->lun_list); - transport_init_queue_obj(&tpg->qobj); - ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, - (void *)tpg, TRANSPORT_TPG_TYPE_NORMAL); - if (ret < 0) { + wq = alloc_workqueue("tcm_fc", 0, 1); + if (!wq) { kfree(tpg); return NULL; } - tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index); - if (IS_ERR(tpg->thread)) { + ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, + tpg, TRANSPORT_TPG_TYPE_NORMAL); + if (ret < 0) { + destroy_workqueue(wq); kfree(tpg); return NULL; } + tpg->workqueue = wq; mutex_lock(&ft_lport_lock); - list_add_tail(&tpg->list, &lacl->tpg_list); + ft_wwn->tpg = tpg; mutex_unlock(&ft_lport_lock); return &tpg->se_tpg; @@ -353,17 +356,18 @@ static struct se_portal_group *ft_add_tpg( static void ft_del_tpg(struct se_portal_group *se_tpg) { struct ft_tpg *tpg = container_of(se_tpg, struct ft_tpg, se_tpg); + struct ft_lport_wwn *ft_wwn = tpg->lport_wwn; - FT_CONF_DBG("del tpg %s\n", + pr_debug("del tpg %s\n", config_item_name(&tpg->se_tpg.tpg_group.cg_item)); - kthread_stop(tpg->thread); + destroy_workqueue(tpg->workqueue); /* Wait for sessions to be freed thru RCU, for BUG_ON below */ synchronize_rcu(); mutex_lock(&ft_lport_lock); - list_del(&tpg->list); + ft_wwn->tpg = NULL; if (tpg->tport) { tpg->tport->tpg = NULL; tpg->tport = NULL; @@ -382,15 +386,11 @@ static void ft_del_tpg(struct se_portal_group *se_tpg) */ struct ft_tpg *ft_lport_find_tpg(struct fc_lport *lport) { - struct ft_lport_acl *lacl; - struct ft_tpg *tpg; + struct ft_lport_wwn *ft_wwn; - list_for_each_entry(lacl, &ft_lport_list, list) { - if (lacl->wwpn == lport->wwpn) { - list_for_each_entry(tpg, &lacl->tpg_list, list) - return tpg; /* XXX for now return first entry */ - return NULL; - } + list_for_each_entry(ft_wwn, &ft_wwn_list, ft_wwn_node) { + if (ft_wwn->wwpn == lport->wwpn) + return ft_wwn->tpg; } return NULL; } @@ -403,51 +403,49 @@ struct ft_tpg *ft_lport_find_tpg(struct fc_lport *lport) * Add lport to allowed config. * The name is the WWPN in lower-case ASCII, colon-separated bytes. */ -static struct se_wwn *ft_add_lport( +static struct se_wwn *ft_add_wwn( struct target_fabric_configfs *tf, struct config_group *group, const char *name) { - struct ft_lport_acl *lacl; - struct ft_lport_acl *old_lacl; + struct ft_lport_wwn *ft_wwn; + struct ft_lport_wwn *old_ft_wwn; u64 wwpn; - FT_CONF_DBG("add lport %s\n", name); + pr_debug("add wwn %s\n", name); if (ft_parse_wwn(name, &wwpn, 1) < 0) return NULL; - lacl = kzalloc(sizeof(*lacl), GFP_KERNEL); - if (!lacl) + ft_wwn = kzalloc(sizeof(*ft_wwn), GFP_KERNEL); + if (!ft_wwn) return NULL; - lacl->wwpn = wwpn; - INIT_LIST_HEAD(&lacl->tpg_list); + ft_wwn->wwpn = wwpn; mutex_lock(&ft_lport_lock); - list_for_each_entry(old_lacl, &ft_lport_list, list) { - if (old_lacl->wwpn == wwpn) { + list_for_each_entry(old_ft_wwn, &ft_wwn_list, ft_wwn_node) { + if (old_ft_wwn->wwpn == wwpn) { mutex_unlock(&ft_lport_lock); - kfree(lacl); + kfree(ft_wwn); return NULL; } } - list_add_tail(&lacl->list, &ft_lport_list); - ft_format_wwn(lacl->name, sizeof(lacl->name), wwpn); + list_add_tail(&ft_wwn->ft_wwn_node, &ft_wwn_list); + ft_format_wwn(ft_wwn->name, sizeof(ft_wwn->name), wwpn); mutex_unlock(&ft_lport_lock); - return &lacl->fc_lport_wwn; + return &ft_wwn->se_wwn; } -static void ft_del_lport(struct se_wwn *wwn) +static void ft_del_wwn(struct se_wwn *wwn) { - struct ft_lport_acl *lacl = container_of(wwn, - struct ft_lport_acl, fc_lport_wwn); + struct ft_lport_wwn *ft_wwn = container_of(wwn, + struct ft_lport_wwn, se_wwn); - FT_CONF_DBG("del lport %s\n", - config_item_name(&wwn->wwn_group.cg_item)); + pr_debug("del wwn %s\n", ft_wwn->name); mutex_lock(&ft_lport_lock); - list_del(&lacl->list); + list_del(&ft_wwn->ft_wwn_node); mutex_unlock(&ft_lport_lock); - kfree(lacl); + kfree(ft_wwn); } static ssize_t ft_wwn_show_attr_version( @@ -474,7 +472,7 @@ static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg) { struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; - return tpg->lport_acl->name; + return tpg->lport_wwn->name; } static u16 ft_get_tag(struct se_portal_group *se_tpg) @@ -502,16 +500,6 @@ static void ft_set_default_node_attr(struct se_node_acl *se_nacl) { } -static u16 ft_get_fabric_sense_len(void) -{ - return 0; -} - -static u16 ft_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_len) -{ - return 0; -} - static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) { struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; @@ -536,13 +524,9 @@ static struct target_core_fabric_ops ft_fabric_ops = { .tpg_release_fabric_acl = ft_tpg_release_fabric_acl, .tpg_get_inst_index = ft_tpg_get_inst_index, .check_stop_free = ft_check_stop_free, - .release_cmd_to_pool = ft_release_cmd, - .release_cmd_direct = ft_release_cmd, + .release_cmd = ft_release_cmd, .shutdown_session = ft_sess_shutdown, .close_session = ft_sess_close, - .stop_session = ft_sess_stop, - .fall_back_to_erl0 = ft_sess_set_erl0, - .sess_logged_in = ft_sess_logged_in, .sess_get_index = ft_sess_get_index, .sess_get_initiator_sid = NULL, .write_pending = ft_write_pending, @@ -550,19 +534,16 @@ static struct target_core_fabric_ops ft_fabric_ops = { .set_default_node_attributes = ft_set_default_node_attr, .get_task_tag = ft_get_task_tag, .get_cmd_state = ft_get_cmd_state, - .new_cmd_failure = ft_new_cmd_failure, .queue_data_in = ft_queue_data_in, .queue_status = ft_queue_status, .queue_tm_rsp = ft_queue_tm_resp, - .get_fabric_sense_len = ft_get_fabric_sense_len, - .set_fabric_sense_len = ft_set_fabric_sense_len, - .is_state_remove = ft_is_state_remove, + .aborted_task = ft_aborted_task, /* * Setup function pointers for generic logic in * target_core_fabric_configfs.c */ - .fabric_make_wwn = &ft_add_lport, - .fabric_drop_wwn = &ft_del_lport, + .fabric_make_wwn = &ft_add_wwn, + .fabric_drop_wwn = &ft_del_wwn, .fabric_make_tpg = &ft_add_tpg, .fabric_drop_tpg = &ft_del_tpg, .fabric_post_link = NULL, @@ -573,7 +554,7 @@ static struct target_core_fabric_ops ft_fabric_ops = { .fabric_drop_nodeacl = &ft_del_acl, }; -int ft_register_configfs(void) +static int ft_register_configfs(void) { struct target_fabric_configfs *fabric; int ret; @@ -582,39 +563,33 @@ int ft_register_configfs(void) * Register the top level struct config_item_type with TCM core */ fabric = target_fabric_configfs_init(THIS_MODULE, "fc"); - if (!fabric) { - printk(KERN_INFO "%s: target_fabric_configfs_init() failed!\n", + if (IS_ERR(fabric)) { + pr_err("%s: target_fabric_configfs_init() failed!\n", __func__); - return -1; + return PTR_ERR(fabric); } fabric->tf_ops = ft_fabric_ops; - /* Allowing support for task_sg_chaining */ - fabric->tf_ops.task_sg_chaining = 1; - /* * Setup default attribute lists for various fabric->tf_cit_tmpl */ - TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = ft_wwn_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = + fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = ft_wwn_attrs; + fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL; + fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; + fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; + fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; + fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = ft_nacl_base_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; + fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; + fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; + fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; /* * register the fabric for use within TCM */ ret = target_fabric_configfs_register(fabric); if (ret < 0) { - FT_CONF_DBG("target_fabric_configfs_register() for" + pr_debug("target_fabric_configfs_register() for" " FC Target failed!\n"); - printk(KERN_INFO - "%s: target_fabric_configfs_register() failed!\n", - __func__); target_fabric_configfs_free(fabric); return -1; } @@ -626,7 +601,7 @@ int ft_register_configfs(void) return 0; } -void ft_deregister_configfs(void) +static void ft_deregister_configfs(void) { if (!ft_configfs) return; @@ -661,9 +636,7 @@ static void __exit ft_exit(void) synchronize_rcu(); } -#ifdef MODULE MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION); MODULE_LICENSE("GPL"); module_init(ft_init); module_exit(ft_exit); -#endif /* MODULE */ diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 4c3c0efbe13..97b486c3dda 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -28,8 +28,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> -#include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> #include <linux/slab.h> @@ -39,6 +37,7 @@ #include <linux/configfs.h> #include <linux/ctype.h> #include <linux/hash.h> +#include <linux/ratelimit.h> #include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -48,12 +47,8 @@ #include <scsi/fc_encode.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include <target/target_core_base.h> #include <target/configfs_macros.h> #include "tcm_fc.h" @@ -65,62 +60,65 @@ int ft_queue_data_in(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); - struct se_transport_task *task; struct fc_frame *fp = NULL; struct fc_exch *ep; struct fc_lport *lport; - struct se_mem *mem; + struct scatterlist *sg = NULL; size_t remaining; u32 f_ctl = FC_FC_EX_CTX | FC_FC_REL_OFF; - u32 mem_off; + u32 mem_off = 0; u32 fh_off = 0; u32 frame_off = 0; size_t frame_len = 0; - size_t mem_len; + size_t mem_len = 0; size_t tlen; size_t off_in_page; - struct page *page; + struct page *page = NULL; int use_sg; int error; void *page_addr; void *from; void *to = NULL; + if (cmd->aborted) + return 0; + + if (se_cmd->scsi_status == SAM_STAT_TASK_SET_FULL) + goto queue_status; + ep = fc_seq_exch(cmd->seq); lport = ep->lp; cmd->seq = lport->tt.seq_start_next(cmd->seq); - task = T_TASK(se_cmd); - BUG_ON(!task); remaining = se_cmd->data_length; /* - * Setup to use first mem list entry if any. + * Setup to use first mem list entry, unless no data. */ - if (task->t_tasks_se_num) { - mem = list_first_entry(task->t_mem_list, - struct se_mem, se_list); - mem_len = mem->se_len; - mem_off = mem->se_off; - page = mem->se_page; - } else { - mem = NULL; - mem_len = remaining; - mem_off = 0; - page = NULL; + BUG_ON(remaining && !se_cmd->t_data_sg); + if (remaining) { + sg = se_cmd->t_data_sg; + mem_len = sg->length; + mem_off = sg->offset; + page = sg_page(sg); } /* no scatter/gather in skb for odd word length due to fc_seq_send() */ use_sg = !(remaining % 4); while (remaining) { + struct fc_seq *seq = cmd->seq; + + if (!seq) { + pr_debug("%s: Command aborted, xid 0x%x\n", + __func__, ep->xid); + break; + } if (!mem_len) { - BUG_ON(!mem); - mem = list_entry(mem->se_list.next, - struct se_mem, se_list); - mem_len = min((size_t)mem->se_len, remaining); - mem_off = mem->se_off; - page = mem->se_page; + sg = sg_next(sg); + mem_len = min((size_t)sg->length, remaining); + mem_off = sg->offset; + page = sg_page(sg); } if (!frame_len) { /* @@ -148,18 +146,7 @@ int ft_queue_data_in(struct se_cmd *se_cmd) tlen = min(mem_len, frame_len); if (use_sg) { - if (!mem) { - BUG_ON(!task->t_task_buf); - page_addr = task->t_task_buf + mem_off; - /* - * In this case, offset is 'offset_in_page' of - * (t_task_buf + mem_off) instead of 'mem_off'. - */ - off_in_page = offset_in_page(page_addr); - page = virt_to_page(page_addr); - tlen = min(tlen, PAGE_SIZE - off_in_page); - } else - off_in_page = mem_off; + off_in_page = mem_off; BUG_ON(!page); get_page(page); skb_fill_page_desc(fp_skb(fp), @@ -169,20 +156,15 @@ int ft_queue_data_in(struct se_cmd *se_cmd) fp_skb(fp)->data_len += tlen; fp_skb(fp)->truesize += PAGE_SIZE << compound_order(page); - } else if (mem) { + } else { BUG_ON(!page); - from = kmap_atomic(page + (mem_off >> PAGE_SHIFT), - KM_SOFTIRQ0); + from = kmap_atomic(page + (mem_off >> PAGE_SHIFT)); page_addr = from; from += mem_off & ~PAGE_MASK; tlen = min(tlen, (size_t)(PAGE_SIZE - (mem_off & ~PAGE_MASK))); memcpy(to, from, tlen); - kunmap_atomic(page_addr, KM_SOFTIRQ0); - to += tlen; - } else { - from = task->t_task_buf + mem_off; - memcpy(to, from, tlen); + kunmap_atomic(page_addr); to += tlen; } @@ -198,20 +180,35 @@ int ft_queue_data_in(struct se_cmd *se_cmd) f_ctl |= FC_FC_END_SEQ; fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid, FC_TYPE_FCP, f_ctl, fh_off); - error = lport->tt.seq_send(lport, cmd->seq, fp); + error = lport->tt.seq_send(lport, seq, fp); if (error) { - /* XXX For now, initiator will retry */ - if (printk_ratelimit()) - printk(KERN_ERR "%s: Failed to send frame %p, " - "xid <0x%x>, remaining <0x%x>, " + pr_info_ratelimited("%s: Failed to send frame %p, " + "xid <0x%x>, remaining %zu, " "lso_max <0x%x>\n", __func__, fp, ep->xid, remaining, lport->lso_max); + /* + * Go ahead and set TASK_SET_FULL status ignoring the + * rest of the DataIN, and immediately attempt to + * send the response via ft_queue_status() in order + * to notify the initiator that it should reduce it's + * per LUN queue_depth. + */ + se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; + break; } } +queue_status: return ft_queue_status(se_cmd); } +static void ft_execute_work(struct work_struct *work) +{ + struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); + + target_execute_cmd(&cmd->se_cmd); +} + /* * Receive write data frame. */ @@ -221,83 +218,64 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) struct fc_seq *seq = cmd->seq; struct fc_exch *ep; struct fc_lport *lport; - struct se_transport_task *task; struct fc_frame_header *fh; - struct se_mem *mem; - u32 mem_off; + struct scatterlist *sg = NULL; + u32 mem_off = 0; u32 rel_off; size_t frame_len; - size_t mem_len; + size_t mem_len = 0; size_t tlen; - struct page *page; + struct page *page = NULL; void *page_addr; void *from; void *to; u32 f_ctl; void *buf; - task = T_TASK(se_cmd); - BUG_ON(!task); - fh = fc_frame_header_get(fp); if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) goto drop; - /* - * Doesn't expect even single byte of payload. Payload - * is expected to be copied directly to user buffers - * due to DDP (Large Rx offload) feature, hence - * BUG_ON if BUF is non-NULL - */ - buf = fc_frame_payload_get(fp, 1); - if (cmd->was_ddp_setup && buf) { - printk(KERN_INFO "%s: When DDP was setup, not expected to" - "receive frame with payload, Payload shall be" - "copied directly to buffer instead of coming " - "via. legacy receive queues\n", __func__); - BUG_ON(buf); - } - - /* - * If ft_cmd indicated 'ddp_setup', in that case only the last frame - * should come with 'TSI bit being set'. If 'TSI bit is not set and if - * data frame appears here, means error condition. In both the cases - * release the DDP context (ddp_put) and in error case, as well - * initiate error recovery mechanism. - */ + f_ctl = ntoh24(fh->fh_f_ctl); ep = fc_seq_exch(seq); + lport = ep->lp; if (cmd->was_ddp_setup) { BUG_ON(!ep); - lport = ep->lp; BUG_ON(!lport); - } - if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) { - f_ctl = ntoh24(fh->fh_f_ctl); /* - * If TSI bit set in f_ctl, means last write data frame is - * received successfully where payload is posted directly - * to user buffer and only the last frame's header is posted - * in legacy receive queue + * Since DDP (Large Rx offload) was setup for this request, + * payload is expected to be copied directly to user buffers. */ - if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */ - cmd->write_data_len = lport->tt.ddp_done(lport, - ep->xid); + buf = fc_frame_payload_get(fp, 1); + if (buf) + pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, " + "cmd->sg_cnt 0x%x. DDP was setup" + " hence not expected to receive frame with " + "payload, Frame will be dropped if" + "'Sequence Initiative' bit in f_ctl is" + "not set\n", __func__, ep->xid, f_ctl, + se_cmd->t_data_sg, se_cmd->t_data_nents); + /* + * Invalidate HW DDP context if it was setup for respective + * command. Invalidation of HW DDP context is requited in both + * situation (success and error). + */ + ft_invl_hw_context(cmd); + + /* + * If "Sequence Initiative (TSI)" bit set in f_ctl, means last + * write data frame is received successfully where payload is + * posted directly to user buffer and only the last frame's + * header is posted in receive queue. + * + * If "Sequence Initiative (TSI)" bit is not set, means error + * condition w.r.t. DDP, hence drop the packet and let explict + * ABORTS from other end of exchange timer trigger the recovery. + */ + if (f_ctl & FC_FC_SEQ_INIT) goto last_frame; - } else { - /* - * Updating the write_data_len may be meaningless at - * this point, but just in case if required in future - * for debugging or any other purpose - */ - printk(KERN_ERR "%s: Received frame with TSI bit not" - " being SET, dropping the frame, " - "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n", - __func__, cmd->sg, cmd->sg_cnt); - cmd->write_data_len = lport->tt.ddp_done(lport, - ep->xid); - lport->tt.seq_exch_abort(cmd->seq, 0); + else goto drop; - } } rel_off = ntohl(fh->fh_parm_offset); @@ -312,29 +290,22 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) frame_len = se_cmd->data_length - rel_off; /* - * Setup to use first mem list entry if any. + * Setup to use first mem list entry, unless no data. */ - if (task->t_tasks_se_num) { - mem = list_first_entry(task->t_mem_list, - struct se_mem, se_list); - mem_len = mem->se_len; - mem_off = mem->se_off; - page = mem->se_page; - } else { - mem = NULL; - page = NULL; - mem_off = 0; - mem_len = frame_len; + BUG_ON(frame_len && !se_cmd->t_data_sg); + if (frame_len) { + sg = se_cmd->t_data_sg; + mem_len = sg->length; + mem_off = sg->offset; + page = sg_page(sg); } while (frame_len) { if (!mem_len) { - BUG_ON(!mem); - mem = list_entry(mem->se_list.next, - struct se_mem, se_list); - mem_len = mem->se_len; - mem_off = mem->se_off; - page = mem->se_page; + sg = sg_next(sg); + mem_len = sg->length; + mem_off = sg->offset; + page = sg_page(sg); } if (rel_off >= mem_len) { rel_off -= mem_len; @@ -347,19 +318,14 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) tlen = min(mem_len, frame_len); - if (mem) { - to = kmap_atomic(page + (mem_off >> PAGE_SHIFT), - KM_SOFTIRQ0); - page_addr = to; - to += mem_off & ~PAGE_MASK; - tlen = min(tlen, (size_t)(PAGE_SIZE - - (mem_off & ~PAGE_MASK))); - memcpy(to, from, tlen); - kunmap_atomic(page_addr, KM_SOFTIRQ0); - } else { - to = task->t_task_buf + mem_off; - memcpy(to, from, tlen); - } + to = kmap_atomic(page + (mem_off >> PAGE_SHIFT)); + page_addr = to; + to += mem_off & ~PAGE_MASK; + tlen = min(tlen, (size_t)(PAGE_SIZE - + (mem_off & ~PAGE_MASK))); + memcpy(to, from, tlen); + kunmap_atomic(page_addr); + from += tlen; frame_len -= tlen; mem_off += tlen; @@ -367,8 +333,47 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) cmd->write_data_len += tlen; } last_frame: - if (cmd->write_data_len == se_cmd->data_length) - transport_generic_handle_data(se_cmd); + if (cmd->write_data_len == se_cmd->data_length) { + INIT_WORK(&cmd->work, ft_execute_work); + queue_work(cmd->sess->tport->tpg->workqueue, &cmd->work); + } drop: fc_frame_free(fp); } + +/* + * Handle and cleanup any HW specific resources if + * received ABORTS, errors, timeouts. + */ +void ft_invl_hw_context(struct ft_cmd *cmd) +{ + struct fc_seq *seq; + struct fc_exch *ep = NULL; + struct fc_lport *lport = NULL; + + BUG_ON(!cmd); + seq = cmd->seq; + + /* Cleanup the DDP context in HW if DDP was setup */ + if (cmd->was_ddp_setup && seq) { + ep = fc_seq_exch(seq); + if (ep) { + lport = ep->lp; + if (lport && (ep->xid <= lport->lro_xid)) + /* + * "ddp_done" trigger invalidation of HW + * specific DDP context + */ + cmd->write_data_len = lport->tt.ddp_done(lport, + ep->xid); + + /* + * Resetting same variable to indicate HW's + * DDP context has been invalidated to avoid + * re_invalidation of same context (context is + * identified using ep->xid) + */ + cmd->was_ddp_setup = 0; + } + } +} diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index a3bd57f2ea3..21ce50880c7 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -19,8 +19,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> -#include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/init.h> #include <linux/slab.h> @@ -41,15 +39,10 @@ #include <scsi/libfc.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include <target/target_core_base.h> #include <target/configfs_macros.h> -#include <scsi/libfc.h> #include "tcm_fc.h" static void ft_sess_delete_all(struct ft_tport *); @@ -58,13 +51,14 @@ static void ft_sess_delete_all(struct ft_tport *); * Lookup or allocate target local port. * Caller holds ft_lport_lock. */ -static struct ft_tport *ft_tport_create(struct fc_lport *lport) +static struct ft_tport *ft_tport_get(struct fc_lport *lport) { struct ft_tpg *tpg; struct ft_tport *tport; int i; - tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); + tport = rcu_dereference_protected(lport->prov[FC_TYPE_FCP], + lockdep_is_held(&ft_lport_lock)); if (tport && tport->tpg) return tport; @@ -74,6 +68,7 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport) if (tport) { tport->tpg = tpg; + tpg->tport = tport; return tport; } @@ -92,16 +87,6 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport) } /* - * Free tport via RCU. - */ -static void ft_tport_rcu_free(struct rcu_head *rcu) -{ - struct ft_tport *tport = container_of(rcu, struct ft_tport, rcu); - - kfree(tport); -} - -/* * Delete a target local port. * Caller holds ft_lport_lock. */ @@ -120,7 +105,7 @@ static void ft_tport_delete(struct ft_tport *tport) tpg->tport = NULL; tport->tpg = NULL; } - call_rcu(&tport->rcu, ft_tport_rcu_free); + kfree_rcu(tport, rcu); } /* @@ -130,7 +115,7 @@ static void ft_tport_delete(struct ft_tport *tport) void ft_lport_add(struct fc_lport *lport, void *arg) { mutex_lock(&ft_lport_lock); - ft_tport_create(lport); + ft_tport_get(lport); mutex_unlock(&ft_lport_lock); } @@ -185,7 +170,6 @@ static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id) { struct ft_tport *tport; struct hlist_head *head; - struct hlist_node *pos; struct ft_sess *sess; rcu_read_lock(); @@ -194,17 +178,17 @@ static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id) goto out; head = &tport->hash[ft_sess_hash(port_id)]; - hlist_for_each_entry_rcu(sess, pos, head, hash) { + hlist_for_each_entry_rcu(sess, head, hash) { if (sess->port_id == port_id) { kref_get(&sess->kref); rcu_read_unlock(); - FT_SESS_DBG("port_id %x found %p\n", port_id, sess); + pr_debug("port_id %x found %p\n", port_id, sess); return sess; } } out: rcu_read_unlock(); - FT_SESS_DBG("port_id %x not found\n", port_id); + pr_debug("port_id %x not found\n", port_id); return NULL; } @@ -217,10 +201,9 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, { struct ft_sess *sess; struct hlist_head *head; - struct hlist_node *pos; head = &tport->hash[ft_sess_hash(port_id)]; - hlist_for_each_entry_rcu(sess, pos, head, hash) + hlist_for_each_entry_rcu(sess, head, hash) if (sess->port_id == port_id) return sess; @@ -228,8 +211,10 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, if (!sess) return NULL; - sess->se_sess = transport_init_session(); - if (!sess->se_sess) { + sess->se_sess = transport_init_session_tags(TCM_FC_DEFAULT_TAGS, + sizeof(struct ft_cmd), + TARGET_PROT_NORMAL); + if (IS_ERR(sess->se_sess)) { kfree(sess); return NULL; } @@ -240,7 +225,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, hlist_add_head_rcu(&sess->hash, head); tport->sess_count++; - FT_SESS_DBG("port_id %x sess %p\n", port_id, sess); + pr_debug("port_id %x sess %p\n", port_id, sess); transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl, sess->se_sess, sess); @@ -269,11 +254,10 @@ static void ft_sess_unhash(struct ft_sess *sess) static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) { struct hlist_head *head; - struct hlist_node *pos; struct ft_sess *sess; head = &tport->hash[ft_sess_hash(port_id)]; - hlist_for_each_entry_rcu(sess, pos, head, hash) { + hlist_for_each_entry_rcu(sess, head, hash) { if (sess->port_id == port_id) { ft_sess_unhash(sess); return sess; @@ -289,12 +273,11 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) static void ft_sess_delete_all(struct ft_tport *tport) { struct hlist_head *head; - struct hlist_node *pos; struct ft_sess *sess; for (head = tport->hash; head < &tport->hash[FT_SESS_HASH_SIZE]; head++) { - hlist_for_each_entry_rcu(sess, pos, head, hash) { + hlist_for_each_entry_rcu(sess, head, hash) { ft_sess_unhash(sess); transport_deregister_session_configfs(sess->se_sess); ft_sess_put(sess); /* release from table */ @@ -314,7 +297,7 @@ int ft_sess_shutdown(struct se_session *se_sess) { struct ft_sess *sess = se_sess->fabric_sess_ptr; - FT_SESS_DBG("port_id %x\n", sess->port_id); + pr_debug("port_id %x\n", sess->port_id); return 1; } @@ -325,17 +308,15 @@ int ft_sess_shutdown(struct se_session *se_sess) void ft_sess_close(struct se_session *se_sess) { struct ft_sess *sess = se_sess->fabric_sess_ptr; - struct fc_lport *lport; u32 port_id; mutex_lock(&ft_lport_lock); - lport = sess->tport->lport; port_id = sess->port_id; if (port_id == -1) { - mutex_lock(&ft_lport_lock); + mutex_unlock(&ft_lport_lock); return; } - FT_SESS_DBG("port_id %x\n", port_id); + pr_debug("port_id %x\n", port_id); ft_sess_unhash(sess); mutex_unlock(&ft_lport_lock); transport_deregister_session_configfs(se_sess); @@ -344,20 +325,6 @@ void ft_sess_close(struct se_session *se_sess) synchronize_rcu(); /* let transport deregister happen */ } -void ft_sess_stop(struct se_session *se_sess, int sess_sleep, int conn_sleep) -{ - struct ft_sess *sess = se_sess->fabric_sess_ptr; - - FT_SESS_DBG("port_id %x\n", sess->port_id); -} - -int ft_sess_logged_in(struct se_session *se_sess) -{ - struct ft_sess *sess = se_sess->fabric_sess_ptr; - - return sess->port_id != -1; -} - u32 ft_sess_get_index(struct se_session *se_sess) { struct ft_sess *sess = se_sess->fabric_sess_ptr; @@ -373,11 +340,6 @@ u32 ft_sess_get_port_name(struct se_session *se_sess, return ft_format_wwn(buf, len, sess->port_name); } -void ft_sess_set_erl0(struct se_session *se_sess) -{ - /* XXX TBD called when out of memory */ -} - /* * libfc ops involving sessions. */ @@ -390,13 +352,13 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, struct ft_node_acl *acl; u32 fcp_parm; - tport = ft_tport_create(rdata->local_port); + tport = ft_tport_get(rdata->local_port); if (!tport) - return 0; /* not a target for this local port */ + goto not_target; /* not a target for this local port */ acl = ft_acl_get(tport->tpg, rdata); if (!acl) - return 0; + goto not_target; /* no target for this remote */ if (!rspp) goto fill; @@ -433,12 +395,18 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, /* * OR in our service parameters with other provider (initiator), if any. - * TBD XXX - indicate RETRY capability? */ fill: fcp_parm = ntohl(spp->spp_params); + fcp_parm &= ~FCP_SPPF_RETRY; spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); return FC_SPP_RESP_ACK; + +not_target: + fcp_parm = ntohl(spp->spp_params); + fcp_parm &= ~FCP_SPPF_TARG_FCN; + spp->spp_params = htonl(fcp_parm); + return 0; } /** @@ -458,24 +426,17 @@ static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len, mutex_lock(&ft_lport_lock); ret = ft_prli_locked(rdata, spp_len, rspp, spp); mutex_unlock(&ft_lport_lock); - FT_SESS_DBG("port_id %x flags %x ret %x\n", + pr_debug("port_id %x flags %x ret %x\n", rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret); return ret; } -static void ft_sess_rcu_free(struct rcu_head *rcu) -{ - struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu); - - transport_deregister_session(sess->se_sess); - kfree(sess); -} - static void ft_sess_free(struct kref *kref) { struct ft_sess *sess = container_of(kref, struct ft_sess, kref); - call_rcu(&sess->rcu, ft_sess_rcu_free); + transport_deregister_session(sess->se_sess); + kfree_rcu(sess, rcu); } void ft_sess_put(struct ft_sess *sess) @@ -492,7 +453,9 @@ static void ft_prlo(struct fc_rport_priv *rdata) struct ft_tport *tport; mutex_lock(&ft_lport_lock); - tport = rcu_dereference(rdata->local_port->prov[FC_TYPE_FCP]); + tport = rcu_dereference_protected(rdata->local_port->prov[FC_TYPE_FCP], + lockdep_is_held(&ft_lport_lock)); + if (!tport) { mutex_unlock(&ft_lport_lock); return; @@ -518,11 +481,11 @@ static void ft_recv(struct fc_lport *lport, struct fc_frame *fp) struct ft_sess *sess; u32 sid = fc_frame_sid(fp); - FT_SESS_DBG("sid %x\n", sid); + pr_debug("sid %x\n", sid); sess = ft_sess_get(lport, sid); if (!sess) { - FT_SESS_DBG("sid %x sess lookup failed\n", sid); + pr_debug("sid %x sess lookup failed\n", sid); /* TBD XXX - if FCP_CMND, send PRLO */ fc_frame_free(fp); return; |
