From 6c10db72c94818573552fd71c89540da325efdfb Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Fri, 26 Jun 2009 19:30:06 -0700 Subject: [SCSI] scsi_dh: Reference count scsi_dh_attach Problem reported: http://marc.info/?l=dm-devel&m=124585978305866&w=2 scsi_dh does not do a refernce count for attach/detach, and this affects the way it is supposed to work with multipath when a device is not in the dev_list of the hardware handler. This patch adds a reference count that counts each attach. Signed-off-by: Chandra Seetharaman Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- include/scsi/scsi_device.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 3f566af3f101..1f3a4c8044c0 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -191,6 +191,8 @@ struct scsi_device_handler { struct scsi_dh_data { struct scsi_device_handler *scsi_dh; + struct scsi_device *sdev; + struct kref kref; char buf[0]; }; -- cgit v1.2.3 From beb29a6d421f6dbd41d68d0621c1b28ad1d4a9f4 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:06 -0700 Subject: [SCSI] libfc: remove extra semicolons from debug macros This is unlikely to cause any problems, but the libfc debug macros introduce extra undesirable semicolons. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- include/scsi/libfc.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index b92584a8843a..ef04a2c52b8c 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -51,22 +51,22 @@ do { \ do { \ CMD; \ } while (0); \ -} while (0); +} while (0) #define FC_LIBFC_DBG(fmt, args...) \ FC_CHECK_LOGGING(FC_LIBFC_LOGGING, \ - printk(KERN_INFO "libfc: " fmt, ##args);) + printk(KERN_INFO "libfc: " fmt, ##args)) #define FC_LPORT_DBG(lport, fmt, args...) \ FC_CHECK_LOGGING(FC_LPORT_LOGGING, \ printk(KERN_INFO "lport: %6x: " fmt, \ - fc_host_port_id(lport->host), ##args);) + fc_host_port_id(lport->host), ##args)) #define FC_DISC_DBG(disc, fmt, args...) \ FC_CHECK_LOGGING(FC_DISC_LOGGING, \ printk(KERN_INFO "disc: %6x: " fmt, \ fc_host_port_id(disc->lport->host), \ - ##args);) + ##args)) #define FC_RPORT_DBG(rport, fmt, args...) \ do { \ @@ -75,31 +75,31 @@ do { \ FC_CHECK_LOGGING(FC_RPORT_LOGGING, \ printk(KERN_INFO "rport: %6x: %6x: " fmt, \ fc_host_port_id(lport->host), \ - rport->port_id, ##args);) \ -} while (0); + rport->port_id, ##args)); \ +} while (0) #define FC_FCP_DBG(pkt, fmt, args...) \ FC_CHECK_LOGGING(FC_FCP_LOGGING, \ printk(KERN_INFO "fcp: %6x: %6x: " fmt, \ fc_host_port_id(pkt->lp->host), \ - pkt->rport->port_id, ##args);) + pkt->rport->port_id, ##args)) #define FC_EM_DBG(em, fmt, args...) \ FC_CHECK_LOGGING(FC_EM_LOGGING, \ printk(KERN_INFO "em: %6x: " fmt, \ fc_host_port_id(em->lp->host), \ - ##args);) + ##args)) #define FC_EXCH_DBG(exch, fmt, args...) \ FC_CHECK_LOGGING(FC_EXCH_LOGGING, \ printk(KERN_INFO "exch: %6x: %4x: " fmt, \ fc_host_port_id(exch->lp->host), \ - exch->xid, ##args);) + exch->xid, ##args)) #define FC_SCSI_DBG(lport, fmt, args...) \ FC_CHECK_LOGGING(FC_SCSI_LOGGING, \ printk(KERN_INFO "scsi: %6x: " fmt, \ - fc_host_port_id(lport->host), ##args);) + fc_host_port_id(lport->host), ##args)) /* * libfc error codes -- cgit v1.2.3 From 7f74549ff630ad444b0b6bbcabf426f781910906 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:12 -0700 Subject: [SCSI] libfc: change debug messages to give host number. libfc debug messages currently show 'lport: :' wher is the hex assigned port-id. When the lport is logged off, that will be zero, so its hard to distinguish which instance is involved. The FC-ID can change if the port is re-patched or changes VSANs. Two lports may even have the same FC-ID if connected to isolated SANs. Change the debug messages to print the SCSI host number "hostN:", which will not change for the life of the lport. Still show the FC_ID on lport messages. Also, add a macro to FC_RPORT_ID_DBG for rport debugging where there's no rdata structure involved. It takes the lport and port_id as parameters. Use this in fc_rport_recv_plogi_req() and fc_rport_recv_logo_req(). Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- include/scsi/libfc.h | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index ef04a2c52b8c..efdb6ba310e5 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -59,47 +59,51 @@ do { \ #define FC_LPORT_DBG(lport, fmt, args...) \ FC_CHECK_LOGGING(FC_LPORT_LOGGING, \ - printk(KERN_INFO "lport: %6x: " fmt, \ - fc_host_port_id(lport->host), ##args)) + printk(KERN_INFO "host%u: lport %6x: " fmt, \ + (lport)->host->host_no, \ + fc_host_port_id((lport)->host), ##args)) #define FC_DISC_DBG(disc, fmt, args...) \ FC_CHECK_LOGGING(FC_DISC_LOGGING, \ - printk(KERN_INFO "disc: %6x: " fmt, \ - fc_host_port_id(disc->lport->host), \ + printk(KERN_INFO "host%u: disc: " fmt, \ + (disc)->lport->host->host_no, \ ##args)) +#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \ + FC_CHECK_LOGGING(FC_RPORT_LOGGING, \ + printk(KERN_INFO "host%u: rport %6x: " fmt, \ + (lport)->host->host_no, \ + (port_id), ##args)) + #define FC_RPORT_DBG(rport, fmt, args...) \ do { \ struct fc_rport_libfc_priv *rdata = rport->dd_data; \ struct fc_lport *lport = rdata->local_port; \ - FC_CHECK_LOGGING(FC_RPORT_LOGGING, \ - printk(KERN_INFO "rport: %6x: %6x: " fmt, \ - fc_host_port_id(lport->host), \ - rport->port_id, ##args)); \ + FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ } while (0) #define FC_FCP_DBG(pkt, fmt, args...) \ FC_CHECK_LOGGING(FC_FCP_LOGGING, \ - printk(KERN_INFO "fcp: %6x: %6x: " fmt, \ - fc_host_port_id(pkt->lp->host), \ + printk(KERN_INFO "host%u: fcp: %6x: " fmt, \ + (pkt)->lp->host->host_no, \ pkt->rport->port_id, ##args)) #define FC_EM_DBG(em, fmt, args...) \ FC_CHECK_LOGGING(FC_EM_LOGGING, \ - printk(KERN_INFO "em: %6x: " fmt, \ - fc_host_port_id(em->lp->host), \ + printk(KERN_INFO "host%u: em: " fmt, \ + (em)->lp->host->host_no, \ ##args)) #define FC_EXCH_DBG(exch, fmt, args...) \ FC_CHECK_LOGGING(FC_EXCH_LOGGING, \ - printk(KERN_INFO "exch: %6x: %4x: " fmt, \ - fc_host_port_id(exch->lp->host), \ + printk(KERN_INFO "host%u: xid %4x: " fmt, \ + (exch)->lp->host->host_no, \ exch->xid, ##args)) #define FC_SCSI_DBG(lport, fmt, args...) \ FC_CHECK_LOGGING(FC_SCSI_LOGGING, \ - printk(KERN_INFO "scsi: %6x: " fmt, \ - fc_host_port_id(lport->host), ##args)) + printk(KERN_INFO "host%u: scsi: " fmt, \ + (lport)->host->host_no, ##args)) /* * libfc error codes -- cgit v1.2.3 From b1d9fd5574763abe5c763e32e3547a4adee9bd88 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:22 -0700 Subject: [SCSI] libfc: rename lport NONE state to DISABLED The state NONE was meant to be invalid, but has been used as the initial state. Rename it to be DISABLED, as more descriptive. Further patches will make it the like the RESET state, except it won't transition to FLOGI until fc_lport_fabric_login() is called. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 2 +- drivers/scsi/libfc/fc_lport.c | 12 ++++++------ include/scsi/libfc.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 145ab9ba55ea..e6d82d780acd 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1875,7 +1875,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, u32 f_ctl; /* lport lock ? */ - if (!lp || !mp || (lp->state == LPORT_ST_NONE)) { + if (!lp || !mp || lp->state == LPORT_ST_DISABLED) { FC_LPORT_DBG(lp, "Receiving frames for an lport that " "has not been initialized correctly\n"); fc_frame_free(fp); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 745fa5555d6a..3b28190ca2eb 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -113,7 +113,7 @@ static void fc_lport_enter_ready(struct fc_lport *); static void fc_lport_enter_logo(struct fc_lport *); static const char *fc_lport_state_names[] = { - [LPORT_ST_NONE] = "none", + [LPORT_ST_DISABLED] = "disabled", [LPORT_ST_FLOGI] = "FLOGI", [LPORT_ST_DNS] = "dNS", [LPORT_ST_RPN_ID] = "RPN_ID", @@ -550,7 +550,7 @@ int fc_fabric_login(struct fc_lport *lport) int rc = -1; mutex_lock(&lport->lp_mutex); - if (lport->state == LPORT_ST_NONE) { + if (lport->state == LPORT_ST_DISABLED) { fc_lport_enter_reset(lport); rc = 0; } @@ -637,7 +637,7 @@ EXPORT_SYMBOL(fc_fabric_logoff); int fc_lport_destroy(struct fc_lport *lport) { mutex_lock(&lport->lp_mutex); - lport->state = LPORT_ST_NONE; + lport->state = LPORT_ST_DISABLED; lport->link_up = 0; lport->tt.frame_send = fc_frame_drop; mutex_unlock(&lport->lp_mutex); @@ -992,7 +992,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) schedule_delayed_work(&lport->retry_work, delay); } else { switch (lport->state) { - case LPORT_ST_NONE: + case LPORT_ST_DISABLED: case LPORT_ST_READY: case LPORT_ST_RESET: case LPORT_ST_RPN_ID: @@ -1316,7 +1316,7 @@ static void fc_lport_timeout(struct work_struct *work) mutex_lock(&lport->lp_mutex); switch (lport->state) { - case LPORT_ST_NONE: + case LPORT_ST_DISABLED: case LPORT_ST_READY: case LPORT_ST_RESET: WARN_ON(1); @@ -1550,7 +1550,7 @@ int fc_lport_config(struct fc_lport *lport) INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); mutex_init(&lport->lp_mutex); - fc_lport_state_enter(lport, LPORT_ST_NONE); + fc_lport_state_enter(lport, LPORT_ST_DISABLED); fc_lport_add_fc4_type(lport, FC_TYPE_FCP); fc_lport_add_fc4_type(lport, FC_TYPE_CT); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index efdb6ba310e5..b5c9b285b462 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -129,7 +129,7 @@ do { \ * FC HBA status */ enum fc_lport_state { - LPORT_ST_NONE = 0, + LPORT_ST_DISABLED = 0, LPORT_ST_FLOGI, LPORT_ST_DNS, LPORT_ST_RPN_ID, -- cgit v1.2.3 From 141940548c6919c22bf0573c68fd59d961e22475 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:43 -0700 Subject: [SCSI] libfc: rename rport state "NONE" to "DELETE". State RPORT_ST_NONE was intented to be an invalid state (0), never used. This was a misguided attempt to be sure it was always initialized. Having an extra state meaning nothing requires switch statements to have a case covering that state. State NONE has been used instead to mean the remote port is being deleted. Changing the name to RPORT_ST_DELETE. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 28 ++++++++++++++-------------- include/scsi/libfc.h | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 7162385f52eb..bf7364fc16cb 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -77,13 +77,13 @@ static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *); static void fc_rport_work(struct work_struct *); static const char *fc_rport_state_names[] = { - [RPORT_ST_NONE] = "None", [RPORT_ST_INIT] = "Init", [RPORT_ST_PLOGI] = "PLOGI", [RPORT_ST_PRLI] = "PRLI", [RPORT_ST_RTV] = "RTV", [RPORT_ST_READY] = "Ready", [RPORT_ST_LOGO] = "LOGO", + [RPORT_ST_DELETE] = "Delete", }; static void fc_rport_rogue_destroy(struct device *dev) @@ -326,8 +326,8 @@ int fc_rport_logoff(struct fc_rport *rport) FC_RPORT_DBG(rport, "Remove port\n"); - if (rdata->rp_state == RPORT_ST_NONE) { - FC_RPORT_DBG(rport, "Port in NONE state, not removing\n"); + if (rdata->rp_state == RPORT_ST_DELETE) { + FC_RPORT_DBG(rport, "Port in Delete state, not removing\n"); mutex_unlock(&rdata->rp_mutex); goto out; } @@ -335,10 +335,10 @@ int fc_rport_logoff(struct fc_rport *rport) fc_rport_enter_logo(rport); /* - * Change the state to NONE so that we discard + * Change the state to Delete so that we discard * the response. */ - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); mutex_unlock(&rdata->rp_mutex); @@ -405,7 +405,7 @@ static void fc_rport_timeout(struct work_struct *work) break; case RPORT_ST_READY: case RPORT_ST_INIT: - case RPORT_ST_NONE: + case RPORT_ST_DELETE: break; } @@ -433,14 +433,14 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) case RPORT_ST_PRLI: case RPORT_ST_LOGO: rdata->event = RPORT_EV_FAILED; - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); break; case RPORT_ST_RTV: fc_rport_enter_ready(rport); break; - case RPORT_ST_NONE: + case RPORT_ST_DELETE: case RPORT_ST_READY: case RPORT_ST_INIT: break; @@ -652,7 +652,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, } else { FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n"); rdata->event = RPORT_EV_FAILED; - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); } @@ -703,7 +703,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, } else { FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n"); rdata->event = RPORT_EV_LOGO; - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); } @@ -1012,7 +1012,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, "- ignored for now\n", rdata->rp_state); /* XXX TBD - should reset */ break; - case RPORT_ST_NONE: + case RPORT_ST_DELETE: default: FC_RPORT_DBG(rport, "Received PLOGI in unexpected " "state %d\n", rdata->rp_state); @@ -1238,7 +1238,7 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, FC_RPORT_DBG(rport, "Received PRLO request while in state %s\n", fc_rport_state(rport)); - if (rdata->rp_state == RPORT_ST_NONE) { + if (rdata->rp_state == RPORT_ST_DELETE) { fc_frame_free(fp); return; } @@ -1271,13 +1271,13 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, FC_RPORT_DBG(rport, "Received LOGO request while in state %s\n", fc_rport_state(rport)); - if (rdata->rp_state == RPORT_ST_NONE) { + if (rdata->rp_state == RPORT_ST_DELETE) { fc_frame_free(fp); return; } rdata->event = RPORT_EV_LOGO; - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index b5c9b285b462..04db7a9e631b 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -147,13 +147,13 @@ enum fc_disc_event { }; enum fc_rport_state { - RPORT_ST_NONE = 0, RPORT_ST_INIT, /* initialized */ RPORT_ST_PLOGI, /* waiting for PLOGI completion */ RPORT_ST_PRLI, /* waiting for PRLI completion */ RPORT_ST_RTV, /* waiting for RTV completion */ RPORT_ST_READY, /* ready for use */ RPORT_ST_LOGO, /* port logout sent */ + RPORT_ST_DELETE, /* port being deleted */ }; enum fc_rport_trans_state { -- cgit v1.2.3 From 96316099ac3cb259eac2d6891f3c75b38b29d26e Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Wed, 29 Jul 2009 17:05:00 -0700 Subject: [SCSI] fcoe, libfc: adds exchange manager(EM) anchor list per lport and related APIs Adds EM list using a anchor struct fc_exch_mgr_anchor, anchor is used to allow same EM instance sharing across more than one lport on a eth device, this implementation is per discussed design posted at http://www.open-fcoe.org/pipermail/devel/2009-June/002566.html. The shared EM is required for multiple lports on eth device when using multiple VLANs or NPIV. Adds fc_exch_mgr_add API to add a EM to the lport and fc_exch_mgr_del API to delete previously added EM. Also adds function fc_exch_mgr_destroy() to destroy allocated EM. The kref is added to the EM to keep track of EM usage count, the EM is destroyed when no longer in use upon kref reaching to zero. The caller can specify match function to fc_exch_mgr_add, this will be used in determining exchange allocation from its EM or not. Moved calling of fcoe_em_config below fcoe_libfc_config calling, so that list head lp->ema_list is initialized before configuring EM. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 14 ++++++------- drivers/scsi/libfc/fc_exch.c | 48 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libfc/fc_lport.c | 1 + include/scsi/libfc.h | 24 ++++++++++++++++++++++ 4 files changed, 80 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 14a4017a1535..719a99d4a438 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -603,18 +603,18 @@ static int fcoe_if_create(struct net_device *netdev) goto out_netdev_cleanup; } - /* lport exch manager allocation */ - rc = fcoe_em_config(lp); + /* Initialize the library */ + rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ); if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the " + FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " "interface\n"); - goto out_netdev_cleanup; + goto out_lp_destroy; } - /* Initialize the library */ - rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ); + /* lport exch manager allocation */ + rc = fcoe_em_config(lp); if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " + FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the " "interface\n"); goto out_lp_destroy; } diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index cab54996375c..f1fa2b196e98 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -55,6 +55,7 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ */ struct fc_exch_mgr { enum fc_class class; /* default class for sequences */ + struct kref kref; /* exchange mgr reference count */ spinlock_t em_lock; /* exchange manager lock, must be taken before ex_lock */ u16 last_xid; /* last allocated exchange ID */ @@ -84,6 +85,12 @@ struct fc_exch_mgr { }; #define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) +struct fc_exch_mgr_anchor { + struct list_head ema_list; + struct fc_exch_mgr *mp; + bool (*match)(struct fc_frame *); +}; + static void fc_exch_rrq(struct fc_exch *); static void fc_seq_ls_acc(struct fc_seq *); static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, @@ -1729,6 +1736,47 @@ reject: fc_frame_free(fp); } +struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport, + struct fc_exch_mgr *mp, + bool (*match)(struct fc_frame *)) +{ + struct fc_exch_mgr_anchor *ema; + + ema = kmalloc(sizeof(*ema), GFP_ATOMIC); + if (!ema) + return ema; + + ema->mp = mp; + ema->match = match; + /* add EM anchor to EM anchors list */ + list_add_tail(&ema->ema_list, &lport->ema_list); + kref_get(&mp->kref); + return ema; +} +EXPORT_SYMBOL(fc_exch_mgr_add); + +static void fc_exch_mgr_destroy(struct kref *kref) +{ + struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref); + + /* + * The total exch count must be zero + * before freeing exchange manager. + */ + WARN_ON(mp->total_exches != 0); + mempool_destroy(mp->ep_pool); + kfree(mp); +} + +void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema) +{ + /* remove EM anchor from EM anchors list */ + list_del(&ema->ema_list); + kref_put(&ema->mp->kref, fc_exch_mgr_destroy); + kfree(ema); +} +EXPORT_SYMBOL(fc_exch_mgr_del); + struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, enum fc_class class, u16 min_xid, u16 max_xid) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index a430335ebf59..ca8ea264b684 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1618,6 +1618,7 @@ int fc_lport_init(struct fc_lport *lport) if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT) fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT; + INIT_LIST_HEAD(&lport->ema_list); return 0; } EXPORT_SYMBOL(fc_lport_init); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 04db7a9e631b..b381b1ca9aec 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -348,6 +348,7 @@ static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp) */ struct fc_exch_mgr; +struct fc_exch_mgr_anchor; /* * Sequence. @@ -709,6 +710,7 @@ struct fc_lport { /* Associations */ struct Scsi_Host *host; struct fc_exch_mgr *emp; + struct list_head ema_list; struct fc_rport *dns_rp; struct fc_rport *ptp_rp; void *scsi_priv; @@ -963,6 +965,28 @@ int fc_elsct_init(struct fc_lport *lp); */ int fc_exch_init(struct fc_lport *lp); +/* + * Adds Exchange Manager (EM) mp to lport. + * + * Adds specified mp to lport using struct fc_exch_mgr_anchor, + * the struct fc_exch_mgr_anchor allows same EM sharing by + * more than one lport with their specified match function, + * the match function is used in allocating exchange from + * added mp. + */ +struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport, + struct fc_exch_mgr *mp, + bool (*match)(struct fc_frame *)); + +/* + * Deletes Exchange Manager (EM) from lport by removing + * its anchor ema from lport. + * + * If removed anchor ema was the last user of its associated EM + * then also destroys associated EM. + */ +void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema); + /* * Allocates an Exchange Manager (EM). * -- cgit v1.2.3 From d459b7ea1b4c7aa3dacfeee174d02b2f7a95850d Mon Sep 17 00:00:00 2001 From: Robert Love Date: Wed, 29 Jul 2009 17:05:05 -0700 Subject: [SCSI] libfc: Remove the FC_EM_DBG macro Currently there is a 1:1 relationship between the lport and exchange manager. This macro takes an EM as an argument and determines the lport from it. However, later patches will use an EM list per lport, so we will no longer have this 1:1 relationship- this macro must change. The FC_EM_DBG macro is rarely used. There are four callers, two can use FC_LPORT_DBG instead and two can be removed since they're not necessary. This patch makes those changes and removes the macro. Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 13 ++++++------- include/scsi/libfc.h | 6 ------ 2 files changed, 6 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index f1fa2b196e98..3ad7f88e7ae3 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1129,7 +1129,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, lp->tt.lport_recv(lp, sp, fp); fc_exch_release(ep); /* release from lookup */ } else { - FC_EM_DBG(mp, "exch/seq lookup failed: reject %x\n", reject); + FC_LPORT_DBG(lp, "exch/seq lookup failed: reject %x\n", reject); fc_frame_free(fp); } } @@ -1235,13 +1235,12 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) struct fc_seq *sp; sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ - if (!sp) { + + if (!sp) atomic_inc(&mp->stats.xid_not_found); - FC_EM_DBG(mp, "seq lookup failed\n"); - } else { + else atomic_inc(&mp->stats.non_bls_resp); - FC_EM_DBG(mp, "non-BLS response to sequence"); - } + fc_frame_free(fp); } @@ -1950,7 +1949,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, fc_exch_recv_req(lp, mp, fp); break; default: - FC_EM_DBG(mp, "dropping invalid frame (eof %x)", fr_eof(fp)); + FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp)); fc_frame_free(fp); break; } diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index b381b1ca9aec..f1bde91f98a2 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -88,12 +88,6 @@ do { \ (pkt)->lp->host->host_no, \ pkt->rport->port_id, ##args)) -#define FC_EM_DBG(em, fmt, args...) \ - FC_CHECK_LOGGING(FC_EM_LOGGING, \ - printk(KERN_INFO "host%u: em: " fmt, \ - (em)->lp->host->host_no, \ - ##args)) - #define FC_EXCH_DBG(exch, fmt, args...) \ FC_CHECK_LOGGING(FC_EXCH_LOGGING, \ printk(KERN_INFO "host%u: xid %4x: " fmt, \ -- cgit v1.2.3 From 52ff878c912215210f53c0a080552dd6ba3055a2 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Wed, 29 Jul 2009 17:05:10 -0700 Subject: [SCSI] fcoe, fnic, libfc: modifies current code paths to use EM anchor list Modifies current code to use EM anchor list in EM allocation, EM free, EM reset, exch allocation and exch lookup code paths. 1. Modifies fc_exch_mgr_alloc to accept EM match function and then have allocated EM added to the lport using fc_exch_mgr_add API while also updating EM kref for newly added EM. 2. Updates fc_exch_mgr_free API to accept only lport pointer instead EM and then have this API free all EMs of the lport from EM anchor list. 3. Removes single lport pointer link from the EM, which was used in associating lport pointer in newly allocated exchange. Instead have lport pointer passed along new exchange allocation call path and then store passed lport pointer in newly allocated exchange, this will allow a single EM instance to be used across more than one lport and used in EM reset to reset only lport specific exchanges. 4. Modifies fc_exch_mgr_reset to reset all EMs from the EM anchor list of the lport, adds additional exch lport pointer (ep->lp) check for shared EM case to reset exchange specific to a lport requested reset. 5. Updates exch allocation API fc_exch_alloc to use EM anchor list and its anchor match func pointer. The fc_exch_alloc will walk the list of EMs until it finds a match, a match will be either null match func pointer or call to match function returning true value. 6. Updates fc_exch_recv to accept incoming frame on local port using only lport pointer and frame pointer without specifying EM instance of incoming frame. Instead modified fc_exch_recv to locate EM for the incoming frame by matching xid of incoming frame against a EM xid range. This change was required to use EM list in libfc Rx path and after this change the lport fc_exch_mgr pointer emp is not needed anymore, so removed emp pointer. 7. Updates fnic for removed lport emp pointer and above modified libfc APIs fc_exch_recv, fc_exch_mgr_alloc and fc_exch_mgr_free. 8. Removes exch_get and exch_put from libfc_function_template as these are no longer needed with EM anchor list and its match function use. Also removes its default function fc_exch_get. A defect this patch introduced regarding the libfc initialization order in the fnic driver was fixed by Joe Eykholt . Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 16 ++-- drivers/scsi/fcoe/libfcoe.c | 2 +- drivers/scsi/fnic/fnic_fcs.c | 2 +- drivers/scsi/fnic/fnic_main.c | 20 ++--- drivers/scsi/libfc/fc_exch.c | 191 ++++++++++++++++++++++++++---------------- include/scsi/libfc.h | 48 ++--------- 6 files changed, 142 insertions(+), 137 deletions(-) (limited to 'include') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 719a99d4a438..ebf2e20370d7 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -423,11 +423,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, */ static inline int fcoe_em_config(struct fc_lport *lp) { - BUG_ON(lp->emp); - - lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, - FCOE_MIN_XID, FCOE_MAX_XID); - if (!lp->emp) + if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID, + FCOE_MAX_XID, NULL)) return -ENOMEM; return 0; @@ -478,8 +475,7 @@ static int fcoe_if_destroy(struct net_device *netdev) scsi_remove_host(lp->host); /* There are no more rports or I/O, free the EM */ - if (lp->emp) - fc_exch_mgr_free(lp->emp); + fc_exch_mgr_free(lp); /* Free existing skbs */ fcoe_clean_pending_queue(lp); @@ -634,7 +630,7 @@ static int fcoe_if_create(struct net_device *netdev) return rc; out_lp_destroy: - fc_exch_mgr_free(lp->emp); /* Free the EM */ + fc_exch_mgr_free(lp); out_netdev_cleanup: fcoe_netdev_cleanup(fc); out_host_put: @@ -1277,7 +1273,7 @@ int fcoe_percpu_receive_thread(void *arg) fh = fc_frame_header_get(fp); if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP) { - fc_exch_recv(lp, lp->emp, fp); + fc_exch_recv(lp, fp); continue; } if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { @@ -1298,7 +1294,7 @@ int fcoe_percpu_receive_thread(void *arg) fc_frame_free(fp); continue; } - fc_exch_recv(lp, lp->emp, fp); + fc_exch_recv(lp, fp); } return 0; } diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 78caa6be1130..4db719d6ada1 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -885,7 +885,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) stats->RxFrames++; stats->RxWords += skb->len / FIP_BPW; - fc_exch_recv(lp, lp->emp, fp); + fc_exch_recv(lp, fp); return; len_err: diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 07e6eedb83ce..50db3e36a619 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -115,7 +115,7 @@ void fnic_handle_frame(struct work_struct *work) } spin_unlock_irqrestore(&fnic->fnic_lock, flags); - fc_exch_recv(lp, lp->emp, fp); + fc_exch_recv(lp, fp); } } diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 2c266c01dc5a..71c7bbe26d05 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -671,14 +671,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev, lp->link_up = 0; lp->tt = fnic_transport_template; - lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, - FCPIO_HOST_EXCH_RANGE_START, - FCPIO_HOST_EXCH_RANGE_END); - if (!lp->emp) { - err = -ENOMEM; - goto err_out_remove_scsi_host; - } - lp->max_retry_count = fnic->config.flogi_retries; lp->max_rport_retry_count = fnic->config.plogi_retries; lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | @@ -693,12 +685,18 @@ static int __devinit fnic_probe(struct pci_dev *pdev, fc_set_wwnn(lp, fnic->config.node_wwn); fc_set_wwpn(lp, fnic->config.port_wwn); - fc_exch_init(lp); fc_lport_init(lp); + fc_exch_init(lp); fc_elsct_init(lp); fc_rport_init(lp); fc_disc_init(lp); + if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START, + FCPIO_HOST_EXCH_RANGE_END, NULL)) { + err = -ENOMEM; + goto err_out_remove_scsi_host; + } + fc_lport_config(lp); if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + @@ -738,7 +736,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev, return 0; err_out_free_exch_mgr: - fc_exch_mgr_free(lp->emp); + fc_exch_mgr_free(lp); err_out_remove_scsi_host: fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); @@ -827,7 +825,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev) fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); - fc_exch_mgr_free(fnic->lport->emp); + fc_exch_mgr_free(fnic->lport); vnic_dev_notify_unset(fnic->vdev); fnic_free_vnic_resources(fnic); fnic_free_intr(fnic); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 3ad7f88e7ae3..324589a5cc03 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -65,7 +65,6 @@ struct fc_exch_mgr { u16 last_read; /* last xid allocated for read */ u32 total_exches; /* total allocated exchanges */ struct list_head ex_list; /* allocated exchanges list */ - struct fc_lport *lp; /* fc device instance */ mempool_t *ep_pool; /* reserve ep's */ /* @@ -275,8 +274,6 @@ static void fc_exch_release(struct fc_exch *ep) mp = ep->em; if (ep->destructor) ep->destructor(&ep->seq, ep->arg); - if (ep->lp->tt.exch_put) - ep->lp->tt.exch_put(ep->lp, mp, ep->xid); WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE)); mempool_free(ep, mp->ep_pool); } @@ -513,17 +510,20 @@ static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) return xid; } -/* - * fc_exch_alloc - allocate an exchange. - * @mp : ptr to the exchange manager - * @xid: input xid +/** + * fc_exch_em_alloc() - allocate an exchange from a specified EM. + * @lport: ptr to the local port + * @mp: ptr to the exchange manager + * @fp: ptr to the FC frame + * @xid: input xid * * if xid is supplied zero then assign next free exchange ID * from exchange manager, otherwise use supplied xid. * Returns with exch lock held. */ -struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, - struct fc_frame *fp, u16 xid) +static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, + struct fc_exch_mgr *mp, + struct fc_frame *fp, u16 xid) { struct fc_exch *ep; @@ -566,7 +566,7 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, */ ep->oxid = ep->xid = xid; ep->em = mp; - ep->lp = mp->lp; + ep->lp = lport; ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ ep->rxid = FC_XID_UNKNOWN; ep->class = mp->class; @@ -579,6 +579,31 @@ err: mempool_free(ep, mp->ep_pool); return NULL; } + +/** + * fc_exch_alloc() - allocate an exchange. + * @lport: ptr to the local port + * @fp: ptr to the FC frame + * + * This function walks the list of the exchange manager(EM) + * anchors to select a EM for new exchange allocation. The + * EM is selected having either a NULL match function pointer + * or call to match function returning true. + */ +struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_exch_mgr_anchor *ema; + struct fc_exch *ep; + + list_for_each_entry(ema, &lport->ema_list, ema_list) { + if (!ema->match || ema->match(fp)) { + ep = fc_exch_em_alloc(lport, ema->mp, fp, 0); + if (ep) + return ep; + } + } + return NULL; +} EXPORT_SYMBOL(fc_exch_alloc); /* @@ -617,12 +642,14 @@ EXPORT_SYMBOL(fc_exch_done); * Allocate a new exchange as responder. * Sets the responder ID in the frame header. */ -static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) +static struct fc_exch *fc_exch_resp(struct fc_lport *lport, + struct fc_exch_mgr *mp, + struct fc_frame *fp) { struct fc_exch *ep; struct fc_frame_header *fh; - ep = mp->lp->tt.exch_get(mp->lp, fp); + ep = fc_exch_alloc(lport, fp); if (ep) { ep->class = fc_frame_class(fp); @@ -648,7 +675,7 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) ep->esb_stat &= ~ESB_ST_SEQ_INIT; fc_exch_hold(ep); /* hold for caller */ - spin_unlock_bh(&ep->ex_lock); /* lock from exch_get */ + spin_unlock_bh(&ep->ex_lock); /* lock from fc_exch_alloc */ } return ep; } @@ -658,7 +685,8 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold * on the ep that should be released by the caller. */ -static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, +static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, + struct fc_exch_mgr *mp, struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); @@ -712,7 +740,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, reject = FC_RJT_RX_ID; goto rel; } - ep = fc_exch_resp(mp, fp); + ep = fc_exch_resp(lport, mp, fp); if (!ep) { reject = FC_RJT_EXCH_EST; /* XXX */ goto out; @@ -1103,7 +1131,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, enum fc_pf_rjt_reason reject; fr_seq(fp) = NULL; - reject = fc_seq_lookup_recip(mp, fp); + reject = fc_seq_lookup_recip(lp, mp, fp); if (reject == FC_RJT_NONE) { sp = fr_seq(fp); /* sequence will be held */ ep = fc_seq_exch(sp); @@ -1467,29 +1495,34 @@ void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) { struct fc_exch *ep; struct fc_exch *next; - struct fc_exch_mgr *mp = lp->emp; + struct fc_exch_mgr *mp; + struct fc_exch_mgr_anchor *ema; - spin_lock_bh(&mp->em_lock); + list_for_each_entry(ema, &lp->ema_list, ema_list) { + mp = ema->mp; + spin_lock_bh(&mp->em_lock); restart: - list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { - if ((sid == 0 || sid == ep->sid) && - (did == 0 || did == ep->did)) { - fc_exch_hold(ep); - spin_unlock_bh(&mp->em_lock); - - fc_exch_reset(ep); - - fc_exch_release(ep); - spin_lock_bh(&mp->em_lock); - - /* - * must restart loop incase while lock was down - * multiple eps were released. - */ - goto restart; + list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { + if ((lp == ep->lp) && + (sid == 0 || sid == ep->sid) && + (did == 0 || did == ep->did)) { + fc_exch_hold(ep); + spin_unlock_bh(&mp->em_lock); + + fc_exch_reset(ep); + + fc_exch_release(ep); + spin_lock_bh(&mp->em_lock); + + /* + * must restart loop incase while lock + * was down multiple eps were released. + */ + goto restart; + } } + spin_unlock_bh(&mp->em_lock); } - spin_unlock_bh(&mp->em_lock); } EXPORT_SYMBOL(fc_exch_mgr_reset); @@ -1778,7 +1811,8 @@ EXPORT_SYMBOL(fc_exch_mgr_del); struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, enum fc_class class, - u16 min_xid, u16 max_xid) + u16 min_xid, u16 max_xid, + bool (*match)(struct fc_frame *)) { struct fc_exch_mgr *mp; size_t len; @@ -1803,7 +1837,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, mp->class = class; mp->total_exches = 0; mp->exches = (struct fc_exch **)(mp + 1); - mp->lp = lp; /* adjust em exch xid range for offload */ mp->min_xid = min_xid; mp->max_xid = max_xid; @@ -1826,6 +1859,18 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, if (!mp->ep_pool) goto free_mp; + kref_init(&mp->kref); + if (!fc_exch_mgr_add(lp, mp, match)) { + mempool_destroy(mp->ep_pool); + goto free_mp; + } + + /* + * Above kref_init() sets mp->kref to 1 and then + * call to fc_exch_mgr_add incremented mp->kref again, + * so adjust that extra increment. + */ + kref_put(&mp->kref, fc_exch_mgr_destroy); return mp; free_mp: @@ -1834,27 +1879,15 @@ free_mp: } EXPORT_SYMBOL(fc_exch_mgr_alloc); -void fc_exch_mgr_free(struct fc_exch_mgr *mp) +void fc_exch_mgr_free(struct fc_lport *lport) { - WARN_ON(!mp); - /* - * The total exch count must be zero - * before freeing exchange manager. - */ - WARN_ON(mp->total_exches != 0); - mempool_destroy(mp->ep_pool); - kfree(mp); + struct fc_exch_mgr_anchor *ema, *next; + + list_for_each_entry_safe(ema, next, &lport->ema_list, ema_list) + fc_exch_mgr_del(ema); } EXPORT_SYMBOL(fc_exch_mgr_free); -struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp) -{ - if (!lp || !lp->emp) - return NULL; - - return fc_exch_alloc(lp->emp, fp, 0); -} -EXPORT_SYMBOL(fc_exch_get); struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, struct fc_frame *fp, @@ -1869,7 +1902,7 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, struct fc_frame_header *fh; int rc = 1; - ep = lp->tt.exch_get(lp, fp); + ep = fc_exch_alloc(lp, fp); if (!ep) { fc_frame_free(fp); return NULL; @@ -1914,24 +1947,44 @@ EXPORT_SYMBOL(fc_exch_seq_send); /* * Receive a frame */ -void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, - struct fc_frame *fp) +void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); - u32 f_ctl; + struct fc_exch_mgr_anchor *ema; + u32 f_ctl, found = 0; + u16 oxid; /* lport lock ? */ - if (!lp || !mp || lp->state == LPORT_ST_DISABLED) { + if (!lp || lp->state == LPORT_ST_DISABLED) { FC_LPORT_DBG(lp, "Receiving frames for an lport that " "has not been initialized correctly\n"); fc_frame_free(fp); return; } + f_ctl = ntoh24(fh->fh_f_ctl); + oxid = ntohs(fh->fh_ox_id); + if (f_ctl & FC_FC_EX_CTX) { + list_for_each_entry(ema, &lp->ema_list, ema_list) { + if ((oxid >= ema->mp->min_xid) && + (oxid <= ema->mp->max_xid)) { + found = 1; + break; + } + } + + if (!found) { + FC_LPORT_DBG(lp, "Received response for out " + "of range oxid:%hx\n", oxid); + fc_frame_free(fp); + return; + } + } else + ema = list_entry(lp->ema_list.prev, typeof(*ema), ema_list); + /* * If frame is marked invalid, just drop it. */ - f_ctl = ntoh24(fh->fh_f_ctl); switch (fr_eof(fp)) { case FC_EOF_T: if (f_ctl & FC_FC_END_SEQ) @@ -1939,34 +1992,24 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, /* fall through */ case FC_EOF_N: if (fh->fh_type == FC_TYPE_BLS) - fc_exch_recv_bls(mp, fp); + fc_exch_recv_bls(ema->mp, fp); else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == FC_FC_EX_CTX) - fc_exch_recv_seq_resp(mp, fp); + fc_exch_recv_seq_resp(ema->mp, fp); else if (f_ctl & FC_FC_SEQ_CTX) - fc_exch_recv_resp(mp, fp); + fc_exch_recv_resp(ema->mp, fp); else - fc_exch_recv_req(lp, mp, fp); + fc_exch_recv_req(lp, ema->mp, fp); break; default: FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp)); fc_frame_free(fp); - break; } } EXPORT_SYMBOL(fc_exch_recv); int fc_exch_init(struct fc_lport *lp) { - if (!lp->tt.exch_get) { - /* - * exch_put() should be NULL if - * exch_get() is NULL - */ - WARN_ON(lp->tt.exch_put); - lp->tt.exch_get = fc_exch_get; - } - if (!lp->tt.seq_start_next) lp->tt.seq_start_next = fc_seq_start_next; diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index f1bde91f98a2..c2b928cfafb9 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -517,25 +517,6 @@ struct libfc_function_template { */ void (*exch_done)(struct fc_seq *sp); - /* - * Assigns a EM and a free XID for an new exchange and then - * allocates a new exchange and sequence pair. - * The fp can be used to determine free XID. - * - * STATUS: OPTIONAL - */ - struct fc_exch *(*exch_get)(struct fc_lport *lp, struct fc_frame *fp); - - /* - * Release previously assigned XID by exch_get API. - * The LLD may implement this if XID is assigned by LLD - * in exch_get(). - * - * STATUS: OPTIONAL - */ - void (*exch_put)(struct fc_lport *lp, struct fc_exch_mgr *mp, - u16 ex_id); - /* * Start a new sequence on the same exchange/sequence tuple. * @@ -703,7 +684,6 @@ struct fc_lport { /* Associations */ struct Scsi_Host *host; - struct fc_exch_mgr *emp; struct list_head ema_list; struct fc_rport *dns_rp; struct fc_rport *ptp_rp; @@ -996,27 +976,25 @@ void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema); * a new exchange. * The LLD may choose to have multiple EMs, * e.g. one EM instance per CPU receive thread in LLD. - * The LLD can use exch_get() of struct libfc_function_template - * to specify XID for a new exchange within - * a specified EM instance. * - * The em_idx to uniquely identify an EM instance. + * Specified match function is used in allocating exchanges + * from newly allocated EM. */ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, enum fc_class class, u16 min_xid, - u16 max_xid); + u16 max_xid, + bool (*match)(struct fc_frame *)); /* - * Free an exchange manager. + * Free all exchange managers of a lport. */ -void fc_exch_mgr_free(struct fc_exch_mgr *mp); +void fc_exch_mgr_free(struct fc_lport *lport); /* * Receive a frame on specified local port and exchange manager. */ -void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, - struct fc_frame *fp); +void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp); /* * This function is for exch_seq_send function pointer in @@ -1057,20 +1035,10 @@ int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec); */ void fc_exch_done(struct fc_seq *sp); -/* - * Assigns a EM and XID for a frame and then allocates - * a new exchange and sequence pair. - * The fp can be used to determine free XID. - */ -struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp); - /* * Allocate a new exchange and sequence pair. - * if ex_id is zero then next free exchange id - * from specified exchange manger mp will be assigned. */ -struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, - struct fc_frame *fp, u16 ex_id); +struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp); /* * Start a new sequence on the same exchange as the supplied sequence. */ -- cgit v1.2.3 From 537029f8e950776951ca2a3fe30121d5c05643d1 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 29 Jul 2009 17:05:32 -0700 Subject: [SCSI] libfc: Remove FC_FRAME_SG_LEN in fc_fcp_send_data FC_FRAME_SG_LEN is 4 which is too small when offload is enabled. Actually, the WARN_ON() in fc_fcp_send_data() should be: WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags > MAX_SKB_FRAGS); But since we will not get anything more than 64K anyway, so there is no need to do this anyway here. Therefore, I am getting rid of FC_FRAME_SG_LEN here and the WARN_ON here. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 2 -- include/scsi/fc_frame.h | 7 ------- 2 files changed, 9 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index e303e0d12c4b..2069edf80268 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -569,8 +569,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, } sg_bytes = min(tlen, sg->length - offset); if (using_sg) { - WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags > - FC_FRAME_SG_LEN); get_page(sg_page(sg)); skb_fill_page_desc(fp_skb(fp), skb_shinfo(fp_skb(fp))->nr_frags, diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h index 59511057cee0..c35d2383cc26 100644 --- a/include/scsi/fc_frame.h +++ b/include/scsi/fc_frame.h @@ -37,13 +37,6 @@ #define FC_FRAME_HEADROOM 32 /* headroom for VLAN + FCoE headers */ #define FC_FRAME_TAILROOM 8 /* trailer space for FCoE */ -/* - * Information about an individual fibre channel frame received or to be sent. - * The buffer may be in up to 4 additional non-contiguous sections, - * but the linear section must hold the frame header. - */ -#define FC_FRAME_SG_LEN 4 /* scatter/gather list maximum length */ - #define fp_skb(fp) (&((fp)->skb)) #define fr_hdr(fp) ((fp)->skb.data) #define fr_len(fp) ((fp)->skb.len) -- cgit v1.2.3 From 163f52b6cf3a639df6a72c7937e0eb88b20f1ef3 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 1 Aug 2009 00:39:36 +0000 Subject: [SCSI] ses: fix hotplug with multiple devices and expanders In a situation either with expanders or with multiple enclosure devices, hot add doesn't always work. This is because we try to find a single enclosure device attached to the host. Fix this by looping over all enclosure devices attached to the host and also by making the find loop recognise that the enclosure devices may be expander remote (i.e. not parented by the host). Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/misc/enclosure.c | 44 ++++++++++++++++++++++++++++++++------------ drivers/scsi/ses.c | 10 ++++++---- include/linux/enclosure.h | 3 ++- 3 files changed, 40 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 348443bdb23b..789d12128c24 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -33,24 +33,44 @@ static DEFINE_MUTEX(container_list_lock); static struct class enclosure_class; /** - * enclosure_find - find an enclosure given a device - * @dev: the device to find for + * enclosure_find - find an enclosure given a parent device + * @dev: the parent to match against + * @start: Optional enclosure device to start from (NULL if none) * - * Looks through the list of registered enclosures to see - * if it can find a match for a device. Returns NULL if no - * enclosure is found. Obtains a reference to the enclosure class - * device which must be released with device_put(). + * Looks through the list of registered enclosures to find all those + * with @dev as a parent. Returns NULL if no enclosure is + * found. @start can be used as a starting point to obtain multiple + * enclosures per parent (should begin with NULL and then be set to + * each returned enclosure device). Obtains a reference to the + * enclosure class device which must be released with device_put(). + * If @start is not NULL, a reference must be taken on it which is + * released before returning (this allows a loop through all + * enclosures to exit with only the reference on the enclosure of + * interest held). Note that the @dev may correspond to the actual + * device housing the enclosure, in which case no iteration via @start + * is required. */ -struct enclosure_device *enclosure_find(struct device *dev) +struct enclosure_device *enclosure_find(struct device *dev, + struct enclosure_device *start) { struct enclosure_device *edev; mutex_lock(&container_list_lock); - list_for_each_entry(edev, &container_list, node) { - if (edev->edev.parent == dev) { - get_device(&edev->edev); - mutex_unlock(&container_list_lock); - return edev; + edev = list_prepare_entry(start, &container_list, node); + if (start) + put_device(&start->edev); + + list_for_each_entry_continue(edev, &container_list, node) { + struct device *parent = edev->edev.parent; + /* parent might not be immediate, so iterate up to + * the root of the tree if necessary */ + while (parent) { + if (parent == dev) { + get_device(&edev->edev); + mutex_unlock(&container_list_lock); + return edev; + } + parent = parent->parent; } } mutex_unlock(&container_list_lock); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 4f618f487356..e1b8c828f03a 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -413,10 +413,11 @@ static int ses_intf_add(struct device *cdev, if (!scsi_device_enclosure(sdev)) { /* not an enclosure, but might be in one */ - edev = enclosure_find(&sdev->host->shost_gendev); - if (edev) { + struct enclosure_device *prev = NULL; + + while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { ses_match_to_enclosure(edev, sdev); - put_device(&edev->edev); + prev = edev; } return -ENODEV; } @@ -625,7 +626,8 @@ static void ses_intf_remove(struct device *cdev, if (!scsi_device_enclosure(sdev)) return; - edev = enclosure_find(cdev->parent); + /* exact match to this enclosure */ + edev = enclosure_find(cdev->parent, NULL); if (!edev) return; diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h index 4332442b1b57..d77811e9ed84 100644 --- a/include/linux/enclosure.h +++ b/include/linux/enclosure.h @@ -123,7 +123,8 @@ enclosure_component_register(struct enclosure_device *, unsigned int, int enclosure_add_device(struct enclosure_device *enclosure, int component, struct device *dev); int enclosure_remove_device(struct enclosure_device *enclosure, int component); -struct enclosure_device *enclosure_find(struct device *dev); +struct enclosure_device *enclosure_find(struct device *dev, + struct enclosure_device *start); int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), void *data); -- cgit v1.2.3 From 43d8eb9cfd0aea93be32181c64e18191b69c211c Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 1 Aug 2009 00:41:22 +0000 Subject: [SCSI] ses: add support for enclosure component hot removal Right at the moment, hot removal of a device within an enclosure does nothing (because the intf_remove only copes with enclosure removal not with component removal). Fix this by adding a function to remove the component. Also needed to fix the prototype of enclosure_remove_device, since we know the device we've removed but not the internal component number Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/misc/enclosure.c | 22 ++++++++++++++-------- drivers/scsi/ses.c | 33 ++++++++++++++++++++++++++------- include/linux/enclosure.h | 2 +- 3 files changed, 41 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 789d12128c24..850706a5e553 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -332,19 +332,25 @@ EXPORT_SYMBOL_GPL(enclosure_add_device); * Returns zero on success or an error. * */ -int enclosure_remove_device(struct enclosure_device *edev, int component) +int enclosure_remove_device(struct enclosure_device *edev, struct device *dev) { struct enclosure_component *cdev; + int i; - if (!edev || component >= edev->components) + if (!edev || !dev) return -EINVAL; - cdev = &edev->component[component]; - - device_del(&cdev->cdev); - put_device(cdev->dev); - cdev->dev = NULL; - return device_add(&cdev->cdev); + for (i = 0; i < edev->components; i++) { + cdev = &edev->component[i]; + if (cdev->dev == dev) { + enclosure_remove_links(cdev); + device_del(&cdev->cdev); + put_device(dev); + cdev->dev = NULL; + return device_add(&cdev->cdev); + } + } + return -ENODEV; } EXPORT_SYMBOL_GPL(enclosure_remove_device); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index e1b8c828f03a..be593c8525b5 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -616,18 +616,26 @@ static int ses_remove(struct device *dev) return 0; } -static void ses_intf_remove(struct device *cdev, - struct class_interface *intf) +static void ses_intf_remove_component(struct scsi_device *sdev) +{ + struct enclosure_device *edev, *prev = NULL; + + while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { + prev = edev; + if (!enclosure_remove_device(edev, &sdev->sdev_gendev)) + break; + } + if (edev) + put_device(&edev->edev); +} + +static void ses_intf_remove_enclosure(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(cdev->parent); struct enclosure_device *edev; struct ses_device *ses_dev; - if (!scsi_device_enclosure(sdev)) - return; - /* exact match to this enclosure */ - edev = enclosure_find(cdev->parent, NULL); + edev = enclosure_find(&sdev->sdev_gendev, NULL); if (!edev) return; @@ -645,6 +653,17 @@ static void ses_intf_remove(struct device *cdev, enclosure_unregister(edev); } +static void ses_intf_remove(struct device *cdev, + struct class_interface *intf) +{ + struct scsi_device *sdev = to_scsi_device(cdev->parent); + + if (!scsi_device_enclosure(sdev)) + ses_intf_remove_component(sdev); + else + ses_intf_remove_enclosure(sdev); +} + static struct class_interface ses_interface = { .add_dev = ses_intf_add, .remove_dev = ses_intf_remove, diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h index d77811e9ed84..90d1c2184112 100644 --- a/include/linux/enclosure.h +++ b/include/linux/enclosure.h @@ -122,7 +122,7 @@ enclosure_component_register(struct enclosure_device *, unsigned int, enum enclosure_component_type, const char *); int enclosure_add_device(struct enclosure_device *enclosure, int component, struct device *dev); -int enclosure_remove_device(struct enclosure_device *enclosure, int component); +int enclosure_remove_device(struct enclosure_device *, struct device *); struct enclosure_device *enclosure_find(struct device *dev, struct enclosure_device *start); int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), -- cgit v1.2.3 From 18ee70c9d7b2dcd312a1f8c6536841e7c0fea5ca Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Mon, 3 Aug 2009 12:42:33 -0700 Subject: [SCSI] scsi_dh: add the interface scsi_dh_set_params() When we moved the device handler functionality from dm layer to SCSI layer we dropped the parameter functionality. This path adds an interface to scsi dh layer to set device handler parameters. Basically, multipath layer need to create a string with all the parameters and call scsi_dh_set_params() after it called scsi_dh_attach() on a device. If a device handler provides such an interface it will handle the parameters as it expects them. Reported-by: Eddie Williams Signed-off-by: Chandra Seetharaman Tested-by: Eddie Williams Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh.c | 33 +++++++++++++++++++++++++++++++++ include/scsi/scsi_device.h | 1 + include/scsi/scsi_dh.h | 5 +++++ 3 files changed, 39 insertions(+) (limited to 'include') diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 53a7385e1b4d..3ee1cbc89479 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -451,6 +451,39 @@ int scsi_dh_activate(struct request_queue *q) } EXPORT_SYMBOL_GPL(scsi_dh_activate); +/* + * scsi_dh_set_params - set the parameters for the device as per the + * string specified in params. + * @q - Request queue that is associated with the scsi_device for + * which the parameters to be set. + * @params - parameters in the following format + * "no_of_params\0param1\0param2\0param3\0...\0" + * for example, string for 2 parameters with value 10 and 21 + * is specified as "2\010\021\0". + */ +int scsi_dh_set_params(struct request_queue *q, const char *params) +{ + int err = -SCSI_DH_NOSYS; + unsigned long flags; + struct scsi_device *sdev; + struct scsi_device_handler *scsi_dh = NULL; + + spin_lock_irqsave(q->queue_lock, flags); + sdev = q->queuedata; + if (sdev && sdev->scsi_dh_data) + scsi_dh = sdev->scsi_dh_data->scsi_dh; + if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev)) + err = 0; + spin_unlock_irqrestore(q->queue_lock, flags); + + if (err) + return err; + err = scsi_dh->set_params(sdev, params); + put_device(&sdev->sdev_gendev); + return err; +} +EXPORT_SYMBOL_GPL(scsi_dh_set_params); + /* * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for * the given name. FALSE(0) otherwise. diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 1f3a4c8044c0..9af48cbf0036 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -187,6 +187,7 @@ struct scsi_device_handler { void (*detach)(struct scsi_device *); int (*activate)(struct scsi_device *); int (*prep_fn)(struct scsi_device *, struct request *); + int (*set_params)(struct scsi_device *, const char *); }; struct scsi_dh_data { diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h index 33efce20c26c..ff2407405b42 100644 --- a/include/scsi/scsi_dh.h +++ b/include/scsi/scsi_dh.h @@ -60,6 +60,7 @@ extern int scsi_dh_activate(struct request_queue *); extern int scsi_dh_handler_exist(const char *); extern int scsi_dh_attach(struct request_queue *, const char *); extern void scsi_dh_detach(struct request_queue *); +extern int scsi_dh_set_params(struct request_queue *, const char *); #else static inline int scsi_dh_activate(struct request_queue *req) { @@ -77,4 +78,8 @@ static inline void scsi_dh_detach(struct request_queue *q) { return; } +static inline int scsi_dh_set_params(struct request_queue *req, const char *params) +{ + return -SCSI_DH_NOSYS; +} #endif -- cgit v1.2.3 From d1af8a328755f51c9b76157a8692e56520d3fd94 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 20 Aug 2009 15:11:02 -0500 Subject: [SCSI] iscsi_tcp: add new conn error to indicate tcp conn closed If a target closed the connection, we will detect it in the state_changed or data_ready callout. This adds a new conn error value to use for this problem, so it is not confused with when the initiator throws a conn error and drops the connection. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 23 +++++++++-------------- include/scsi/iscsi_if.h | 1 + 2 files changed, 10 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index c7e2ff24ee9e..2b1b834a098b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -109,11 +109,14 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, */ static inline int iscsi_sw_sk_state_check(struct sock *sk) { - if ((sk->sk_state == TCP_CLOSE_WAIT || - sk->sk_state == TCP_CLOSE) && - !atomic_read(&sk->sk_rmem_alloc)) - return -ECONNRESET; + struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data; + if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) && + !atomic_read(&sk->sk_rmem_alloc)) { + ISCSI_SW_TCP_DBG(conn, "TCP_CLOSE|TCP_CLOSE_WAIT\n"); + iscsi_conn_failure(conn, ISCSI_ERR_TCP_CONN_CLOSE); + return -ECONNRESET; + } return 0; } @@ -135,11 +138,7 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) rd_desc.count = 1; tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv); - if (iscsi_sw_sk_state_check(sk) < 0) { - ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_data_ready: " - "TCP_CLOSE|TCP_CLOSE_WAIT\n"); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - } + iscsi_sw_sk_state_check(sk); read_unlock(&sk->sk_callback_lock); @@ -161,11 +160,7 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) conn = (struct iscsi_conn*)sk->sk_user_data; session = conn->session; - if (iscsi_sw_sk_state_check(sk) < 0) { - ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_state_change: " - "TCP_CLOSE|TCP_CLOSE_WAIT\n"); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - } + iscsi_sw_sk_state_check(sk); tcp_conn = conn->dd_data; tcp_sw_conn = tcp_conn->dd_data; diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 4426f00da5ff..d67dda2b6aa0 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -262,6 +262,7 @@ enum iscsi_err { ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17, ISCSI_ERR_INVALID_HOST = ISCSI_ERR_BASE + 18, ISCSI_ERR_XMIT_FAILED = ISCSI_ERR_BASE + 19, + ISCSI_ERR_TCP_CONN_CLOSE = ISCSI_ERR_BASE + 20, }; /* -- cgit v1.2.3 From e4bc50bedf0dd6c63f20a7bc0a2b46667664fba1 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 25 Aug 2009 13:58:47 -0700 Subject: [SCSI] fcoe, libfc: adds per cpu exch pool within exchange manager(EM) Adds per cpu exch pool for these reasons:- 1. Currently an EM instance is shared across all cpus to manage all exches for all cpus. This required em_lock across all cpus for an exch alloc, free, lookup and reset each frame and that made em_lock expensive, so instead having per cpu exch pool with their own per cpu pool lock will likely reduce locking contention in fast path for an exch alloc, free and lookup. 2. Per cpu exch pool will likely improve cache hit ratio since all frames of an exch will be processed on the same cpu on which exch originated. This patch is only prep work to help in keeping complexity of next patch low, so this patch only sets up per cpu exch pool and related helper funcs to be used by next patch. The next patch fully makes use of per cpu exch pool in all code paths ie. tx, rx and reset. Divides per EM exch id range equally across all cpus to setup per cpu exch pool. This division is such that lower bits of exch id carries cpu number info on which exch originated, later a simple bitwise AND operation on exch id of incoming frame with fc_cpu_mask retrieves cpu number info to direct all frames to same cpu on which exch originated. This required a global fc_cpu_mask and fc_cpu_order initialized to max possible cpus number nr_cpu_ids rounded up to 2's power, this will be used in mapping exch id and exch ptr array index in pool during exch allocation, find or reset code paths. Adds a check in fc_exch_mgr_alloc() to ensure specified min_xid lower bits are zero since these bits are used to carry cpu info. Adds and initializes struct fc_exch_pool with all required fields to manage exches in pool. Allocates per cpu struct fc_exch_pool with memory for exches array for range of exches per pool. The exches array memory is followed by struct fc_exch_pool. Adds fc_exch_ptr_get/set() helper functions to get/set exch ptr in pool exches array at specified array index. Increases default FCOE_MAX_XID to 0x0FFF from 0x07EF, so that more exches are available per cpu after above described exch id range division across all cpus to each pool. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.h | 2 +- drivers/scsi/libfc/fc_exch.c | 89 ++++++++++++++++++++++++++++++++++++++++++-- include/scsi/libfc.h | 1 + 3 files changed, 88 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 65120e21f5c4..550d1e49d1a3 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -38,7 +38,7 @@ #define FCOE_MAX_OUTSTANDING_COMMANDS 1024 #define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ -#define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ +#define FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */ unsigned int fcoe_debug_logging; module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 40c34274bd81..9cbe8d66eb25 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -32,6 +32,9 @@ #include #include +u16 fc_cpu_mask; /* cpu mask for possible cpus */ +EXPORT_SYMBOL(fc_cpu_mask); +static u16 fc_cpu_order; /* 2's power to represent total possible cpus */ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ /* @@ -47,6 +50,20 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ * fc_seq holds the state for an individual sequence. */ +/* + * Per cpu exchange pool + * + * This structure manages per cpu exchanges in array of exchange pointers. + * This array is allocated followed by struct fc_exch_pool memory for + * assigned range of exchanges to per cpu pool. + */ +struct fc_exch_pool { + u16 next_index; /* next possible free exchange index */ + u16 total_exches; /* total allocated exchanges */ + spinlock_t lock; /* exch pool lock */ + struct list_head ex_list; /* allocated exchanges list */ +}; + /* * Exchange manager. * @@ -66,6 +83,8 @@ struct fc_exch_mgr { u32 total_exches; /* total allocated exchanges */ struct list_head ex_list; /* allocated exchanges list */ mempool_t *ep_pool; /* reserve ep's */ + u16 pool_max_index; /* max exch array index in exch pool */ + struct fc_exch_pool *pool; /* per cpu exch pool */ /* * currently exchange mgr stats are updated but not used. @@ -303,6 +322,19 @@ static int fc_exch_done_locked(struct fc_exch *ep) return rc; } +static inline struct fc_exch *fc_exch_ptr_get(struct fc_exch_pool *pool, + u16 index) +{ + struct fc_exch **exches = (struct fc_exch **)(pool + 1); + return exches[index]; +} + +static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index, + struct fc_exch *ep) +{ + ((struct fc_exch **)(pool + 1))[index] = ep; +} + static void fc_exch_mgr_delete_ep(struct fc_exch *ep) { struct fc_exch_mgr *mp; @@ -1751,6 +1783,7 @@ static void fc_exch_mgr_destroy(struct kref *kref) */ WARN_ON(mp->total_exches != 0); mempool_destroy(mp->ep_pool); + free_percpu(mp->pool); kfree(mp); } @@ -1770,8 +1803,13 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, { struct fc_exch_mgr *mp; size_t len; + u16 pool_exch_range; + size_t pool_size; + unsigned int cpu; + struct fc_exch_pool *pool; - if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { + if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN || + (min_xid & fc_cpu_mask) != 0) { FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", min_xid, max_xid); return NULL; @@ -1802,10 +1840,31 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, if (!mp->ep_pool) goto free_mp; + /* + * Setup per cpu exch pool with entire exchange id range equally + * divided across all cpus. The exch pointers array memory is + * allocated for exch range per pool. + */ + pool_exch_range = (mp->max_xid - mp->min_xid + 1) / (fc_cpu_mask + 1); + mp->pool_max_index = pool_exch_range - 1; + + /* + * Allocate and initialize per cpu exch pool + */ + pool_size = sizeof(*pool) + pool_exch_range * sizeof(struct fc_exch *); + mp->pool = __alloc_percpu(pool_size, __alignof__(struct fc_exch_pool)); + if (!mp->pool) + goto free_mempool; + for_each_possible_cpu(cpu) { + pool = per_cpu_ptr(mp->pool, cpu); + spin_lock_init(&pool->lock); + INIT_LIST_HEAD(&pool->ex_list); + } + kref_init(&mp->kref); if (!fc_exch_mgr_add(lp, mp, match)) { - mempool_destroy(mp->ep_pool); - goto free_mp; + free_percpu(mp->pool); + goto free_mempool; } /* @@ -1816,6 +1875,8 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, kref_put(&mp->kref, fc_exch_mgr_destroy); return mp; +free_mempool: + mempool_destroy(mp->ep_pool); free_mp: kfree(mp); return NULL; @@ -1975,6 +2036,28 @@ int fc_exch_init(struct fc_lport *lp) if (!lp->tt.seq_exch_abort) lp->tt.seq_exch_abort = fc_seq_exch_abort; + /* + * Initialize fc_cpu_mask and fc_cpu_order. The + * fc_cpu_mask is set for nr_cpu_ids rounded up + * to order of 2's * power and order is stored + * in fc_cpu_order as this is later required in + * mapping between an exch id and exch array index + * in per cpu exch pool. + * + * This round up is required to align fc_cpu_mask + * to exchange id's lower bits such that all incoming + * frames of an exchange gets delivered to the same + * cpu on which exchange originated by simple bitwise + * AND operation between fc_cpu_mask and exchange id. + */ + fc_cpu_mask = 1; + fc_cpu_order = 0; + while (fc_cpu_mask < nr_cpu_ids) { + fc_cpu_mask <<= 1; + fc_cpu_order++; + } + fc_cpu_mask--; + return 0; } EXPORT_SYMBOL(fc_exch_init); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index c2b928cfafb9..32063389c4b0 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -343,6 +343,7 @@ static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp) struct fc_exch_mgr; struct fc_exch_mgr_anchor; +extern u16 fc_cpu_mask; /* cpu mask for possible cpus */ /* * Sequence. -- cgit v1.2.3 From b2f0091fbf8b475fa09b5e1712e0ab84cb3e1ca4 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 25 Aug 2009 13:58:53 -0700 Subject: [SCSI] fcoe, libfc: fully makes use of per cpu exch pool and then removes em_lock 1. Updates fcoe_rcv() to queue incoming frames to the fcoe per cpu thread on which this frame's exch was originated and simply use current cpu for request exch not originated by initiator. It is redundant to add this code under CONFIG_SMP, so removes CONFIG_SMP uses around this code. 2. Updates fc_exch_em_alloc, fc_exch_delete, fc_exch_find to use per cpu exch pools, here fc_exch_delete is rename of older fc_exch_mgr_delete_ep since ep/exch are now deleted in pools of EM and so brief new name is sufficient and better name. Updates these functions to map exch id to their index into exch pool using fc_cpu_mask, fc_cpu_order and EM min_xid. This mapping is as per detailed explanation about this in last patch and basically this is just as lower fc_cpu_mask bits of exch id as cpu number and upper bit sum of EM min_xid and exch index in pool. Uses pool next_index to keep track of exch allocation from pool along with pool_max_index as upper bound of exches array in pool. 3. Adds exch pool ptr to fc_exch to free exch to its pool in fc_exch_delete. 4. Updates fc_exch_mgr_reset to reset all exch pools of an EM, this required adding fc_exch_pool_reset func to reset exches in pool and then have fc_exch_mgr_reset call fc_exch_pool_reset for each pool within each EM for a lport. 5. Removes no longer needed exches array, em_lock, next_xid, and total_exches from struct fc_exch_mgr, these are not needed after use of per cpu exch pool, also removes not used max_read, last_read from struct fc_exch_mgr. 6. Updates locking notes for exch pool lock with fc_exch lock and uses pool lock in exch allocation, lookup and reset. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 19 +++-- drivers/scsi/libfc/fc_exch.c | 189 +++++++++++++++++++++++-------------------- include/scsi/libfc.h | 9 ++- 3 files changed, 115 insertions(+), 102 deletions(-) (limited to 'include') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 757aa28f0f04..e32a0ed266aa 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -912,8 +912,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, struct fcoe_softc *fc; struct fc_frame_header *fh; struct fcoe_percpu_s *fps; - unsigned short oxid; - unsigned int cpu = 0; + unsigned int cpu; fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); lp = fc->ctlr.lp; @@ -947,20 +946,20 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); fh = (struct fc_frame_header *) skb_transport_header(skb); - oxid = ntohs(fh->fh_ox_id); - fr = fcoe_dev_from_skb(skb); fr->fr_dev = lp; fr->ptype = ptype; -#ifdef CONFIG_SMP /* - * The incoming frame exchange id(oxid) is ANDed with num of online - * cpu bits to get cpu and then this cpu is used for selecting - * a per cpu kernel thread from fcoe_percpu. + * In case the incoming frame's exchange is originated from + * the initiator, then received frame's exchange id is ANDed + * with fc_cpu_mask bits to get the same cpu on which exchange + * was originated, otherwise just use the current cpu. */ - cpu = oxid & (num_online_cpus() - 1); -#endif + if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) + cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; + else + cpu = smp_processor_id(); fps = &per_cpu(fcoe_percpu, cpu); spin_lock_bh(&fps->fcoe_rx_list.lock); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 9cbe8d66eb25..b51db15a3876 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -73,14 +73,8 @@ struct fc_exch_pool { struct fc_exch_mgr { enum fc_class class; /* default class for sequences */ struct kref kref; /* exchange mgr reference count */ - spinlock_t em_lock; /* exchange manager lock, - must be taken before ex_lock */ - u16 next_xid; /* next possible free exchange ID */ u16 min_xid; /* min exchange ID */ u16 max_xid; /* max exchange ID */ - u16 max_read; /* max exchange ID for read */ - u16 last_read; /* last xid allocated for read */ - u32 total_exches; /* total allocated exchanges */ struct list_head ex_list; /* allocated exchanges list */ mempool_t *ep_pool; /* reserve ep's */ u16 pool_max_index; /* max exch array index in exch pool */ @@ -99,7 +93,6 @@ struct fc_exch_mgr { atomic_t seq_not_found; atomic_t non_bls_resp; } stats; - struct fc_exch **exches; /* for exch pointers indexed by xid */ }; #define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) @@ -192,8 +185,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp); * sequence allocation and deallocation must be locked. * - exchange refcnt can be done atomicly without locks. * - sequence allocation must be locked by exch lock. - * - If the em_lock and ex_lock must be taken at the same time, then the - * em_lock must be taken before the ex_lock. + * - If the EM pool lock and ex_lock must be taken at the same time, then the + * EM pool lock must be taken before the ex_lock. */ /* @@ -335,17 +328,18 @@ static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index, ((struct fc_exch **)(pool + 1))[index] = ep; } -static void fc_exch_mgr_delete_ep(struct fc_exch *ep) +static void fc_exch_delete(struct fc_exch *ep) { - struct fc_exch_mgr *mp; + struct fc_exch_pool *pool; - mp = ep->em; - spin_lock_bh(&mp->em_lock); - WARN_ON(mp->total_exches <= 0); - mp->total_exches--; - mp->exches[ep->xid - mp->min_xid] = NULL; + pool = ep->pool; + spin_lock_bh(&pool->lock); + WARN_ON(pool->total_exches <= 0); + pool->total_exches--; + fc_exch_ptr_set(pool, (ep->xid - ep->em->min_xid) >> fc_cpu_order, + NULL); list_del(&ep->ex_list); - spin_unlock_bh(&mp->em_lock); + spin_unlock_bh(&pool->lock); fc_exch_release(ep); /* drop hold for exch in mp */ } @@ -465,7 +459,7 @@ static void fc_exch_timeout(struct work_struct *work) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); if (resp) resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); fc_seq_exch_abort(sp, 2 * ep->r_a_tov); @@ -509,10 +503,9 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, struct fc_exch_mgr *mp) { struct fc_exch *ep; - u16 min, max, xid; - - min = mp->min_xid; - max = mp->max_xid; + unsigned int cpu; + u16 index; + struct fc_exch_pool *pool; /* allocate memory for exchange */ ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); @@ -522,15 +515,17 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, } memset(ep, 0, sizeof(*ep)); - spin_lock_bh(&mp->em_lock); - xid = mp->next_xid; - /* alloc a new xid */ - while (mp->exches[xid - min]) { - xid = (xid == max) ? min : xid + 1; - if (xid == mp->next_xid) + cpu = smp_processor_id(); + pool = per_cpu_ptr(mp->pool, cpu); + spin_lock_bh(&pool->lock); + index = pool->next_index; + /* allocate new exch from pool */ + while (fc_exch_ptr_get(pool, index)) { + index = index == mp->pool_max_index ? 0 : index + 1; + if (index == pool->next_index) goto err; } - mp->next_xid = (xid == max) ? min : xid + 1; + pool->next_index = index == mp->pool_max_index ? 0 : index + 1; fc_exch_hold(ep); /* hold for exch in mp */ spin_lock_init(&ep->ex_lock); @@ -541,17 +536,18 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, */ spin_lock_bh(&ep->ex_lock); - mp->exches[xid - mp->min_xid] = ep; - list_add_tail(&ep->ex_list, &mp->ex_list); + fc_exch_ptr_set(pool, index, ep); + list_add_tail(&ep->ex_list, &pool->ex_list); fc_seq_alloc(ep, ep->seq_id++); - mp->total_exches++; - spin_unlock_bh(&mp->em_lock); + pool->total_exches++; + spin_unlock_bh(&pool->lock); /* * update exchange */ - ep->oxid = ep->xid = xid; + ep->oxid = ep->xid = (index << fc_cpu_order | cpu) + mp->min_xid; ep->em = mp; + ep->pool = pool; ep->lp = lport; ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ ep->rxid = FC_XID_UNKNOWN; @@ -560,7 +556,7 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, out: return ep; err: - spin_unlock_bh(&mp->em_lock); + spin_unlock_bh(&pool->lock); atomic_inc(&mp->stats.no_free_exch_xid); mempool_free(ep, mp->ep_pool); return NULL; @@ -597,16 +593,18 @@ EXPORT_SYMBOL(fc_exch_alloc); */ static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid) { + struct fc_exch_pool *pool; struct fc_exch *ep = NULL; if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) { - spin_lock_bh(&mp->em_lock); - ep = mp->exches[xid - mp->min_xid]; + pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask); + spin_lock_bh(&pool->lock); + ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order); if (ep) { fc_exch_hold(ep); WARN_ON(ep->xid != xid); } - spin_unlock_bh(&mp->em_lock); + spin_unlock_bh(&pool->lock); } return ep; } @@ -620,7 +618,7 @@ void fc_exch_done(struct fc_seq *sp) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); } EXPORT_SYMBOL(fc_exch_done); @@ -1213,7 +1211,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) WARN_ON(fc_seq_exch(sp) != ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); } /* @@ -1323,7 +1321,7 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); if (resp) resp(sp, fp, ex_resp_arg); @@ -1466,48 +1464,76 @@ static void fc_exch_reset(struct fc_exch *ep) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); if (resp) resp(sp, ERR_PTR(-FC_EX_CLOSED), arg); } -/* - * Reset an exchange manager, releasing all sequences and exchanges. - * If sid is non-zero, reset only exchanges we source from that FID. - * If did is non-zero, reset only exchanges destined to that FID. +/** + * fc_exch_pool_reset() - Resets an per cpu exches pool. + * @lport: ptr to the local port + * @pool: ptr to the per cpu exches pool + * @sid: source FC ID + * @did: destination FC ID + * + * Resets an per cpu exches pool, releasing its all sequences + * and exchanges. If sid is non-zero, then reset only exchanges + * we sourced from that FID. If did is non-zero, reset only + * exchanges destined to that FID. */ -void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) +static void fc_exch_pool_reset(struct fc_lport *lport, + struct fc_exch_pool *pool, + u32 sid, u32 did) { struct fc_exch *ep; struct fc_exch *next; - struct fc_exch_mgr *mp; - struct fc_exch_mgr_anchor *ema; - list_for_each_entry(ema, &lp->ema_list, ema_list) { - mp = ema->mp; - spin_lock_bh(&mp->em_lock); + spin_lock_bh(&pool->lock); restart: - list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { - if ((lp == ep->lp) && - (sid == 0 || sid == ep->sid) && - (did == 0 || did == ep->did)) { - fc_exch_hold(ep); - spin_unlock_bh(&mp->em_lock); - - fc_exch_reset(ep); - - fc_exch_release(ep); - spin_lock_bh(&mp->em_lock); - - /* - * must restart loop incase while lock - * was down multiple eps were released. - */ - goto restart; - } + list_for_each_entry_safe(ep, next, &pool->ex_list, ex_list) { + if ((lport == ep->lp) && + (sid == 0 || sid == ep->sid) && + (did == 0 || did == ep->did)) { + fc_exch_hold(ep); + spin_unlock_bh(&pool->lock); + + fc_exch_reset(ep); + + fc_exch_release(ep); + spin_lock_bh(&pool->lock); + + /* + * must restart loop incase while lock + * was down multiple eps were released. + */ + goto restart; } - spin_unlock_bh(&mp->em_lock); + } + spin_unlock_bh(&pool->lock); +} + +/** + * fc_exch_mgr_reset() - Resets all EMs of a lport + * @lport: ptr to the local port + * @sid: source FC ID + * @did: destination FC ID + * + * Reset all EMs of a lport, releasing its all sequences and + * exchanges. If sid is non-zero, then reset only exchanges + * we sourced from that FID. If did is non-zero, reset only + * exchanges destined to that FID. + */ +void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did) +{ + struct fc_exch_mgr_anchor *ema; + unsigned int cpu; + + list_for_each_entry(ema, &lport->ema_list, ema_list) { + for_each_possible_cpu(cpu) + fc_exch_pool_reset(lport, + per_cpu_ptr(ema->mp->pool, cpu), + sid, did); } } EXPORT_SYMBOL(fc_exch_mgr_reset); @@ -1777,11 +1803,6 @@ static void fc_exch_mgr_destroy(struct kref *kref) { struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref); - /* - * The total exch count must be zero - * before freeing exchange manager. - */ - WARN_ON(mp->total_exches != 0); mempool_destroy(mp->ep_pool); free_percpu(mp->pool); kfree(mp); @@ -1802,7 +1823,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, bool (*match)(struct fc_frame *)) { struct fc_exch_mgr *mp; - size_t len; u16 pool_exch_range; size_t pool_size; unsigned int cpu; @@ -1816,25 +1836,16 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, } /* - * Memory need for EM + * allocate memory for EM */ - len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); - len += sizeof(struct fc_exch_mgr); - - mp = kzalloc(len, GFP_ATOMIC); + mp = kzalloc(sizeof(struct fc_exch_mgr), GFP_ATOMIC); if (!mp) return NULL; mp->class = class; - mp->total_exches = 0; - mp->exches = (struct fc_exch **)(mp + 1); /* adjust em exch xid range for offload */ mp->min_xid = min_xid; mp->max_xid = max_xid; - mp->next_xid = min_xid; - - INIT_LIST_HEAD(&mp->ex_list); - spin_lock_init(&mp->em_lock); mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep); if (!mp->ep_pool) @@ -1944,7 +1955,7 @@ err: rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); return NULL; } EXPORT_SYMBOL(fc_exch_seq_send); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 32063389c4b0..53b38814d38a 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -368,6 +368,7 @@ struct fc_seq { */ struct fc_exch { struct fc_exch_mgr *em; /* exchange manager */ + struct fc_exch_pool *pool; /* per cpu exches pool */ u32 state; /* internal driver state */ u16 xid; /* our exchange ID */ struct list_head ex_list; /* free or busy list linkage */ @@ -1045,10 +1046,12 @@ struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp); */ struct fc_seq *fc_seq_start_next(struct fc_seq *sp); + /* - * Reset an exchange manager, completing all sequences and exchanges. - * If s_id is non-zero, reset only exchanges originating from that FID. - * If d_id is non-zero, reset only exchanges sending to that FID. + * Reset all EMs of a lport, releasing its all sequences and + * exchanges. If sid is non-zero, then reset only exchanges + * we sourced from that FID. If did is non-zero, reset only + * exchanges destined to that FID. */ void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id); -- cgit v1.2.3 From ab28f1fd3b0d14c1bd693e640decd711d5e6642a Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:34 -0700 Subject: [SCSI] libfc: prepare to split off struct fc_rport_priv from fc_rport_libfc_priv While the I/O and LLD interfaces use fc_rport_libfc_priv, the disc and rport interfaces will use fc_rport_priv, which will be separately allocated. Change the disc and rport usage of fc_rport_libfc_priv to fc_rport_priv. Use #define temporarily to make both names equivalent until a subsequent patch splits them. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 18 ++++++------- drivers/scsi/libfc/fc_lport.c | 2 +- drivers/scsi/libfc/fc_rport.c | 60 +++++++++++++++++++++---------------------- include/scsi/libfc.h | 10 +++++++- 4 files changed, 49 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 6fabf66972b9..4c8d893af7bd 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -65,7 +65,7 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, { const struct fc_disc *disc = &lport->disc; struct fc_rport *rport, *found = NULL; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; int disc_found = 0; list_for_each_entry(rdata, &disc->rports, peers) { @@ -94,7 +94,7 @@ void fc_disc_stop_rports(struct fc_disc *disc) { struct fc_lport *lport; struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata, *next; + struct fc_rport_priv *rdata, *next; lport = disc->lport; @@ -126,7 +126,7 @@ static void fc_disc_rport_callback(struct fc_lport *lport, struct fc_rport *rport, enum fc_rport_event event) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_disc *disc = &lport->disc; FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, @@ -170,7 +170,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, { struct fc_lport *lport; struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; struct fc_els_rscn *rp; struct fc_els_rscn_page *pp; struct fc_seq_els_data rjt_data; @@ -309,7 +309,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, static void fc_disc_restart(struct fc_disc *disc) { struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata, *next; + struct fc_rport_priv *rdata, *next; struct fc_lport *lport = disc->lport; FC_DISC_DBG(disc, "Restarting discovery\n"); @@ -400,7 +400,7 @@ static int fc_disc_new_target(struct fc_disc *disc, struct fc_rport_identifiers *ids) { struct fc_lport *lport = disc->lport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; int error = 0; if (rport && ids->port_name) { @@ -458,7 +458,7 @@ static int fc_disc_new_target(struct fc_disc *disc, static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport) { struct fc_lport *lport = disc->lport; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; list_del(&rdata->peers); lport->tt.rport_logoff(rport); } @@ -580,7 +580,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) int error = 0; struct fc_disc_port dp; struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; lport = disc->lport; @@ -774,7 +774,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) { struct fc_lport *lport; struct fc_rport *new_rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; lport = disc->lport; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index ca8ea264b684..f7f328f952a5 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1306,7 +1306,7 @@ static struct fc_rport_operations fc_lport_rport_ops = { static void fc_lport_enter_dns(struct fc_lport *lport) { struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; struct fc_disc_port dp; dp.ids.port_id = FC_FID_DIR_SERV; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 90cc90dd3b5d..5f8f437e76b3 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -96,7 +96,7 @@ static void fc_rport_rogue_destroy(struct device *dev) struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) { struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL); if (!rport) @@ -144,7 +144,7 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) static const char *fc_rport_state(struct fc_rport *rport) { const char *cp; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; cp = fc_rport_state_names[rdata->rp_state]; if (!cp) @@ -199,7 +199,7 @@ static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp, static void fc_rport_state_enter(struct fc_rport *rport, enum fc_rport_state new) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; if (rdata->rp_state != new) rdata->retries = 0; rdata->rp_state = new; @@ -208,8 +208,8 @@ static void fc_rport_state_enter(struct fc_rport *rport, static void fc_rport_work(struct work_struct *work) { u32 port_id; - struct fc_rport_libfc_priv *rdata = - container_of(work, struct fc_rport_libfc_priv, event_work); + struct fc_rport_priv *rdata = + container_of(work, struct fc_rport_priv, event_work); enum fc_rport_event event; enum fc_rport_trans_state trans_state; struct fc_lport *lport = rdata->local_port; @@ -222,7 +222,7 @@ static void fc_rport_work(struct work_struct *work) if (event == RPORT_EV_CREATED) { struct fc_rport *new_rport; - struct fc_rport_libfc_priv *new_rdata; + struct fc_rport_priv *new_rdata; struct fc_rport_identifiers ids; ids.port_id = rport->port_id; @@ -299,7 +299,7 @@ static void fc_rport_work(struct work_struct *work) */ int fc_rport_login(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; mutex_lock(&rdata->rp_mutex); @@ -329,7 +329,7 @@ int fc_rport_login(struct fc_rport *rport) static void fc_rport_enter_delete(struct fc_rport *rport, enum fc_rport_event event) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; if (rdata->rp_state == RPORT_ST_DELETE) return; @@ -353,7 +353,7 @@ static void fc_rport_enter_delete(struct fc_rport *rport, */ int fc_rport_logoff(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; mutex_lock(&rdata->rp_mutex); @@ -387,7 +387,7 @@ out: */ static void fc_rport_enter_ready(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; fc_rport_state_enter(rport, RPORT_ST_READY); @@ -400,7 +400,7 @@ static void fc_rport_enter_ready(struct fc_rport *rport) /** * fc_rport_timeout() - Handler for the retry_work timer. - * @work: The work struct of the fc_rport_libfc_priv + * @work: The work struct of the fc_rport_priv * * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* @@ -408,8 +408,8 @@ static void fc_rport_enter_ready(struct fc_rport *rport) */ static void fc_rport_timeout(struct work_struct *work) { - struct fc_rport_libfc_priv *rdata = - container_of(work, struct fc_rport_libfc_priv, retry_work.work); + struct fc_rport_priv *rdata = + container_of(work, struct fc_rport_priv, retry_work.work); struct fc_rport *rport = PRIV_TO_RPORT(rdata); mutex_lock(&rdata->rp_mutex); @@ -446,7 +446,7 @@ static void fc_rport_timeout(struct work_struct *work) */ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; FC_RPORT_DBG(rport, "Error %ld in state %s, retries %d\n", PTR_ERR(fp), fc_rport_state(rport), rdata->retries); @@ -480,7 +480,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) */ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; unsigned long delay = FC_DEF_E_D_TOV; /* make sure this isn't an FC_EX_CLOSED error, never retry those */ @@ -515,7 +515,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg) { struct fc_rport *rport = rp_arg; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_els_flogi *plp = NULL; unsigned int tov; @@ -586,7 +586,7 @@ err: */ static void fc_rport_enter_plogi(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; @@ -624,7 +624,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg) { struct fc_rport *rport = rp_arg; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct { struct fc_els_prli prli; struct fc_els_spp spp; @@ -694,7 +694,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg) { struct fc_rport *rport = rp_arg; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; u8 op; mutex_lock(&rdata->rp_mutex); @@ -738,7 +738,7 @@ err: */ static void fc_rport_enter_prli(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct { struct fc_els_prli prli; @@ -780,7 +780,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg) { struct fc_rport *rport = rp_arg; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; u8 op; mutex_lock(&rdata->rp_mutex); @@ -841,7 +841,7 @@ err: static void fc_rport_enter_rtv(struct fc_rport *rport) { struct fc_frame *fp; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; FC_RPORT_DBG(rport, "Port entered RTV state from %s state\n", @@ -871,7 +871,7 @@ static void fc_rport_enter_rtv(struct fc_rport *rport) */ static void fc_rport_enter_logo(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; @@ -907,7 +907,7 @@ static void fc_rport_enter_logo(struct fc_rport *rport) void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame_header *fh; @@ -967,7 +967,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, static void fc_rport_recv_plogi_req(struct fc_rport *rport, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame *fp = rx_fp; struct fc_exch *ep; @@ -1090,7 +1090,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, static void fc_rport_recv_prli_req(struct fc_rport *rport, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_exch *ep; struct fc_frame *fp; @@ -1242,7 +1242,7 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, struct fc_frame *fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame_header *fh; @@ -1278,7 +1278,7 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, struct fc_frame *fp) { struct fc_frame_header *fh; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; fh = fc_frame_header_get(fp); @@ -1342,8 +1342,8 @@ EXPORT_SYMBOL(fc_destroy_rport); void fc_rport_terminate_io(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; - struct fc_lport *lport = rdata->local_port; + struct fc_rport_libfc_priv *rp = rport->dd_data; + struct fc_lport *lport = rp->local_port; lport->tt.exch_mgr_reset(lport, 0, rport->port_id); lport->tt.exch_mgr_reset(lport, rport->port_id, 0); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 53b38814d38a..aa219514c96b 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -77,7 +77,7 @@ do { \ #define FC_RPORT_DBG(rport, fmt, args...) \ do { \ - struct fc_rport_libfc_priv *rdata = rport->dd_data; \ + struct fc_rport_priv *rdata = rport->dd_data; \ struct fc_lport *lport = rdata->local_port; \ FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ } while (0) @@ -177,6 +177,14 @@ enum fc_rport_event { RPORT_EV_LOGO }; +/* + * Temporary definition to prepare for split off from fc_rport_libfc_priv + * of a separately-allocated structure called fc_rport_priv. This will + * be the primary object for the discovery and rport state machines. + * This definition is just to make this patch series easier to review. + */ +#define fc_rport_priv fc_rport_libfc_priv + struct fc_rport_operations { void (*event_callback)(struct fc_lport *, struct fc_rport *, enum fc_rport_event); -- cgit v1.2.3 From 795d86f55ec3bf6280dda368f208943f1fb7d366 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:39 -0700 Subject: [SCSI] libfc: change interface for rport_create The interface for lport->tt.rport_create() takes a fc_disc_port arg, which is unnatural for most calls. The only reason for this was to avoid passing in the local port as an argument, but otherwise added to complexity. Simplify by just using lport and fc_rport_identifiers. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 31 ++++++++++++------------------- drivers/scsi/libfc/fc_lport.c | 26 ++++++++++++-------------- drivers/scsi/libfc/fc_rport.c | 17 +++++++++-------- include/scsi/libfc.h | 5 ++--- 4 files changed, 35 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 4c8d893af7bd..ecc625c20520 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -428,13 +428,7 @@ static int fc_disc_new_target(struct fc_disc *disc, if (!rport) { rport = lport->tt.rport_lookup(lport, ids->port_id); if (!rport) { - struct fc_disc_port dp; - dp.lp = lport; - dp.ids.port_id = ids->port_id; - dp.ids.port_name = ids->port_name; - dp.ids.node_name = ids->node_name; - dp.ids.roles = ids->roles; - rport = lport->tt.rport_create(&dp); + rport = lport->tt.rport_create(lport, ids); } if (!rport) error = -ENOMEM; @@ -578,7 +572,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) size_t plen; size_t tlen; int error = 0; - struct fc_disc_port dp; + struct fc_rport_identifiers ids; struct fc_rport *rport; struct fc_rport_priv *rdata; @@ -621,15 +615,14 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) * After the first time through the loop, things return to "normal". */ while (plen >= sizeof(*np)) { - dp.lp = lport; - dp.ids.port_id = ntoh24(np->fp_fid); - dp.ids.port_name = ntohll(np->fp_wwpn); - dp.ids.node_name = -1; - dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; - - if ((dp.ids.port_id != fc_host_port_id(lport->host)) && - (dp.ids.port_name != lport->wwpn)) { - rport = lport->tt.rport_create(&dp); + ids.port_id = ntoh24(np->fp_fid); + ids.port_name = ntohll(np->fp_wwpn); + ids.node_name = -1; + ids.roles = FC_RPORT_ROLE_UNKNOWN; + + if (ids.port_id != fc_host_port_id(lport->host) && + ids.port_name != lport->wwpn) { + rport = lport->tt.rport_create(lport, &ids); if (rport) { rdata = rport->dd_data; rdata->ops = &fc_disc_rport_ops; @@ -640,7 +633,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) } else printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " - "(%6x)\n", dp.ids.port_id); + "(%6x)\n", ids.port_id); } if (np->fp_flags & FC_NS_FID_LAST) { @@ -781,7 +774,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) if (dp->ids.port_id == fc_host_port_id(lport->host)) goto out; - new_rport = lport->tt.rport_create(dp); + new_rport = lport->tt.rport_create(lport, &dp->ids); if (new_rport) { rdata = new_rport->dd_data; rdata->ops = &fc_disc_rport_ops; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index f7f328f952a5..a78161cf1811 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -211,20 +211,19 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, u32 remote_fid, u64 remote_wwpn, u64 remote_wwnn) { - struct fc_disc_port dp; + struct fc_rport_identifiers ids; - dp.lp = lport; - dp.ids.port_id = remote_fid; - dp.ids.port_name = remote_wwpn; - dp.ids.node_name = remote_wwnn; - dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; + ids.port_id = remote_fid; + ids.port_name = remote_wwpn; + ids.node_name = remote_wwnn; + ids.roles = FC_RPORT_ROLE_UNKNOWN; if (lport->ptp_rp) { lport->tt.rport_logoff(lport->ptp_rp); lport->ptp_rp = NULL; } - lport->ptp_rp = lport->tt.rport_create(&dp); + lport->ptp_rp = lport->tt.rport_create(lport, &ids); lport->tt.rport_login(lport->ptp_rp); @@ -1307,20 +1306,19 @@ static void fc_lport_enter_dns(struct fc_lport *lport) { struct fc_rport *rport; struct fc_rport_priv *rdata; - struct fc_disc_port dp; + struct fc_rport_identifiers ids; - dp.ids.port_id = FC_FID_DIR_SERV; - dp.ids.port_name = -1; - dp.ids.node_name = -1; - dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; - dp.lp = lport; + ids.port_id = FC_FID_DIR_SERV; + ids.port_name = -1; + ids.node_name = -1; + ids.roles = FC_RPORT_ROLE_UNKNOWN; FC_LPORT_DBG(lport, "Entered DNS state from %s state\n", fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_DNS); - rport = lport->tt.rport_create(&dp); + rport = lport->tt.rport_create(lport, &ids); if (!rport) goto err; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 5f8f437e76b3..2fbc94aaf343 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -93,7 +93,8 @@ static void fc_rport_rogue_destroy(struct device *dev) kfree(rport); } -struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) +struct fc_rport *fc_rport_rogue_create(struct fc_lport *lport, + struct fc_rport_identifiers *ids) { struct fc_rport *rport; struct fc_rport_priv *rdata; @@ -105,10 +106,10 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) rdata = RPORT_TO_PRIV(rport); rport->dd_data = rdata; - rport->port_id = dp->ids.port_id; - rport->port_name = dp->ids.port_name; - rport->node_name = dp->ids.node_name; - rport->roles = dp->ids.roles; + rport->port_id = ids->port_id; + rport->port_name = ids->port_name; + rport->node_name = ids->node_name; + rport->roles = ids->roles; rport->maxframe_size = FC_MIN_MAX_PAYLOAD; /* * Note: all this libfc rogue rport code will be removed for @@ -118,14 +119,14 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) rport->dev.release = fc_rport_rogue_destroy; mutex_init(&rdata->rp_mutex); - rdata->local_port = dp->lp; + rdata->local_port = lport; rdata->trans_state = FC_PORTSTATE_ROGUE; rdata->rp_state = RPORT_ST_INIT; rdata->event = RPORT_EV_NONE; rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; rdata->ops = NULL; - rdata->e_d_tov = dp->lp->e_d_tov; - rdata->r_a_tov = dp->lp->r_a_tov; + rdata->e_d_tov = lport->e_d_tov; + rdata->r_a_tov = lport->r_a_tov; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); /* diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index aa219514c96b..d888cbecd72e 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -227,8 +227,6 @@ struct fc_rport_libfc_priv { #define RPORT_TO_PRIV(x) \ (struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport)); -struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *); - static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) { rport->node_name = wwnn; @@ -569,7 +567,8 @@ struct libfc_function_template { /* * Create a remote port */ - struct fc_rport *(*rport_create)(struct fc_disc_port *); + struct fc_rport *(*rport_create)(struct fc_lport *, + struct fc_rport_identifiers *); /* * Initiates the RP state machine. It is called from the LP module. -- cgit v1.2.3 From 922aa210bcad4b34a7bb98ec9d318b7e59e7a5ca Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:45 -0700 Subject: [SCSI] libfc: fix RPORT_TO_PRIV and PRIV_TO_RPORT() macros. These macros introduce extra undesirable semicolons that keep them from being used in expressions, and they don't protect against being passed an expression. Add parens and remove the semicolons. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- include/scsi/libfc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index d888cbecd72e..2fdd8ac12b89 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -223,9 +223,9 @@ struct fc_rport_libfc_priv { }; #define PRIV_TO_RPORT(x) \ - (struct fc_rport *)((void *)x - sizeof(struct fc_rport)); + ((struct fc_rport *)((void *)(x) - sizeof(struct fc_rport))) #define RPORT_TO_PRIV(x) \ - (struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport)); + ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport))) static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) { -- cgit v1.2.3 From 9fb9d32831fd687e427ec5b147bb690f468b99a0 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:50 -0700 Subject: [SCSI] libfc: make fc_rport_priv the primary rport interface. The rport and discovery modules deal with remote ports before fc_remote_port_add() can be done, because the full set of rport identifiers is not known at early stages. In preparation for splitting the fc_rport/fc_rport_priv allocation, make fc_rport_priv the primary interface for the remote port and discovery engines. The FCP / SCSI layers still deal with fc_rport and fc_rport_libfc_priv, however. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 95 ++++------- drivers/scsi/libfc/fc_elsct.c | 4 +- drivers/scsi/libfc/fc_fcp.c | 2 +- drivers/scsi/libfc/fc_lport.c | 26 +-- drivers/scsi/libfc/fc_rport.c | 364 ++++++++++++++++++++---------------------- include/scsi/fc_encode.h | 7 +- include/scsi/libfc.h | 26 +-- 7 files changed, 245 insertions(+), 279 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index ecc625c20520..448ffc388656 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -49,7 +49,6 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static int fc_disc_new_target(struct fc_disc *, struct fc_rport *, struct fc_rport_identifiers *); -static void fc_disc_del_target(struct fc_disc *, struct fc_rport *); static void fc_disc_done(struct fc_disc *); static void fc_disc_timeout(struct work_struct *); static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); @@ -60,27 +59,19 @@ static void fc_disc_restart(struct fc_disc *); * @lport: Fibre Channel host port instance * @port_id: remote port port_id to match */ -struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, - u32 port_id) +struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, + u32 port_id) { const struct fc_disc *disc = &lport->disc; - struct fc_rport *rport, *found = NULL; + struct fc_rport *rport; struct fc_rport_priv *rdata; - int disc_found = 0; list_for_each_entry(rdata, &disc->rports, peers) { rport = PRIV_TO_RPORT(rdata); - if (rport->port_id == port_id) { - disc_found = 1; - found = rport; - break; - } + if (rport->port_id == port_id) + return rdata; } - - if (!disc_found) - found = NULL; - - return found; + return NULL; } /** @@ -93,21 +84,18 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, void fc_disc_stop_rports(struct fc_disc *disc) { struct fc_lport *lport; - struct fc_rport *rport; struct fc_rport_priv *rdata, *next; lport = disc->lport; mutex_lock(&disc->disc_mutex); list_for_each_entry_safe(rdata, next, &disc->rports, peers) { - rport = PRIV_TO_RPORT(rdata); list_del(&rdata->peers); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } list_for_each_entry_safe(rdata, next, &disc->rogue_rports, peers) { - rport = PRIV_TO_RPORT(rdata); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } mutex_unlock(&disc->disc_mutex); @@ -116,18 +104,18 @@ void fc_disc_stop_rports(struct fc_disc *disc) /** * fc_disc_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event - * @rport: The rport which the event has occured on + * @rdata: private remote port data * @event: The event that occured * * Locking Note: The rport lock should not be held when calling * this function. */ static void fc_disc_rport_callback(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *rdata, enum fc_rport_event event) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_disc *disc = &lport->disc; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, rport->port_id); @@ -169,7 +157,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_disc *disc) { struct fc_lport *lport; - struct fc_rport *rport; struct fc_rport_priv *rdata; struct fc_els_rscn *rp; struct fc_els_rscn_page *pp; @@ -249,11 +236,10 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, redisc, lport->state, disc->pending); list_for_each_entry_safe(dp, next, &disc_ports, peers) { list_del(&dp->peers); - rport = lport->tt.rport_lookup(lport, dp->ids.port_id); - if (rport) { - rdata = rport->dd_data; + rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); + if (rdata) { list_del(&rdata->peers); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } fc_disc_single(disc, dp); } @@ -308,16 +294,14 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, */ static void fc_disc_restart(struct fc_disc *disc) { - struct fc_rport *rport; struct fc_rport_priv *rdata, *next; struct fc_lport *lport = disc->lport; FC_DISC_DBG(disc, "Restarting discovery\n"); list_for_each_entry_safe(rdata, next, &disc->rports, peers) { - rport = PRIV_TO_RPORT(rdata); list_del(&rdata->peers); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } disc->requested = 1; @@ -335,6 +319,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, enum fc_disc_event), struct fc_lport *lport) { + struct fc_rport_priv *rdata; struct fc_rport *rport; struct fc_rport_identifiers ids; struct fc_disc *disc = &lport->disc; @@ -362,8 +347,9 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, * Handle point-to-point mode as a simple discovery * of the remote port. Yucky, yucky, yuck, yuck! */ - rport = disc->lport->ptp_rp; - if (rport) { + rdata = disc->lport->ptp_rp; + if (rdata) { + rport = PRIV_TO_RPORT(rdata); ids.port_id = rport->port_id; ids.port_name = rport->port_name; ids.node_name = rport->node_name; @@ -418,7 +404,9 @@ static int fc_disc_new_target(struct fc_disc *disc, * assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ - fc_disc_del_target(disc, rport); + rdata = rport->dd_data; + list_del(&rdata->peers); + lport->tt.rport_logoff(rdata); rport = NULL; } } @@ -426,37 +414,26 @@ static int fc_disc_new_target(struct fc_disc *disc, ids->port_id != fc_host_port_id(lport->host) && ids->port_name != lport->wwpn) { if (!rport) { - rport = lport->tt.rport_lookup(lport, ids->port_id); + rdata = lport->tt.rport_lookup(lport, ids->port_id); if (!rport) { - rport = lport->tt.rport_create(lport, ids); + rdata = lport->tt.rport_create(lport, ids); } - if (!rport) + if (!rdata) error = -ENOMEM; + else + rport = PRIV_TO_RPORT(rdata); } if (rport) { rdata = rport->dd_data; rdata->ops = &fc_disc_rport_ops; rdata->rp_state = RPORT_ST_INIT; list_add_tail(&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login(rport); + lport->tt.rport_login(rdata); } } return error; } -/** - * fc_disc_del_target() - Delete a target - * @disc: FC discovery context - * @rport: The remote port to be removed - */ -static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport) -{ - struct fc_lport *lport = disc->lport; - struct fc_rport_priv *rdata = rport->dd_data; - list_del(&rdata->peers); - lport->tt.rport_logoff(rport); -} - /** * fc_disc_done() - Discovery has been completed * @disc: FC discovery context @@ -573,7 +550,6 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) size_t tlen; int error = 0; struct fc_rport_identifiers ids; - struct fc_rport *rport; struct fc_rport_priv *rdata; lport = disc->lport; @@ -622,14 +598,13 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) if (ids.port_id != fc_host_port_id(lport->host) && ids.port_name != lport->wwpn) { - rport = lport->tt.rport_create(lport, &ids); - if (rport) { - rdata = rport->dd_data; + rdata = lport->tt.rport_create(lport, &ids); + if (rdata) { rdata->ops = &fc_disc_rport_ops; rdata->local_port = lport; list_add_tail(&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login(rport); + lport->tt.rport_login(rdata); } else printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " @@ -766,7 +741,6 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) { struct fc_lport *lport; - struct fc_rport *new_rport; struct fc_rport_priv *rdata; lport = disc->lport; @@ -774,13 +748,12 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) if (dp->ids.port_id == fc_host_port_id(lport->host)) goto out; - new_rport = lport->tt.rport_create(lport, &dp->ids); - if (new_rport) { - rdata = new_rport->dd_data; + rdata = lport->tt.rport_create(lport, &dp->ids); + if (rdata) { rdata->ops = &fc_disc_rport_ops; kfree(dp); list_add_tail(&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login(new_rport); + lport->tt.rport_login(rdata); } return; out: diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 5878b34bff18..2b8a3bbc0399 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -32,7 +32,7 @@ * fc_elsct_send - sends ELS/CT frame */ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *rdata, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *, @@ -47,7 +47,7 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, /* ELS requests */ if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) - rc = fc_els_fill(lport, rport, fp, op, &r_ctl, &did, &fh_type); + rc = fc_els_fill(lport, rdata, fp, op, &r_ctl, &did, &fh_type); else /* CT requests */ rc = fc_ct_fill(lport, fp, op, &r_ctl, &did, &fh_type); diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 7d5ffcbbf39b..a622096eb315 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1308,7 +1308,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, fc_host_port_id(rp->local_port->host), FC_TYPE_ELS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - if (lp->tt.elsct_send(lp, rport, fp, ELS_REC, fc_fcp_rec_resp, + if (lp->tt.elsct_send(lp, rport->dd_data, fp, ELS_REC, fc_fcp_rec_resp, fsp, jiffies_to_msecs(FC_SCSI_REC_TOV))) { fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ return; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index a78161cf1811..3c15abd35ffa 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -133,16 +133,18 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) /** * fc_lport_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event - * @rport: The rport which the event has occured on + * @rdata: private remote port data * @event: The event that occured * * Locking Note: The rport lock should not be held when calling * this function. */ static void fc_lport_rport_callback(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *rdata, enum fc_rport_event event) { + struct fc_rport *rport = PRIV_TO_RPORT(rdata); + FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, rport->port_id); @@ -151,7 +153,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, if (rport->port_id == FC_FID_DIR_SERV) { mutex_lock(&lport->lp_mutex); if (lport->state == LPORT_ST_DNS) { - lport->dns_rp = rport; + lport->dns_rp = rdata; fc_lport_enter_rpn_id(lport); } else { FC_LPORT_DBG(lport, "Received an CREATED event " @@ -160,7 +162,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, "in the DNS state, it's in the " "%d state", rport->port_id, lport->state); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } mutex_unlock(&lport->lp_mutex); } else @@ -832,7 +834,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, { struct fc_frame_header *fh = fc_frame_header_get(fp); void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *); - struct fc_rport *rport; + struct fc_rport_priv *rdata; u32 s_id; u32 d_id; struct fc_seq_els_data rjt_data; @@ -888,9 +890,9 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, s_id = ntoh24(fh->fh_s_id); d_id = ntoh24(fh->fh_d_id); - rport = lport->tt.rport_lookup(lport, s_id); - if (rport) - lport->tt.rport_recv_req(sp, fp, rport); + rdata = lport->tt.rport_lookup(lport, s_id); + if (rdata) + lport->tt.rport_recv_req(sp, fp, rdata); else { rjt_data.fp = NULL; rjt_data.reason = ELS_RJT_UNAB; @@ -1304,7 +1306,6 @@ static struct fc_rport_operations fc_lport_rport_ops = { */ static void fc_lport_enter_dns(struct fc_lport *lport) { - struct fc_rport *rport; struct fc_rport_priv *rdata; struct fc_rport_identifiers ids; @@ -1318,13 +1319,12 @@ static void fc_lport_enter_dns(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_DNS); - rport = lport->tt.rport_create(lport, &ids); - if (!rport) + rdata = lport->tt.rport_create(lport, &ids); + if (!rdata) goto err; - rdata = rport->dd_data; rdata->ops = &fc_lport_rport_ops; - lport->tt.rport_login(rport); + lport->tt.rport_login(rdata); return; err: diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 2fbc94aaf343..13d3d758fb0e 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -57,23 +57,23 @@ struct workqueue_struct *rport_event_queue; -static void fc_rport_enter_plogi(struct fc_rport *); -static void fc_rport_enter_prli(struct fc_rport *); -static void fc_rport_enter_rtv(struct fc_rport *); -static void fc_rport_enter_ready(struct fc_rport *); -static void fc_rport_enter_logo(struct fc_rport *); +static void fc_rport_enter_plogi(struct fc_rport_priv *); +static void fc_rport_enter_prli(struct fc_rport_priv *); +static void fc_rport_enter_rtv(struct fc_rport_priv *); +static void fc_rport_enter_ready(struct fc_rport_priv *); +static void fc_rport_enter_logo(struct fc_rport_priv *); -static void fc_rport_recv_plogi_req(struct fc_rport *, +static void fc_rport_recv_plogi_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_prli_req(struct fc_rport *, +static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_prlo_req(struct fc_rport *, +static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_logo_req(struct fc_rport *, +static void fc_rport_recv_logo_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); static void fc_rport_timeout(struct work_struct *); -static void fc_rport_error(struct fc_rport *, struct fc_frame *); -static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *); +static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); +static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *); static void fc_rport_work(struct work_struct *); static const char *fc_rport_state_names[] = { @@ -89,12 +89,14 @@ static const char *fc_rport_state_names[] = { static void fc_rport_rogue_destroy(struct device *dev) { struct fc_rport *rport = dev_to_rport(dev); - FC_RPORT_DBG(rport, "Destroying rogue rport\n"); + struct fc_rport_priv *rdata = RPORT_TO_PRIV(rport); + + FC_RPORT_DBG(rdata, "Destroying rogue rport\n"); kfree(rport); } -struct fc_rport *fc_rport_rogue_create(struct fc_lport *lport, - struct fc_rport_identifiers *ids) +struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, + struct fc_rport_identifiers *ids) { struct fc_rport *rport; struct fc_rport_priv *rdata; @@ -135,17 +137,16 @@ struct fc_rport *fc_rport_rogue_create(struct fc_lport *lport, */ INIT_LIST_HEAD(&rdata->peers); - return rport; + return rdata; } /** * fc_rport_state() - return a string for the state the rport is in - * @rport: The rport whose state we want to get a string for + * @rdata: remote port private data */ -static const char *fc_rport_state(struct fc_rport *rport) +static const char *fc_rport_state(struct fc_rport_priv *rdata) { const char *cp; - struct fc_rport_priv *rdata = rport->dd_data; cp = fc_rport_state_names[rdata->rp_state]; if (!cp) @@ -192,15 +193,14 @@ static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp, /** * fc_rport_state_enter() - Change the rport's state - * @rport: The rport whose state should change + * @rdata: The rport whose state should change * @new: The new state of the rport * * Locking Note: Called with the rport lock held */ -static void fc_rport_state_enter(struct fc_rport *rport, +static void fc_rport_state_enter(struct fc_rport_priv *rdata, enum fc_rport_state new) { - struct fc_rport_priv *rdata = rport->dd_data; if (rdata->rp_state != new) rdata->retries = 0; rdata->rp_state = new; @@ -255,7 +255,7 @@ static void fc_rport_work(struct work_struct *work) INIT_LIST_HEAD(&new_rdata->peers); INIT_WORK(&new_rdata->event_work, fc_rport_work); - fc_rport_state_enter(new_rport, RPORT_ST_READY); + fc_rport_state_enter(new_rdata, RPORT_ST_READY); } else { printk(KERN_WARNING "libfc: Failed to allocate " " memory for rport (%6x)\n", ids.port_id); @@ -263,20 +263,20 @@ static void fc_rport_work(struct work_struct *work) } if (rport->port_id != FC_FID_DIR_SERV) if (rport_ops->event_callback) - rport_ops->event_callback(lport, rport, + rport_ops->event_callback(lport, rdata, RPORT_EV_FAILED); put_device(&rport->dev); rport = new_rport; rdata = new_rport->dd_data; if (rport_ops->event_callback) - rport_ops->event_callback(lport, rport, event); + rport_ops->event_callback(lport, rdata, event); } else if ((event == RPORT_EV_FAILED) || (event == RPORT_EV_LOGO) || (event == RPORT_EV_STOP)) { trans_state = rdata->trans_state; mutex_unlock(&rdata->rp_mutex); if (rport_ops->event_callback) - rport_ops->event_callback(lport, rport, event); + rport_ops->event_callback(lport, rdata, event); cancel_delayed_work_sync(&rdata->retry_work); if (trans_state == FC_PORTSTATE_ROGUE) put_device(&rport->dev); @@ -292,21 +292,19 @@ static void fc_rport_work(struct work_struct *work) /** * fc_rport_login() - Start the remote port login state machine - * @rport: Fibre Channel remote port + * @rdata: private remote port * * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. */ -int fc_rport_login(struct fc_rport *rport) +int fc_rport_login(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; - mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Login to port\n"); + FC_RPORT_DBG(rdata, "Login to port\n"); - fc_rport_enter_plogi(rport); + fc_rport_enter_plogi(rdata); mutex_unlock(&rdata->rp_mutex); @@ -315,7 +313,7 @@ int fc_rport_login(struct fc_rport *rport) /** * fc_rport_enter_delete() - schedule a remote port to be deleted. - * @rport: Fibre Channel remote port + * @rdata: private remote port * @event: event to report as the reason for deletion * * Locking Note: Called with the rport lock held. @@ -327,17 +325,15 @@ int fc_rport_login(struct fc_rport *rport) * Since we have the mutex, even if fc_rport_work() is already started, * it'll see the new event. */ -static void fc_rport_enter_delete(struct fc_rport *rport, +static void fc_rport_enter_delete(struct fc_rport_priv *rdata, enum fc_rport_event event) { - struct fc_rport_priv *rdata = rport->dd_data; - if (rdata->rp_state == RPORT_ST_DELETE) return; - FC_RPORT_DBG(rport, "Delete port\n"); + FC_RPORT_DBG(rdata, "Delete port\n"); - fc_rport_state_enter(rport, RPORT_ST_DELETE); + fc_rport_state_enter(rdata, RPORT_ST_DELETE); if (rdata->event == RPORT_EV_NONE) queue_work(rport_event_queue, &rdata->event_work); @@ -346,33 +342,31 @@ static void fc_rport_enter_delete(struct fc_rport *rport, /** * fc_rport_logoff() - Logoff and remove an rport - * @rport: Fibre Channel remote port to be removed + * @rdata: private remote port * * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. */ -int fc_rport_logoff(struct fc_rport *rport) +int fc_rport_logoff(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; - mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Remove port\n"); + FC_RPORT_DBG(rdata, "Remove port\n"); if (rdata->rp_state == RPORT_ST_DELETE) { - FC_RPORT_DBG(rport, "Port in Delete state, not removing\n"); + FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); mutex_unlock(&rdata->rp_mutex); goto out; } - fc_rport_enter_logo(rport); + fc_rport_enter_logo(rdata); /* * Change the state to Delete so that we discard * the response. */ - fc_rport_enter_delete(rport, RPORT_EV_STOP); + fc_rport_enter_delete(rdata, RPORT_EV_STOP); mutex_unlock(&rdata->rp_mutex); out: @@ -381,18 +375,16 @@ out: /** * fc_rport_enter_ready() - The rport is ready - * @rport: Fibre Channel remote port that is ready + * @rdata: private remote port * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_ready(struct fc_rport *rport) +static void fc_rport_enter_ready(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; - - fc_rport_state_enter(rport, RPORT_ST_READY); + fc_rport_state_enter(rdata, RPORT_ST_READY); - FC_RPORT_DBG(rport, "Port is Ready\n"); + FC_RPORT_DBG(rdata, "Port is Ready\n"); if (rdata->event == RPORT_EV_NONE) queue_work(rport_event_queue, &rdata->event_work); @@ -411,22 +403,21 @@ static void fc_rport_timeout(struct work_struct *work) { struct fc_rport_priv *rdata = container_of(work, struct fc_rport_priv, retry_work.work); - struct fc_rport *rport = PRIV_TO_RPORT(rdata); mutex_lock(&rdata->rp_mutex); switch (rdata->rp_state) { case RPORT_ST_PLOGI: - fc_rport_enter_plogi(rport); + fc_rport_enter_plogi(rdata); break; case RPORT_ST_PRLI: - fc_rport_enter_prli(rport); + fc_rport_enter_prli(rdata); break; case RPORT_ST_RTV: - fc_rport_enter_rtv(rport); + fc_rport_enter_rtv(rdata); break; case RPORT_ST_LOGO: - fc_rport_enter_logo(rport); + fc_rport_enter_logo(rdata); break; case RPORT_ST_READY: case RPORT_ST_INIT: @@ -439,27 +430,25 @@ static void fc_rport_timeout(struct work_struct *work) /** * fc_rport_error() - Error handler, called once retries have been exhausted - * @rport: The fc_rport object + * @rdata: private remote port * @fp: The frame pointer * * Locking Note: The rport lock is expected to be held before * calling this routine */ -static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) +static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) { - struct fc_rport_priv *rdata = rport->dd_data; - - FC_RPORT_DBG(rport, "Error %ld in state %s, retries %d\n", - PTR_ERR(fp), fc_rport_state(rport), rdata->retries); + FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n", + PTR_ERR(fp), fc_rport_state(rdata), rdata->retries); switch (rdata->rp_state) { case RPORT_ST_PLOGI: case RPORT_ST_PRLI: case RPORT_ST_LOGO: - fc_rport_enter_delete(rport, RPORT_EV_FAILED); + fc_rport_enter_delete(rdata, RPORT_EV_FAILED); break; case RPORT_ST_RTV: - fc_rport_enter_ready(rport); + fc_rport_enter_ready(rdata); break; case RPORT_ST_DELETE: case RPORT_ST_READY: @@ -470,7 +459,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) /** * fc_rport_error_retry() - Error handler when retries are desired - * @rport: The fc_rport object + * @rdata: private remote port data * @fp: The frame pointer * * If the error was an exchange timeout retry immediately, @@ -479,18 +468,18 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) * Locking Note: The rport lock is expected to be held before * calling this routine */ -static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) +static void fc_rport_error_retry(struct fc_rport_priv *rdata, + struct fc_frame *fp) { - struct fc_rport_priv *rdata = rport->dd_data; unsigned long delay = FC_DEF_E_D_TOV; /* make sure this isn't an FC_EX_CLOSED error, never retry those */ if (PTR_ERR(fp) == -FC_EX_CLOSED) - return fc_rport_error(rport, fp); + return fc_rport_error(rdata, fp); if (rdata->retries < rdata->local_port->max_rport_retry_count) { - FC_RPORT_DBG(rport, "Error %ld in state %s, retrying\n", - PTR_ERR(fp), fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n", + PTR_ERR(fp), fc_rport_state(rdata)); rdata->retries++; /* no additional delay on exchange timeouts */ if (PTR_ERR(fp) == -FC_EX_TIMEOUT) @@ -499,24 +488,24 @@ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) return; } - return fc_rport_error(rport, fp); + return fc_rport_error(rdata, fp); } /** * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response * @sp: current sequence in the PLOGI exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Locking Note: This function will be called without the rport lock * held, but it will lock, call an _enter_* function or fc_rport_error * and then unlock the rport. */ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) + void *rdata_arg) { - struct fc_rport *rport = rp_arg; - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_els_flogi *plp = NULL; unsigned int tov; @@ -526,18 +515,18 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Received a PLOGI response\n"); + FC_RPORT_DBG(rdata, "Received a PLOGI response\n"); if (rdata->rp_state != RPORT_ST_PLOGI) { - FC_RPORT_DBG(rport, "Received a PLOGI response, but in state " - "%s\n", fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state " + "%s\n", fc_rport_state(rdata)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); goto err; } @@ -565,11 +554,11 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, * we skip PRLI and RTV and go straight to READY. */ if (rport->port_id >= FC_FID_DOM_MGR) - fc_rport_enter_ready(rport); + fc_rport_enter_ready(rdata); else - fc_rport_enter_prli(rport); + fc_rport_enter_prli(rdata); } else - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); out: fc_frame_free(fp); @@ -580,33 +569,33 @@ err: /** * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer - * @rport: Fibre Channel remote port to send PLOGI to + * @rdata: private remote port data * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_plogi(struct fc_rport *rport) +static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_frame *fp; - FC_RPORT_DBG(rport, "Port entered PLOGI state from %s state\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n", + fc_rport_state(rdata)); - fc_rport_state_enter(rport, RPORT_ST_PLOGI); + fc_rport_state_enter(rdata, RPORT_ST_PLOGI); rport->maxframe_size = FC_MIN_MAX_PAYLOAD; fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); if (!fp) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); return; } rdata->e_d_tov = lport->e_d_tov; - if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI, - fc_rport_plogi_resp, rport, lport->e_d_tov)) - fc_rport_error_retry(rport, fp); + if (!lport->tt.elsct_send(lport, rdata, fp, ELS_PLOGI, + fc_rport_plogi_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); else get_device(&rport->dev); } @@ -615,17 +604,17 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) * fc_rport_prli_resp() - Process Login (PRLI) response handler * @sp: current sequence in the PRLI exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Locking Note: This function will be called without the rport lock * held, but it will lock, call an _enter_* function or fc_rport_error * and then unlock the rport. */ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) + void *rdata_arg) { - struct fc_rport *rport = rp_arg; - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct { struct fc_els_prli prli; struct fc_els_spp spp; @@ -636,18 +625,18 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Received a PRLI response\n"); + FC_RPORT_DBG(rdata, "Received a PRLI response\n"); if (rdata->rp_state != RPORT_ST_PRLI) { - FC_RPORT_DBG(rport, "Received a PRLI response, but in state " - "%s\n", fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received a PRLI response, but in state " + "%s\n", fc_rport_state(rdata)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); goto err; } @@ -667,11 +656,11 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, roles |= FC_RPORT_ROLE_FCP_TARGET; rport->roles = roles; - fc_rport_enter_rtv(rport); + fc_rport_enter_rtv(rdata); } else { - FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n"); - fc_rport_enter_delete(rport, RPORT_EV_FAILED); + FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n"); + fc_rport_enter_delete(rdata, RPORT_EV_FAILED); } out: @@ -685,42 +674,42 @@ err: * fc_rport_logo_resp() - Logout (LOGO) response handler * @sp: current sequence in the LOGO exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Locking Note: This function will be called without the rport lock * held, but it will lock, call an _enter_* function or fc_rport_error * and then unlock the rport. */ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) + void *rdata_arg) { - struct fc_rport *rport = rp_arg; - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); u8 op; mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Received a LOGO response\n"); + FC_RPORT_DBG(rdata, "Received a LOGO response\n"); if (rdata->rp_state != RPORT_ST_LOGO) { - FC_RPORT_DBG(rport, "Received a LOGO response, but in state " - "%s\n", fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received a LOGO response, but in state " + "%s\n", fc_rport_state(rdata)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); goto err; } op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) { - fc_rport_enter_rtv(rport); + fc_rport_enter_rtv(rdata); } else { - FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n"); - fc_rport_enter_delete(rport, RPORT_EV_LOGO); + FC_RPORT_DBG(rdata, "Bad ELS response for LOGO command\n"); + fc_rport_enter_delete(rdata, RPORT_EV_LOGO); } out: @@ -732,14 +721,14 @@ err: /** * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer - * @rport: Fibre Channel remote port to send PRLI to + * @rdata: private remote port data * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_prli(struct fc_rport *rport) +static void fc_rport_enter_prli(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct { struct fc_els_prli prli; @@ -747,20 +736,20 @@ static void fc_rport_enter_prli(struct fc_rport *rport) } *pp; struct fc_frame *fp; - FC_RPORT_DBG(rport, "Port entered PRLI state from %s state\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n", + fc_rport_state(rdata)); - fc_rport_state_enter(rport, RPORT_ST_PRLI); + fc_rport_state_enter(rdata, RPORT_ST_PRLI); fp = fc_frame_alloc(lport, sizeof(*pp)); if (!fp) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); return; } - if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI, - fc_rport_prli_resp, rport, lport->e_d_tov)) - fc_rport_error_retry(rport, fp); + if (!lport->tt.elsct_send(lport, rdata, fp, ELS_PRLI, + fc_rport_prli_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); else get_device(&rport->dev); } @@ -769,7 +758,7 @@ static void fc_rport_enter_prli(struct fc_rport *rport) * fc_rport_els_rtv_resp() - Request Timeout Value response handler * @sp: current sequence in the RTV exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Many targets don't seem to support this. * @@ -778,26 +767,26 @@ static void fc_rport_enter_prli(struct fc_rport *rport) * and then unlock the rport. */ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) + void *rdata_arg) { - struct fc_rport *rport = rp_arg; - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); u8 op; mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Received a RTV response\n"); + FC_RPORT_DBG(rdata, "Received a RTV response\n"); if (rdata->rp_state != RPORT_ST_RTV) { - FC_RPORT_DBG(rport, "Received a RTV response, but in state " - "%s\n", fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received a RTV response, but in state " + "%s\n", fc_rport_state(rdata)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { - fc_rport_error(rport, fp); + fc_rport_error(rdata, fp); goto err; } @@ -823,7 +812,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, } } - fc_rport_enter_ready(rport); + fc_rport_enter_ready(rdata); out: fc_frame_free(fp); @@ -834,62 +823,62 @@ err: /** * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer - * @rport: Fibre Channel remote port to send RTV to + * @rdata: private remote port data * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_rtv(struct fc_rport *rport) +static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) { struct fc_frame *fp; - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); - FC_RPORT_DBG(rport, "Port entered RTV state from %s state\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n", + fc_rport_state(rdata)); - fc_rport_state_enter(rport, RPORT_ST_RTV); + fc_rport_state_enter(rdata, RPORT_ST_RTV); fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv)); if (!fp) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); return; } - if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV, - fc_rport_rtv_resp, rport, lport->e_d_tov)) - fc_rport_error_retry(rport, fp); + if (!lport->tt.elsct_send(lport, rdata, fp, ELS_RTV, + fc_rport_rtv_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); else get_device(&rport->dev); } /** * fc_rport_enter_logo() - Send Logout (LOGO) request to peer - * @rport: Fibre Channel remote port to send LOGO to + * @rdata: private remote port data * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_logo(struct fc_rport *rport) +static void fc_rport_enter_logo(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_frame *fp; - FC_RPORT_DBG(rport, "Port entered LOGO state from %s state\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n", + fc_rport_state(rdata)); - fc_rport_state_enter(rport, RPORT_ST_LOGO); + fc_rport_state_enter(rdata, RPORT_ST_LOGO); fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); if (!fp) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); return; } - if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO, - fc_rport_logo_resp, rport, lport->e_d_tov)) - fc_rport_error_retry(rport, fp); + if (!lport->tt.elsct_send(lport, rdata, fp, ELS_LOGO, + fc_rport_logo_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); else get_device(&rport->dev); } @@ -899,16 +888,15 @@ static void fc_rport_enter_logo(struct fc_rport *rport) * fc_rport_recv_req() - Receive a request from a rport * @sp: current sequence in the PLOGI exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. */ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_rport *rport) + struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame_header *fh; @@ -927,16 +915,16 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, op = fc_frame_payload_op(fp); switch (op) { case ELS_PLOGI: - fc_rport_recv_plogi_req(rport, sp, fp); + fc_rport_recv_plogi_req(rdata, sp, fp); break; case ELS_PRLI: - fc_rport_recv_prli_req(rport, sp, fp); + fc_rport_recv_prli_req(rdata, sp, fp); break; case ELS_PRLO: - fc_rport_recv_prlo_req(rport, sp, fp); + fc_rport_recv_prlo_req(rdata, sp, fp); break; case ELS_LOGO: - fc_rport_recv_logo_req(rport, sp, fp); + fc_rport_recv_logo_req(rdata, sp, fp); break; case ELS_RRQ: els_data.fp = fp; @@ -958,17 +946,17 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, /** * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request - * @rport: Fibre Channel remote port that initiated PLOGI + * @rdata: private remote port data * @sp: current sequence in the PLOGI exchange * @fp: PLOGI request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_plogi_req(struct fc_rport *rport, +static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_frame *fp = rx_fp; struct fc_exch *ep; @@ -984,13 +972,13 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, fh = fc_frame_header_get(fp); - FC_RPORT_DBG(rport, "Received PLOGI request while in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n", + fc_rport_state(rdata)); sid = ntoh24(fh->fh_s_id); pl = fc_frame_payload_get(fp, sizeof(*pl)); if (!pl) { - FC_RPORT_DBG(rport, "Received PLOGI too short\n"); + FC_RPORT_DBG(rdata, "Received PLOGI too short\n"); WARN_ON(1); /* XXX TBD: send reject? */ fc_frame_free(fp); @@ -1012,25 +1000,25 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, */ switch (rdata->rp_state) { case RPORT_ST_INIT: - FC_RPORT_DBG(rport, "Received PLOGI, wwpn %llx state INIT " + FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT " "- reject\n", (unsigned long long)wwpn); reject = ELS_RJT_UNSUP; break; case RPORT_ST_PLOGI: - FC_RPORT_DBG(rport, "Received PLOGI in PLOGI state %d\n", + FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n", rdata->rp_state); if (wwpn < lport->wwpn) reject = ELS_RJT_INPROG; break; case RPORT_ST_PRLI: case RPORT_ST_READY: - FC_RPORT_DBG(rport, "Received PLOGI in logged-in state %d " + FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " "- ignored for now\n", rdata->rp_state); /* XXX TBD - should reset */ break; case RPORT_ST_DELETE: default: - FC_RPORT_DBG(rport, "Received PLOGI in unexpected " + FC_RPORT_DBG(rdata, "Received PLOGI in unexpected " "state %d\n", rdata->rp_state); fc_frame_free(fp); return; @@ -1074,24 +1062,24 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, FC_TYPE_ELS, f_ctl, 0); lport->tt.seq_send(lport, sp, fp); if (rdata->rp_state == RPORT_ST_PLOGI) - fc_rport_enter_prli(rport); + fc_rport_enter_prli(rdata); } } } /** * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request - * @rport: Fibre Channel remote port that initiated PRLI + * @rdata: private remote port data * @sp: current sequence in the PRLI exchange * @fp: PRLI request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_prli_req(struct fc_rport *rport, +static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_exch *ep; struct fc_frame *fp; @@ -1115,8 +1103,8 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, fh = fc_frame_header_get(rx_fp); - FC_RPORT_DBG(rport, "Received PRLI request while in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", + fc_rport_state(rdata)); switch (rdata->rp_state) { case RPORT_ST_PRLI: @@ -1220,7 +1208,7 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, */ switch (rdata->rp_state) { case RPORT_ST_PRLI: - fc_rport_enter_ready(rport); + fc_rport_enter_ready(rdata); break; case RPORT_ST_READY: break; @@ -1233,17 +1221,17 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, /** * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request - * @rport: Fibre Channel remote port that initiated PRLO + * @rdata: private remote port data * @sp: current sequence in the PRLO exchange * @fp: PRLO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, +static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, + struct fc_seq *sp, struct fc_frame *fp) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame_header *fh; @@ -1251,8 +1239,8 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, fh = fc_frame_header_get(fp); - FC_RPORT_DBG(rport, "Received PRLO request while in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", + fc_rport_state(rdata)); if (rdata->rp_state == RPORT_ST_DELETE) { fc_frame_free(fp); @@ -1268,24 +1256,24 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, /** * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request - * @rport: Fibre Channel remote port that initiated LOGO + * @rdata: private remote port data * @sp: current sequence in the LOGO exchange * @fp: LOGO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, +static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata, + struct fc_seq *sp, struct fc_frame *fp) { struct fc_frame_header *fh; - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; fh = fc_frame_header_get(fp); - FC_RPORT_DBG(rport, "Received LOGO request while in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", + fc_rport_state(rdata)); if (rdata->rp_state == RPORT_ST_DELETE) { fc_frame_free(fp); @@ -1293,7 +1281,7 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, } rdata->event = RPORT_EV_LOGO; - fc_rport_state_enter(rport, RPORT_ST_DELETE); + fc_rport_state_enter(rdata, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h index a0ff61c3e935..3ede1abad4b7 100644 --- a/include/scsi/fc_encode.h +++ b/include/scsi/fc_encode.h @@ -249,10 +249,13 @@ static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp) /** * fc_els_fill - Fill in an ELS request frame */ -static inline int fc_els_fill(struct fc_lport *lport, struct fc_rport *rport, +static inline int fc_els_fill(struct fc_lport *lport, + struct fc_rport_priv *rdata, struct fc_frame *fp, unsigned int op, enum fc_rctl *r_ctl, u32 *did, enum fc_fh_type *fh_type) { + struct fc_rport *rport = PRIV_TO_RPORT(rdata); + switch (op) { case ELS_PLOGI: fc_plogi_fill(lport, fp, ELS_PLOGI); @@ -272,7 +275,7 @@ static inline int fc_els_fill(struct fc_lport *lport, struct fc_rport *rport, * is port logo, therefore * set did to rport id. */ - if (rport) + if (rdata) *did = rport->port_id; break; diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 2fdd8ac12b89..df57cb762dc2 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -75,10 +75,10 @@ do { \ (lport)->host->host_no, \ (port_id), ##args)) -#define FC_RPORT_DBG(rport, fmt, args...) \ +#define FC_RPORT_DBG(rdata, fmt, args...) \ do { \ - struct fc_rport_priv *rdata = rport->dd_data; \ struct fc_lport *lport = rdata->local_port; \ + struct fc_rport *rport = PRIV_TO_RPORT(rdata); \ FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ } while (0) @@ -185,8 +185,10 @@ enum fc_rport_event { */ #define fc_rport_priv fc_rport_libfc_priv +struct fc_rport_priv; + struct fc_rport_operations { - void (*event_callback)(struct fc_lport *, struct fc_rport *, + void (*event_callback)(struct fc_lport *, struct fc_rport_priv *, enum fc_rport_event); }; @@ -422,7 +424,7 @@ struct libfc_function_template { * STATUS: OPTIONAL */ struct fc_seq *(*elsct_send)(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *, @@ -567,8 +569,8 @@ struct libfc_function_template { /* * Create a remote port */ - struct fc_rport *(*rport_create)(struct fc_lport *, - struct fc_rport_identifiers *); + struct fc_rport_priv *(*rport_create)(struct fc_lport *, + struct fc_rport_identifiers *); /* * Initiates the RP state machine. It is called from the LP module. @@ -581,7 +583,7 @@ struct libfc_function_template { * * STATUS: OPTIONAL */ - int (*rport_login)(struct fc_rport *rport); + int (*rport_login)(struct fc_rport_priv *); /* * Logoff, and remove the rport from the transport if @@ -589,7 +591,7 @@ struct libfc_function_template { * * STATUS: OPTIONAL */ - int (*rport_logoff)(struct fc_rport *rport); + int (*rport_logoff)(struct fc_rport_priv *); /* * Recieve a request from a remote port. @@ -597,14 +599,14 @@ struct libfc_function_template { * STATUS: OPTIONAL */ void (*rport_recv_req)(struct fc_seq *, struct fc_frame *, - struct fc_rport *); + struct fc_rport_priv *); /* * lookup an rport by it's port ID. * * STATUS: OPTIONAL */ - struct fc_rport *(*rport_lookup)(const struct fc_lport *, u32); + struct fc_rport_priv *(*rport_lookup)(const struct fc_lport *, u32); /* * Send a fcp cmd from fsp pkt. @@ -694,8 +696,8 @@ struct fc_lport { /* Associations */ struct Scsi_Host *host; struct list_head ema_list; - struct fc_rport *dns_rp; - struct fc_rport *ptp_rp; + struct fc_rport_priv *dns_rp; + struct fc_rport_priv *ptp_rp; void *scsi_priv; struct fc_disc disc; -- cgit v1.2.3 From a46f327aa5caf2cce138e98ddd863b6cca0e71e2 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:55 -0700 Subject: [SCSI] libfc: change elsct to use FC_ID instead of rdata tt.elsct_send is used by both FCP and by the rport state machine. After further patches, these two modules will use different structures for the remote port. So, change elsct_send to use the FC_ID instead of the fc_rport_priv as its argument. It currently only uses the FC_ID anyway. For CT requests the destination FC_ID is still implicitly 0xfffffc. After further patches the did arg on CT requests will be used to specify the FC_ID being inquired about for GPN_ID or other queries. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 2 +- drivers/scsi/libfc/fc_elsct.c | 11 ++++++----- drivers/scsi/libfc/fc_fcp.c | 2 +- drivers/scsi/libfc/fc_lport.c | 12 ++++++------ drivers/scsi/libfc/fc_rport.c | 8 ++++---- include/scsi/fc_encode.h | 26 +++++--------------------- include/scsi/libfc.h | 2 +- 7 files changed, 24 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 448ffc388656..4b1f9faf639a 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -526,7 +526,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *disc) if (!fp) goto err; - if (lport->tt.elsct_send(lport, NULL, fp, + if (lport->tt.elsct_send(lport, 0, fp, FC_NS_GPN_FT, fc_disc_gpn_ft_resp, disc, lport->e_d_tov)) diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 2b8a3bbc0399..5e8b011af50e 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -32,7 +32,7 @@ * fc_elsct_send - sends ELS/CT frame */ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, - struct fc_rport_priv *rdata, + u32 did, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *, @@ -41,16 +41,17 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, void *arg, u32 timer_msec) { enum fc_rctl r_ctl; - u32 did = FC_FID_NONE; enum fc_fh_type fh_type; int rc; /* ELS requests */ if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) - rc = fc_els_fill(lport, rdata, fp, op, &r_ctl, &did, &fh_type); - else + rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); + else { /* CT requests */ - rc = fc_ct_fill(lport, fp, op, &r_ctl, &did, &fh_type); + rc = fc_ct_fill(lport, fp, op, &r_ctl, &fh_type); + did = FC_FID_DIR_SERV; + } if (rc) return NULL; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index a622096eb315..59a4408b27b5 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1308,7 +1308,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, fc_host_port_id(rp->local_port->host), FC_TYPE_ELS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - if (lp->tt.elsct_send(lp, rport->dd_data, fp, ELS_REC, fc_fcp_rec_resp, + if (lp->tt.elsct_send(lp, rport->port_id, fp, ELS_REC, fc_fcp_rec_resp, fsp, jiffies_to_msecs(FC_SCSI_REC_TOV))) { fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ return; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 3c15abd35ffa..aa605d2012e0 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1217,7 +1217,7 @@ static void fc_lport_enter_scr(struct fc_lport *lport) return; } - if (!lport->tt.elsct_send(lport, NULL, fp, ELS_SCR, + if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR, fc_lport_scr_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); } @@ -1258,7 +1258,7 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport) return; } - if (!lport->tt.elsct_send(lport, NULL, fp, FC_NS_RFT_ID, + if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RFT_ID, fc_lport_rft_id_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); @@ -1287,7 +1287,7 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport) return; } - if (!lport->tt.elsct_send(lport, NULL, fp, FC_NS_RPN_ID, + if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RPN_ID, fc_lport_rpn_id_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); @@ -1443,8 +1443,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport) return; } - if (!lport->tt.elsct_send(lport, NULL, fp, ELS_LOGO, fc_lport_logo_resp, - lport, lport->e_d_tov)) + if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO, + fc_lport_logo_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); } @@ -1567,7 +1567,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport) if (!fp) return fc_lport_error(lport, fp); - if (!lport->tt.elsct_send(lport, NULL, fp, ELS_FLOGI, + if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_FLOGI, fc_lport_flogi_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); } diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 13d3d758fb0e..20371b445bb1 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -593,7 +593,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) } rdata->e_d_tov = lport->e_d_tov; - if (!lport->tt.elsct_send(lport, rdata, fp, ELS_PLOGI, + if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PLOGI, fc_rport_plogi_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else @@ -747,7 +747,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rdata, fp, ELS_PRLI, + if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PRLI, fc_rport_prli_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else @@ -845,7 +845,7 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rdata, fp, ELS_RTV, + if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_RTV, fc_rport_rtv_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else @@ -876,7 +876,7 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rdata, fp, ELS_LOGO, + if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_LOGO, fc_rport_logo_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h index 3ede1abad4b7..24bf764f9884 100644 --- a/include/scsi/fc_encode.h +++ b/include/scsi/fc_encode.h @@ -79,8 +79,9 @@ static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp, /** * fc_ct_fill - Fill in a name service request frame */ -static inline int fc_ct_fill(struct fc_lport *lport, struct fc_frame *fp, - unsigned int op, enum fc_rctl *r_ctl, u32 *did, +static inline int fc_ct_fill(struct fc_lport *lport, + struct fc_frame *fp, + unsigned int op, enum fc_rctl *r_ctl, enum fc_fh_type *fh_type) { struct fc_ct_req *ct; @@ -110,7 +111,6 @@ static inline int fc_ct_fill(struct fc_lport *lport, struct fc_frame *fp, return -EINVAL; } *r_ctl = FC_RCTL_DD_UNSOL_CTL; - *did = FC_FID_DIR_SERV; *fh_type = FC_TYPE_CT; return 0; } @@ -250,53 +250,37 @@ static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp) * fc_els_fill - Fill in an ELS request frame */ static inline int fc_els_fill(struct fc_lport *lport, - struct fc_rport_priv *rdata, + u32 did, struct fc_frame *fp, unsigned int op, - enum fc_rctl *r_ctl, u32 *did, enum fc_fh_type *fh_type) + enum fc_rctl *r_ctl, enum fc_fh_type *fh_type) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); - switch (op) { case ELS_PLOGI: fc_plogi_fill(lport, fp, ELS_PLOGI); - *did = rport->port_id; break; case ELS_FLOGI: fc_flogi_fill(lport, fp); - *did = FC_FID_FLOGI; break; case ELS_LOGO: fc_logo_fill(lport, fp); - *did = FC_FID_FLOGI; - /* - * if rport is valid then it - * is port logo, therefore - * set did to rport id. - */ - if (rdata) - *did = rport->port_id; break; case ELS_RTV: fc_rtv_fill(lport, fp); - *did = rport->port_id; break; case ELS_REC: fc_rec_fill(lport, fp); - *did = rport->port_id; break; case ELS_PRLI: fc_prli_fill(lport, fp); - *did = rport->port_id; break; case ELS_SCR: fc_scr_fill(lport, fp); - *did = FC_FID_FCTRL; break; default: diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index df57cb762dc2..2473167464c2 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -424,7 +424,7 @@ struct libfc_function_template { * STATUS: OPTIONAL */ struct fc_seq *(*elsct_send)(struct fc_lport *lport, - struct fc_rport_priv *, + u32 did, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *, -- cgit v1.2.3 From f211fa514a07326c0f9364c0e6ed17e38860172f Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:01 -0700 Subject: [SCSI] libfc: make rport structure optional Allow a struct fc_rport_priv to have no fc_rport associated with it. This sets up to remove the need for "rogue" rports. Add a few fields to fc_rport_priv that are needed before the fc_rport is created. These are the ids, maxframe_size, classes, and rport pointer. Remove the macro PRIV_TO_RPORT(). Just use rdata->rport where appropriate. To take the place of the get_device()/put_device ops that were used to hold both the rport and rdata, add a reference count to rdata structures using kref. When kref_get decrements the refcount to zero, a new template function releasing the rdata should be called. This will take care of freeing the rdata and releasing the hold on the rport (for now). After subsequent patches make the rport truly optional, this release function will simply free the rdata. Remove the simple inline function fc_rport_set_name(), which becomes semanticly ambiguous otherwise. The caller will set the port_name and node_name in the rdata->Ids, which will later be copied to the rport when it its created. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 54 ++++++++-------------- drivers/scsi/libfc/fc_lport.c | 14 +++--- drivers/scsi/libfc/fc_rport.c | 102 +++++++++++++++++++++++------------------- include/scsi/libfc.h | 29 ++++++------ 4 files changed, 98 insertions(+), 101 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 4b1f9faf639a..5f839b625e50 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -47,7 +47,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); -static int fc_disc_new_target(struct fc_disc *, struct fc_rport *, +static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *, struct fc_rport_identifiers *); static void fc_disc_done(struct fc_disc *); static void fc_disc_timeout(struct work_struct *); @@ -63,12 +63,10 @@ struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, u32 port_id) { const struct fc_disc *disc = &lport->disc; - struct fc_rport *rport; struct fc_rport_priv *rdata; list_for_each_entry(rdata, &disc->rports, peers) { - rport = PRIV_TO_RPORT(rdata); - if (rport->port_id == port_id) + if (rdata->ids.port_id == port_id) return rdata; } return NULL; @@ -115,10 +113,9 @@ static void fc_disc_rport_callback(struct fc_lport *lport, enum fc_rport_event event) { struct fc_disc *disc = &lport->disc; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, - rport->port_id); + rdata->ids.port_id); switch (event) { case RPORT_EV_CREATED: @@ -320,8 +317,6 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, struct fc_lport *lport) { struct fc_rport_priv *rdata; - struct fc_rport *rport; - struct fc_rport_identifiers ids; struct fc_disc *disc = &lport->disc; /* @@ -349,18 +344,12 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, */ rdata = disc->lport->ptp_rp; if (rdata) { - rport = PRIV_TO_RPORT(rdata); - ids.port_id = rport->port_id; - ids.port_name = rport->port_name; - ids.node_name = rport->node_name; - ids.roles = FC_RPORT_ROLE_UNKNOWN; - get_device(&rport->dev); - - if (!fc_disc_new_target(disc, rport, &ids)) { + kref_get(&rdata->kref); + if (!fc_disc_new_target(disc, rdata, &rdata->ids)) { disc->event = DISC_EV_SUCCESS; fc_disc_done(disc); } - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } else { fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ } @@ -375,28 +364,27 @@ static struct fc_rport_operations fc_disc_rport_ops = { /** * fc_disc_new_target() - Handle new target found by discovery * @lport: FC local port - * @rport: The previous FC remote port (NULL if new remote port) + * @rdata: The previous FC remote port priv (NULL if new remote port) * @ids: Identifiers for the new FC remote port * * Locking Note: This function expects that the disc_mutex is locked * before it is called. */ static int fc_disc_new_target(struct fc_disc *disc, - struct fc_rport *rport, + struct fc_rport_priv *rdata, struct fc_rport_identifiers *ids) { struct fc_lport *lport = disc->lport; - struct fc_rport_priv *rdata; int error = 0; - if (rport && ids->port_name) { - if (rport->port_name == -1) { + if (rdata && ids->port_name) { + if (rdata->ids.port_name == -1) { /* * Set WWN and fall through to notify of create. */ - fc_rport_set_name(rport, ids->port_name, - rport->node_name); - } else if (rport->port_name != ids->port_name) { + rdata->ids.port_name = ids->port_name; + rdata->ids.node_name = ids->node_name; + } else if (rdata->ids.port_name != ids->port_name) { /* * This is a new port with the same FCID as * a previously-discovered port. Presumably the old @@ -404,27 +392,23 @@ static int fc_disc_new_target(struct fc_disc *disc, * assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ - rdata = rport->dd_data; list_del(&rdata->peers); lport->tt.rport_logoff(rdata); - rport = NULL; + rdata = NULL; } } if (((ids->port_name != -1) || (ids->port_id != -1)) && ids->port_id != fc_host_port_id(lport->host) && ids->port_name != lport->wwpn) { - if (!rport) { + if (!rdata) { rdata = lport->tt.rport_lookup(lport, ids->port_id); - if (!rport) { + if (!rdata) { rdata = lport->tt.rport_create(lport, ids); + if (!rdata) + error = -ENOMEM; } - if (!rdata) - error = -ENOMEM; - else - rport = PRIV_TO_RPORT(rdata); } - if (rport) { - rdata = rport->dd_data; + if (rdata) { rdata->ops = &fc_disc_rport_ops; rdata->rp_state = RPORT_ST_INIT; list_add_tail(&rdata->peers, &disc->rogue_rports); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index aa605d2012e0..a7fe6b8d38b8 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -143,14 +143,12 @@ static void fc_lport_rport_callback(struct fc_lport *lport, struct fc_rport_priv *rdata, enum fc_rport_event event) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); - FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, - rport->port_id); + rdata->ids.port_id); switch (event) { case RPORT_EV_CREATED: - if (rport->port_id == FC_FID_DIR_SERV) { + if (rdata->ids.port_id == FC_FID_DIR_SERV) { mutex_lock(&lport->lp_mutex); if (lport->state == LPORT_ST_DNS) { lport->dns_rp = rdata; @@ -160,7 +158,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, "on port (%6x) for the directory " "server, but the lport is not " "in the DNS state, it's in the " - "%d state", rport->port_id, + "%d state", rdata->ids.port_id, lport->state); lport->tt.rport_logoff(rdata); } @@ -168,12 +166,12 @@ static void fc_lport_rport_callback(struct fc_lport *lport, } else FC_LPORT_DBG(lport, "Received an event for port (%6x) " "which is not the directory server\n", - rport->port_id); + rdata->ids.port_id); break; case RPORT_EV_LOGO: case RPORT_EV_FAILED: case RPORT_EV_STOP: - if (rport->port_id == FC_FID_DIR_SERV) { + if (rdata->ids.port_id == FC_FID_DIR_SERV) { mutex_lock(&lport->lp_mutex); lport->dns_rp = NULL; mutex_unlock(&lport->lp_mutex); @@ -181,7 +179,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, } else FC_LPORT_DBG(lport, "Received an event for port (%6x) " "which is not the directory server\n", - rport->port_id); + rdata->ids.port_id); break; case RPORT_EV_NONE: break; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 20371b445bb1..69f6e588d37b 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -120,7 +120,10 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, device_initialize(&rport->dev); rport->dev.release = fc_rport_rogue_destroy; + rdata->ids = *ids; + kref_init(&rdata->kref); mutex_init(&rdata->rp_mutex); + rdata->rport = rport; rdata->local_port = lport; rdata->trans_state = FC_PORTSTATE_ROGUE; rdata->rp_state = RPORT_ST_INIT; @@ -129,6 +132,7 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, rdata->ops = NULL; rdata->e_d_tov = lport->e_d_tov; rdata->r_a_tov = lport->r_a_tov; + rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); /* @@ -140,6 +144,20 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, return rdata; } +/** + * fc_rport_destroy() - free a remote port after last reference is released. + * @kref: pointer to kref inside struct fc_rport_priv + */ +static void fc_rport_destroy(struct kref *kref) +{ + struct fc_rport_priv *rdata; + struct fc_rport *rport; + + rdata = container_of(kref, struct fc_rport_priv, kref); + rport = rdata->rport; + put_device(&rport->dev); +} + /** * fc_rport_state() - return a string for the state the rport is in * @rdata: remote port private data @@ -215,22 +233,19 @@ static void fc_rport_work(struct work_struct *work) enum fc_rport_trans_state trans_state; struct fc_lport *lport = rdata->local_port; struct fc_rport_operations *rport_ops; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); + struct fc_rport *rport; mutex_lock(&rdata->rp_mutex); event = rdata->event; rport_ops = rdata->ops; + rport = rdata->rport; if (event == RPORT_EV_CREATED) { struct fc_rport *new_rport; struct fc_rport_priv *new_rdata; struct fc_rport_identifiers ids; - ids.port_id = rport->port_id; - ids.roles = rport->roles; - ids.port_name = rport->port_name; - ids.node_name = rport->node_name; - + ids = rdata->ids; rdata->event = RPORT_EV_NONE; mutex_unlock(&rdata->rp_mutex); @@ -240,15 +255,20 @@ static void fc_rport_work(struct work_struct *work) * Switch from the rogue rport to the rport * returned by the FC class. */ - new_rport->maxframe_size = rport->maxframe_size; + new_rport->maxframe_size = rdata->maxframe_size; new_rdata = new_rport->dd_data; + new_rdata->rport = new_rport; + new_rdata->ids = ids; new_rdata->e_d_tov = rdata->e_d_tov; new_rdata->r_a_tov = rdata->r_a_tov; new_rdata->ops = rdata->ops; new_rdata->local_port = rdata->local_port; new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; new_rdata->trans_state = FC_PORTSTATE_REAL; + new_rdata->maxframe_size = rdata->maxframe_size; + new_rdata->supported_classes = rdata->supported_classes; + kref_init(&new_rdata->kref); mutex_init(&new_rdata->rp_mutex); INIT_DELAYED_WORK(&new_rdata->retry_work, fc_rport_timeout); @@ -261,12 +281,11 @@ static void fc_rport_work(struct work_struct *work) " memory for rport (%6x)\n", ids.port_id); event = RPORT_EV_FAILED; } - if (rport->port_id != FC_FID_DIR_SERV) + if (rdata->ids.port_id != FC_FID_DIR_SERV) if (rport_ops->event_callback) rport_ops->event_callback(lport, rdata, RPORT_EV_FAILED); - put_device(&rport->dev); - rport = new_rport; + kref_put(&rdata->kref, lport->tt.rport_destroy); rdata = new_rport->dd_data; if (rport_ops->event_callback) rport_ops->event_callback(lport, rdata, event); @@ -279,7 +298,7 @@ static void fc_rport_work(struct work_struct *work) rport_ops->event_callback(lport, rdata, event); cancel_delayed_work_sync(&rdata->retry_work); if (trans_state == FC_PORTSTATE_ROGUE) - put_device(&rport->dev); + kref_put(&rdata->kref, lport->tt.rport_destroy); else { port_id = rport->port_id; fc_remote_port_delete(rport); @@ -505,7 +524,6 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *rdata_arg) { struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_els_flogi *plp = NULL; unsigned int tov; @@ -533,8 +551,8 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC && (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { - rport->port_name = get_unaligned_be64(&plp->fl_wwpn); - rport->node_name = get_unaligned_be64(&plp->fl_wwnn); + rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); + rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); tov = ntohl(plp->fl_csp.sp_e_d_tov); if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) @@ -546,14 +564,13 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, if (cssp_seq < csp_seq) csp_seq = cssp_seq; rdata->max_seq = csp_seq; - rport->maxframe_size = - fc_plogi_get_maxframe(plp, lport->mfs); + rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs); /* * If the rport is one of the well known addresses * we skip PRLI and RTV and go straight to READY. */ - if (rport->port_id >= FC_FID_DOM_MGR) + if (rdata->ids.port_id >= FC_FID_DOM_MGR) fc_rport_enter_ready(rdata); else fc_rport_enter_prli(rdata); @@ -564,7 +581,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } /** @@ -577,7 +594,6 @@ err: static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) { struct fc_lport *lport = rdata->local_port; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_frame *fp; FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n", @@ -585,7 +601,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) fc_rport_state_enter(rdata, RPORT_ST_PLOGI); - rport->maxframe_size = FC_MIN_MAX_PAYLOAD; + rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); if (!fp) { fc_rport_error_retry(rdata, fp); @@ -593,11 +609,11 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) } rdata->e_d_tov = lport->e_d_tov; - if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PLOGI, + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI, fc_rport_plogi_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else - get_device(&rport->dev); + kref_get(&rdata->kref); } /** @@ -614,7 +630,6 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, void *rdata_arg) { struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct { struct fc_els_prli prli; struct fc_els_spp spp; @@ -649,13 +664,13 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, rdata->flags |= FC_RP_FLAGS_RETRY; } - rport->supported_classes = FC_COS_CLASS3; + rdata->supported_classes = FC_COS_CLASS3; if (fcp_parm & FCP_SPPF_INIT_FCN) roles |= FC_RPORT_ROLE_FCP_INITIATOR; if (fcp_parm & FCP_SPPF_TARG_FCN) roles |= FC_RPORT_ROLE_FCP_TARGET; - rport->roles = roles; + rdata->ids.roles = roles; fc_rport_enter_rtv(rdata); } else { @@ -667,7 +682,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } /** @@ -684,7 +699,6 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, void *rdata_arg) { struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); u8 op; mutex_lock(&rdata->rp_mutex); @@ -716,7 +730,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } /** @@ -728,7 +742,6 @@ err: */ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct { struct fc_els_prli prli; @@ -747,11 +760,11 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PRLI, + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI, fc_rport_prli_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else - get_device(&rport->dev); + kref_get(&rdata->kref); } /** @@ -770,7 +783,6 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, void *rdata_arg) { struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); u8 op; mutex_lock(&rdata->rp_mutex); @@ -818,7 +830,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } /** @@ -832,7 +844,6 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) { struct fc_frame *fp; struct fc_lport *lport = rdata->local_port; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n", fc_rport_state(rdata)); @@ -845,11 +856,11 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_RTV, + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV, fc_rport_rtv_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else - get_device(&rport->dev); + kref_get(&rdata->kref); } /** @@ -862,7 +873,6 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) static void fc_rport_enter_logo(struct fc_rport_priv *rdata) { struct fc_lport *lport = rdata->local_port; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_frame *fp; FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n", @@ -876,11 +886,11 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_LOGO, + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, fc_rport_logo_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else - get_device(&rport->dev); + kref_get(&rdata->kref); } @@ -956,7 +966,6 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_frame *fp = rx_fp; struct fc_exch *ep; @@ -1041,12 +1050,13 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, } else { sp = lport->tt.seq_start_next(sp); WARN_ON(!sp); - fc_rport_set_name(rport, wwpn, wwnn); + rdata->ids.port_name = wwpn; + rdata->ids.node_name = wwnn; /* * Get session payload size from incoming PLOGI. */ - rport->maxframe_size = + rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); fc_frame_free(rx_fp); fc_plogi_fill(lport, fp, ELS_LS_ACC); @@ -1079,7 +1089,6 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_exch *ep; struct fc_frame *fp; @@ -1173,12 +1182,12 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, fcp_parm = ntohl(rspp->spp_params); if (fcp_parm * FCP_SPPF_RETRY) rdata->flags |= FC_RP_FLAGS_RETRY; - rport->supported_classes = FC_COS_CLASS3; + rdata->supported_classes = FC_COS_CLASS3; if (fcp_parm & FCP_SPPF_INIT_FCN) roles |= FC_RPORT_ROLE_FCP_INITIATOR; if (fcp_parm & FCP_SPPF_TARG_FCN) roles |= FC_RPORT_ROLE_FCP_TARGET; - rport->roles = roles; + rdata->ids.roles = roles; spp->spp_params = htonl(lport->service_params); @@ -1310,6 +1319,9 @@ int fc_rport_init(struct fc_lport *lport) if (!lport->tt.rport_flush_queue) lport->tt.rport_flush_queue = fc_rport_flush_queue; + if (!lport->tt.rport_destroy) + lport->tt.rport_destroy = fc_rport_destroy; + return 0; } EXPORT_SYMBOL(fc_rport_init); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 2473167464c2..a94d216d2207 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -76,11 +76,7 @@ do { \ (port_id), ##args)) #define FC_RPORT_DBG(rdata, fmt, args...) \ -do { \ - struct fc_lport *lport = rdata->local_port; \ - struct fc_rport *rport = PRIV_TO_RPORT(rdata); \ - FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ -} while (0) + FC_RPORT_ID_DBG((rdata)->local_port, (rdata)->ids.port_id, fmt, ##args) #define FC_FCP_DBG(pkt, fmt, args...) \ FC_CHECK_LOGGING(FC_FCP_LOGGING, \ @@ -195,9 +191,13 @@ struct fc_rport_operations { /** * struct fc_rport_libfc_priv - libfc internal information about a remote port * @local_port: Fibre Channel host port instance + * @rport: transport remote port + * @kref: reference counter * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges + * @ids: remote port identifiers and roles * @flags: REC and RETRY supported flags * @max_seq: maximum number of concurrent sequences + * @maxframe_size: maximum frame size * @retries: retry count in current state * @e_d_tov: error detect timeout value (in msec) * @r_a_tov: resource allocation timeout value (in msec) @@ -207,11 +207,15 @@ struct fc_rport_operations { */ struct fc_rport_libfc_priv { struct fc_lport *local_port; + struct fc_rport *rport; + struct kref kref; enum fc_rport_state rp_state; + struct fc_rport_identifiers ids; u16 flags; #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) #define FC_RP_FLAGS_RETRY (1 << 1) u16 max_seq; + u16 maxframe_size; unsigned int retries; unsigned int e_d_tov; unsigned int r_a_tov; @@ -222,19 +226,12 @@ struct fc_rport_libfc_priv { struct fc_rport_operations *ops; struct list_head peers; struct work_struct event_work; + u32 supported_classes; }; -#define PRIV_TO_RPORT(x) \ - ((struct fc_rport *)((void *)(x) - sizeof(struct fc_rport))) #define RPORT_TO_PRIV(x) \ ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport))) -static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) -{ - rport->node_name = wwnn; - rport->port_name = wwpn; -} - /* * fcoe stats structure */ @@ -608,6 +605,12 @@ struct libfc_function_template { */ struct fc_rport_priv *(*rport_lookup)(const struct fc_lport *, u32); + /* + * Destroy an rport after final kref_put(). + * The argument is a pointer to the kref inside the fc_rport_priv. + */ + void (*rport_destroy)(struct kref *); + /* * Send a fcp cmd from fsp pkt. * Called with the SCSI host lock unlocked and irqs disabled. -- cgit v1.2.3 From 4c0f62b5679321b2e5572cf541ffb9f7b344d47c Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:12 -0700 Subject: [SCSI] libfc: rename rport event CREATED to READY Remote ports will become READY more than once after ADISC is implemented in a later patch. The event callback that has been called "CREATED" will mean "READY". Rename it now in preparation for those changes. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 2 +- drivers/scsi/libfc/fc_lport.c | 4 ++-- drivers/scsi/libfc/fc_rport.c | 4 ++-- include/scsi/libfc.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 5f839b625e50..e5e5b260a572 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -118,7 +118,7 @@ static void fc_disc_rport_callback(struct fc_lport *lport, rdata->ids.port_id); switch (event) { - case RPORT_EV_CREATED: + case RPORT_EV_READY: if (disc) { mutex_lock(&disc->disc_mutex); list_add_tail(&rdata->peers, &disc->rports); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index a7fe6b8d38b8..016f771ebe69 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -147,14 +147,14 @@ static void fc_lport_rport_callback(struct fc_lport *lport, rdata->ids.port_id); switch (event) { - case RPORT_EV_CREATED: + case RPORT_EV_READY: if (rdata->ids.port_id == FC_FID_DIR_SERV) { mutex_lock(&lport->lp_mutex); if (lport->state == LPORT_ST_DNS) { lport->dns_rp = rdata; fc_lport_enter_rpn_id(lport); } else { - FC_LPORT_DBG(lport, "Received an CREATED event " + FC_LPORT_DBG(lport, "Received an READY event " "on port (%6x) for the directory " "server, but the lport is not " "in the DNS state, it's in the " diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index d0a45425cc3f..50959ba0a9a0 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -244,7 +244,7 @@ static void fc_rport_work(struct work_struct *work) rport = rdata->rport; switch (event) { - case RPORT_EV_CREATED: + case RPORT_EV_READY: ids = rdata->ids; rdata->event = RPORT_EV_NONE; mutex_unlock(&rdata->rp_mutex); @@ -413,7 +413,7 @@ static void fc_rport_enter_ready(struct fc_rport_priv *rdata) if (rdata->event == RPORT_EV_NONE) queue_work(rport_event_queue, &rdata->event_work); - rdata->event = RPORT_EV_CREATED; + rdata->event = RPORT_EV_READY; } /** diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index a94d216d2207..d324df8c36e6 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -167,7 +167,7 @@ struct fc_disc_port { enum fc_rport_event { RPORT_EV_NONE = 0, - RPORT_EV_CREATED, + RPORT_EV_READY, RPORT_EV_FAILED, RPORT_EV_STOP, RPORT_EV_LOGO -- cgit v1.2.3 From 9e9d0452fe12115b1c1883c0d4d2ee509079791b Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:18 -0700 Subject: [SCSI] libfc: don't create dummy (rogue) remote ports Don't create a "dummy" remote port to go with fc_rport_priv. Make the rport truly optional by allocating fc_rport_priv separately and not requiring a dummy rport to be there if we haven't yet done fc_remote_port_add(). The fc_rport_libfc_priv remains as a structure attached to the rport for I/O purposes. Be sure to hold references on rdata when the lock is dropped in fc_rport_work(). Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 40 +++-------- drivers/scsi/libfc/fc_rport.c | 154 +++++++++++++++++------------------------- include/scsi/libfc.h | 40 ++++++----- 3 files changed, 92 insertions(+), 142 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index e5e5b260a572..bbea41e50a57 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -66,7 +66,8 @@ struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, struct fc_rport_priv *rdata; list_for_each_entry(rdata, &disc->rports, peers) { - if (rdata->ids.port_id == port_id) + if (rdata->ids.port_id == port_id && + rdata->rp_state != RPORT_ST_DELETE) return rdata; } return NULL; @@ -87,15 +88,8 @@ void fc_disc_stop_rports(struct fc_disc *disc) lport = disc->lport; mutex_lock(&disc->disc_mutex); - list_for_each_entry_safe(rdata, next, &disc->rports, peers) { - list_del(&rdata->peers); + list_for_each_entry_safe(rdata, next, &disc->rports, peers) lport->tt.rport_logoff(rdata); - } - - list_for_each_entry_safe(rdata, next, &disc->rogue_rports, peers) { - lport->tt.rport_logoff(rdata); - } - mutex_unlock(&disc->disc_mutex); } @@ -119,20 +113,12 @@ static void fc_disc_rport_callback(struct fc_lport *lport, switch (event) { case RPORT_EV_READY: - if (disc) { - mutex_lock(&disc->disc_mutex); - list_add_tail(&rdata->peers, &disc->rports); - mutex_unlock(&disc->disc_mutex); - } break; case RPORT_EV_LOGO: case RPORT_EV_FAILED: case RPORT_EV_STOP: mutex_lock(&disc->disc_mutex); - mutex_lock(&rdata->rp_mutex); - if (rdata->trans_state == FC_PORTSTATE_ROGUE) - list_del(&rdata->peers); - mutex_unlock(&rdata->rp_mutex); + list_del(&rdata->peers); mutex_unlock(&disc->disc_mutex); break; default: @@ -235,7 +221,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, list_del(&dp->peers); rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); if (rdata) { - list_del(&rdata->peers); lport->tt.rport_logoff(rdata); } fc_disc_single(disc, dp); @@ -296,10 +281,8 @@ static void fc_disc_restart(struct fc_disc *disc) FC_DISC_DBG(disc, "Restarting discovery\n"); - list_for_each_entry_safe(rdata, next, &disc->rports, peers) { - list_del(&rdata->peers); + list_for_each_entry_safe(rdata, next, &disc->rports, peers) lport->tt.rport_logoff(rdata); - } disc->requested = 1; if (!disc->pending) @@ -392,7 +375,6 @@ static int fc_disc_new_target(struct fc_disc *disc, * assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ - list_del(&rdata->peers); lport->tt.rport_logoff(rdata); rdata = NULL; } @@ -406,12 +388,13 @@ static int fc_disc_new_target(struct fc_disc *disc, rdata = lport->tt.rport_create(lport, ids); if (!rdata) error = -ENOMEM; + else + list_add_tail(&rdata->peers, + &disc->rports); } } if (rdata) { rdata->ops = &fc_disc_rport_ops; - rdata->rp_state = RPORT_ST_INIT; - list_add_tail(&rdata->peers, &disc->rogue_rports); lport->tt.rport_login(rdata); } } @@ -585,9 +568,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) rdata = lport->tt.rport_create(lport, &ids); if (rdata) { rdata->ops = &fc_disc_rport_ops; - rdata->local_port = lport; - list_add_tail(&rdata->peers, - &disc->rogue_rports); + list_add_tail(&rdata->peers, &disc->rports); lport->tt.rport_login(rdata); } else printk(KERN_WARNING "libfc: Failed to allocate " @@ -736,7 +717,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) if (rdata) { rdata->ops = &fc_disc_rport_ops; kfree(dp); - list_add_tail(&rdata->peers, &disc->rogue_rports); + list_add_tail(&rdata->peers, &disc->rports); lport->tt.rport_login(rdata); } return; @@ -798,7 +779,6 @@ int fc_disc_init(struct fc_lport *lport) INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); mutex_init(&disc->disc_mutex); INIT_LIST_HEAD(&disc->rports); - INIT_LIST_HEAD(&disc->rogue_rports); disc->lport = lport; disc->delay = FC_DISC_DELAY; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 50959ba0a9a0..a1794a39158e 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -86,61 +86,35 @@ static const char *fc_rport_state_names[] = { [RPORT_ST_DELETE] = "Delete", }; -static void fc_rport_rogue_destroy(struct device *dev) -{ - struct fc_rport *rport = dev_to_rport(dev); - struct fc_rport_priv *rdata = RPORT_TO_PRIV(rport); - - FC_RPORT_DBG(rdata, "Destroying rogue rport\n"); - kfree(rport); -} - -struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, - struct fc_rport_identifiers *ids) +/** + * fc_rport_create() - create remote port in INIT state. + * @lport: local port. + * @ids: remote port identifiers. + * + * Locking note: this may be called without locks held, but + * is usually called from discovery with the disc_mutex held. + */ +static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, + struct fc_rport_identifiers *ids) { - struct fc_rport *rport; struct fc_rport_priv *rdata; - rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL); - if (!rport) + rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); + if (!rdata) return NULL; - rdata = RPORT_TO_PRIV(rport); - - rport->dd_data = rdata; - rport->port_id = ids->port_id; - rport->port_name = ids->port_name; - rport->node_name = ids->node_name; - rport->roles = ids->roles; - rport->maxframe_size = FC_MIN_MAX_PAYLOAD; - /* - * Note: all this libfc rogue rport code will be removed for - * upstream so it fine that this is really ugly and hacky right now. - */ - device_initialize(&rport->dev); - rport->dev.release = fc_rport_rogue_destroy; - rdata->ids = *ids; kref_init(&rdata->kref); mutex_init(&rdata->rp_mutex); - rdata->rport = rport; rdata->local_port = lport; - rdata->trans_state = FC_PORTSTATE_ROGUE; rdata->rp_state = RPORT_ST_INIT; rdata->event = RPORT_EV_NONE; rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; - rdata->ops = NULL; rdata->e_d_tov = lport->e_d_tov; rdata->r_a_tov = lport->r_a_tov; rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); - /* - * For good measure, but not necessary as we should only - * add REAL rport to the lport list. - */ - INIT_LIST_HEAD(&rdata->peers); - return rdata; } @@ -151,11 +125,9 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, static void fc_rport_destroy(struct kref *kref) { struct fc_rport_priv *rdata; - struct fc_rport *rport; rdata = container_of(kref, struct fc_rport_priv, kref); - rport = rdata->rport; - put_device(&rport->dev); + kfree(rdata); } /** @@ -229,12 +201,10 @@ static void fc_rport_work(struct work_struct *work) u32 port_id; struct fc_rport_priv *rdata = container_of(work, struct fc_rport_priv, event_work); + struct fc_rport_libfc_priv *rp; enum fc_rport_event event; - enum fc_rport_trans_state trans_state; struct fc_lport *lport = rdata->local_port; struct fc_rport_operations *rport_ops; - struct fc_rport *new_rport; - struct fc_rport_priv *new_rdata; struct fc_rport_identifiers ids; struct fc_rport *rport; @@ -243,70 +213,72 @@ static void fc_rport_work(struct work_struct *work) rport_ops = rdata->ops; rport = rdata->rport; + FC_RPORT_DBG(rdata, "work event %u\n", event); + switch (event) { case RPORT_EV_READY: ids = rdata->ids; rdata->event = RPORT_EV_NONE; + kref_get(&rdata->kref); mutex_unlock(&rdata->rp_mutex); - new_rport = fc_remote_port_add(lport->host, 0, &ids); - if (new_rport) { - /* - * Switch from the rogue rport to the rport - * returned by the FC class. - */ - new_rport->maxframe_size = rdata->maxframe_size; - - new_rdata = new_rport->dd_data; - new_rdata->rport = new_rport; - new_rdata->ids = ids; - new_rdata->e_d_tov = rdata->e_d_tov; - new_rdata->r_a_tov = rdata->r_a_tov; - new_rdata->ops = rdata->ops; - new_rdata->local_port = rdata->local_port; - new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; - new_rdata->trans_state = FC_PORTSTATE_REAL; - new_rdata->maxframe_size = rdata->maxframe_size; - new_rdata->supported_classes = rdata->supported_classes; - kref_init(&new_rdata->kref); - mutex_init(&new_rdata->rp_mutex); - INIT_DELAYED_WORK(&new_rdata->retry_work, - fc_rport_timeout); - INIT_LIST_HEAD(&new_rdata->peers); - INIT_WORK(&new_rdata->event_work, fc_rport_work); - - fc_rport_state_enter(new_rdata, RPORT_ST_READY); - } else { - printk(KERN_WARNING "libfc: Failed to allocate " - " memory for rport (%6x)\n", ids.port_id); - event = RPORT_EV_FAILED; + if (!rport) + rport = fc_remote_port_add(lport->host, 0, &ids); + if (!rport) { + FC_RPORT_DBG(rdata, "Failed to add the rport\n"); + lport->tt.rport_logoff(rdata); + kref_put(&rdata->kref, lport->tt.rport_destroy); + return; } - if (rdata->ids.port_id != FC_FID_DIR_SERV) - if (rport_ops->event_callback) - rport_ops->event_callback(lport, rdata, - RPORT_EV_FAILED); - kref_put(&rdata->kref, lport->tt.rport_destroy); - rdata = new_rport->dd_data; - if (rport_ops->event_callback) + mutex_lock(&rdata->rp_mutex); + if (rdata->rport) + FC_RPORT_DBG(rdata, "rport already allocated\n"); + rdata->rport = rport; + rport->maxframe_size = rdata->maxframe_size; + rport->supported_classes = rdata->supported_classes; + + rp = rport->dd_data; + rp->local_port = lport; + rp->rp_state = rdata->rp_state; + rp->flags = rdata->flags; + rp->e_d_tov = rdata->e_d_tov; + rp->r_a_tov = rdata->r_a_tov; + mutex_unlock(&rdata->rp_mutex); + + if (rport_ops->event_callback) { + FC_RPORT_DBG(rdata, "callback ev %d\n", event); rport_ops->event_callback(lport, rdata, event); + } + kref_put(&rdata->kref, lport->tt.rport_destroy); break; case RPORT_EV_FAILED: case RPORT_EV_LOGO: case RPORT_EV_STOP: - trans_state = rdata->trans_state; + port_id = rdata->ids.port_id; mutex_unlock(&rdata->rp_mutex); - if (rport_ops->event_callback) + + if (rport_ops->event_callback) { + FC_RPORT_DBG(rdata, "callback ev %d\n", event); rport_ops->event_callback(lport, rdata, event); + } cancel_delayed_work_sync(&rdata->retry_work); - if (trans_state == FC_PORTSTATE_ROGUE) - kref_put(&rdata->kref, lport->tt.rport_destroy); - else { - port_id = rport->port_id; + + /* + * Reset any outstanding exchanges before freeing rport. + */ + lport->tt.exch_mgr_reset(lport, 0, port_id); + lport->tt.exch_mgr_reset(lport, port_id, 0); + + if (rport) { + rp = rport->dd_data; + rp->rp_state = RPORT_ST_DELETE; + mutex_lock(&rdata->rp_mutex); + rdata->rport = NULL; + mutex_unlock(&rdata->rp_mutex); fc_remote_port_delete(rport); - lport->tt.exch_mgr_reset(lport, 0, port_id); - lport->tt.exch_mgr_reset(lport, port_id, 0); } + kref_put(&rdata->kref, lport->tt.rport_destroy); break; default: @@ -1311,7 +1283,7 @@ static void fc_rport_flush_queue(void) int fc_rport_init(struct fc_lport *lport) { if (!lport->tt.rport_create) - lport->tt.rport_create = fc_rport_rogue_create; + lport->tt.rport_create = fc_rport_create; if (!lport->tt.rport_login) lport->tt.rport_login = fc_rport_login; diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index d324df8c36e6..bf4b1c2ec600 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -146,11 +146,6 @@ enum fc_rport_state { RPORT_ST_DELETE, /* port being deleted */ }; -enum fc_rport_trans_state { - FC_PORTSTATE_ROGUE, - FC_PORTSTATE_REAL, -}; - /** * struct fc_disc_port - temporary discovery port to hold rport identifiers * @lp: Fibre Channel host port instance @@ -173,14 +168,6 @@ enum fc_rport_event { RPORT_EV_LOGO }; -/* - * Temporary definition to prepare for split off from fc_rport_libfc_priv - * of a separately-allocated structure called fc_rport_priv. This will - * be the primary object for the discovery and rport state machines. - * This definition is just to make this patch series easier to review. - */ -#define fc_rport_priv fc_rport_libfc_priv - struct fc_rport_priv; struct fc_rport_operations { @@ -191,6 +178,24 @@ struct fc_rport_operations { /** * struct fc_rport_libfc_priv - libfc internal information about a remote port * @local_port: Fibre Channel host port instance + * @rp_state: indicates READY for I/O or DELETE when blocked. + * @flags: REC and RETRY supported flags + * @e_d_tov: error detect timeout value (in msec) + * @r_a_tov: resource allocation timeout value (in msec) + */ +struct fc_rport_libfc_priv { + struct fc_lport *local_port; + enum fc_rport_state rp_state; + u16 flags; + #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) + #define FC_RP_FLAGS_RETRY (1 << 1) + unsigned int e_d_tov; + unsigned int r_a_tov; +}; + +/** + * struct fc_rport_priv - libfc rport and discovery info about a remote port + * @local_port: Fibre Channel host port instance * @rport: transport remote port * @kref: reference counter * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges @@ -205,21 +210,18 @@ struct fc_rport_operations { * @retry_work: * @event_callback: Callback for rport READY, FAILED or LOGO */ -struct fc_rport_libfc_priv { +struct fc_rport_priv { struct fc_lport *local_port; struct fc_rport *rport; struct kref kref; enum fc_rport_state rp_state; struct fc_rport_identifiers ids; u16 flags; - #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) - #define FC_RP_FLAGS_RETRY (1 << 1) u16 max_seq; u16 maxframe_size; unsigned int retries; unsigned int e_d_tov; unsigned int r_a_tov; - enum fc_rport_trans_state trans_state; struct mutex rp_mutex; struct delayed_work retry_work; enum fc_rport_event event; @@ -229,9 +231,6 @@ struct fc_rport_libfc_priv { u32 supported_classes; }; -#define RPORT_TO_PRIV(x) \ - ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport))) - /* * fcoe stats structure */ @@ -686,7 +685,6 @@ struct fc_disc { enum fc_disc_event); struct list_head rports; - struct list_head rogue_rports; struct fc_lport *lport; struct mutex disc_mutex; struct fc_gpn_ft_resp partial_buf; /* partial name buffer */ -- cgit v1.2.3 From 786681b96fc1a5b94d187160b7bf80bf6b4681ed Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:29 -0700 Subject: [SCSI] libfc: eliminate disc->event There was no need to have the discovery status stored in struct fc_disc. Change fc_disc_done() to take the discovery status as an argument and just pass it on to the discovery callback. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 31 ++++++++++++------------------- include/scsi/libfc.h | 1 - 2 files changed, 12 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index bbea41e50a57..736f91742064 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -49,7 +49,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *, struct fc_rport_identifiers *); -static void fc_disc_done(struct fc_disc *); +static void fc_disc_done(struct fc_disc *, enum fc_disc_event); static void fc_disc_timeout(struct work_struct *); static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); static void fc_disc_restart(struct fc_disc *); @@ -329,8 +329,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, if (rdata) { kref_get(&rdata->kref); if (!fc_disc_new_target(disc, rdata, &rdata->ids)) { - disc->event = DISC_EV_SUCCESS; - fc_disc_done(disc); + fc_disc_done(disc, DISC_EV_SUCCESS); } kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } else { @@ -404,20 +403,18 @@ static int fc_disc_new_target(struct fc_disc *disc, /** * fc_disc_done() - Discovery has been completed * @disc: FC discovery context + * @event: discovery completion status + * * Locking Note: This function expects that the disc mutex is locked before * it is called. The discovery callback is then made with the lock released, * and the lock is re-taken before returning from this function */ -static void fc_disc_done(struct fc_disc *disc) +static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) { struct fc_lport *lport = disc->lport; - enum fc_disc_event event; FC_DISC_DBG(disc, "Discovery complete\n"); - event = disc->event; - disc->event = DISC_EV_NONE; - if (disc->requested) fc_disc_gpn_ft_req(disc); else @@ -460,11 +457,8 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) } disc->retry_count++; schedule_delayed_work(&disc->disc_work, delay); - } else { - /* exceeded retries */ - disc->event = DISC_EV_FAILED; - fc_disc_done(disc); - } + } else + fc_disc_done(disc, DISC_EV_FAILED); } } @@ -503,10 +497,12 @@ err: } /** - * fc_disc_gpn_ft_parse() - Parse the list of IDs and names resulting from a request + * fc_disc_gpn_ft_parse() - Parse the body of the dNS GPN_FT response. * @lport: Fibre Channel host port instance * @buf: GPN_FT response buffer * @len: size of response buffer + * + * Goes through the list of IDs and names resulting from a request. */ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) { @@ -577,8 +573,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) } if (np->fp_flags & FC_NS_FID_LAST) { - disc->event = DISC_EV_SUCCESS; - fc_disc_done(disc); + fc_disc_done(disc, DISC_EV_SUCCESS); len = 0; break; } @@ -669,8 +664,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x " "(check zoning)\n", cp->ct_reason, cp->ct_explan); - disc->event = DISC_EV_FAILED; - fc_disc_done(disc); + fc_disc_done(disc, DISC_EV_FAILED); } else { FC_DISC_DBG(disc, "GPN_FT unexpected response code " "%x\n", ntohs(cp->ct_cmd)); @@ -782,7 +776,6 @@ int fc_disc_init(struct fc_lport *lport) disc->lport = lport; disc->delay = FC_DISC_DELAY; - disc->event = DISC_EV_NONE; return 0; } diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index bf4b1c2ec600..f3f320f1d399 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -679,7 +679,6 @@ struct fc_disc { unsigned char requested; unsigned short seq_count; unsigned char buf_len; - enum fc_disc_event event; void (*disc_callback)(struct fc_lport *, enum fc_disc_event); -- cgit v1.2.3 From b84c7962653e4d04065d2603f0e1424ee0f455ae Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:34 -0700 Subject: [SCSI] libfc: remove unused disc->delay element Delete unused disc->delay element. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 3 --- include/scsi/libfc.h | 1 - 2 files changed, 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 736f91742064..8427396909e8 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -43,8 +43,6 @@ #define FC_DISC_RETRY_LIMIT 3 /* max retries */ #define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */ -#define FC_DISC_DELAY 3 - static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *, @@ -775,7 +773,6 @@ int fc_disc_init(struct fc_lport *lport) INIT_LIST_HEAD(&disc->rports); disc->lport = lport; - disc->delay = FC_DISC_DELAY; return 0; } diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index f3f320f1d399..093b0439a2cf 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -674,7 +674,6 @@ struct libfc_function_template { /* information used by the discovery layer */ struct fc_disc { unsigned char retry_count; - unsigned char delay; unsigned char pending; unsigned char requested; unsigned short seq_count; -- cgit v1.2.3 From 0f6c6149870e03c722af6eae406758b28cb71320 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:11 -0700 Subject: [SCSI] libfc: do not log off rports before or after discovery When receiving an RSCN, do not log off all rports. This is extremely disruptive. If, after the GPN_FT response, some rports haven't been listed, delete them. Add field disc_id to structs fc_rport_priv and fc_disc. disc_id is an arbitrary serial number used to identify the rports found by the latest discovery. This eliminates the need to go through the rport list when restarting discovery. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 47 ++++++++++++++++++++++++++++++++------------ include/scsi/libfc.h | 3 +++ 2 files changed, 37 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index f6762a52147d..ddf494424ff4 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -221,17 +221,19 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, */ static void fc_disc_restart(struct fc_disc *disc) { - struct fc_rport_priv *rdata, *next; - struct fc_lport *lport = disc->lport; - FC_DISC_DBG(disc, "Restarting discovery\n"); - list_for_each_entry_safe(rdata, next, &disc->rports, peers) - lport->tt.rport_logoff(rdata); - disc->requested = 1; - if (!disc->pending) - fc_disc_gpn_ft_req(disc); + if (disc->pending) + return; + + /* + * Advance disc_id. This is an arbitrary non-zero number that will + * match the value in the fc_rport_priv after discovery for all + * freshly-discovered remote ports. Avoid wrapping to zero. + */ + disc->disc_id = (disc->disc_id + 2) | 1; + fc_disc_gpn_ft_req(disc); } /** @@ -278,6 +280,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, } kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } else { + disc->disc_id = (disc->disc_id + 2) | 1; fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ } @@ -345,13 +348,30 @@ static int fc_disc_new_target(struct fc_disc *disc, static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) { struct fc_lport *lport = disc->lport; + struct fc_rport_priv *rdata; FC_DISC_DBG(disc, "Discovery complete\n"); - if (disc->requested) - fc_disc_gpn_ft_req(disc); - else - disc->pending = 0; + disc->pending = 0; + if (disc->requested) { + fc_disc_restart(disc); + return; + } + + /* + * Go through all remote ports. If they were found in the latest + * discovery, reverify or log them in. Otherwise, log them out. + * Skip ports which were never discovered. These are the dNS port + * and ports which were created by PLOGI. + */ + list_for_each_entry(rdata, &disc->rports, peers) { + if (!rdata->disc_id) + continue; + if (rdata->disc_id == disc->disc_id) + lport->tt.rport_login(rdata); + else + lport->tt.rport_logoff(rdata); + } mutex_unlock(&disc->disc_mutex); disc->disc_callback(lport, event); @@ -496,7 +516,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) ids.port_name != lport->wwpn) { rdata = lport->tt.rport_create(lport, &ids); if (rdata) - lport->tt.rport_login(rdata); + rdata->disc_id = disc->disc_id; else printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " @@ -640,6 +660,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) rdata = lport->tt.rport_create(lport, &dp->ids); if (rdata) { + rdata->disc_id = disc->disc_id; kfree(dp); lport->tt.rport_login(rdata); } diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 093b0439a2cf..517dce5c8d0d 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -202,6 +202,7 @@ struct fc_rport_libfc_priv { * @ids: remote port identifiers and roles * @flags: REC and RETRY supported flags * @max_seq: maximum number of concurrent sequences + * @disc_id: discovery identifier * @maxframe_size: maximum frame size * @retries: retry count in current state * @e_d_tov: error detect timeout value (in msec) @@ -218,6 +219,7 @@ struct fc_rport_priv { struct fc_rport_identifiers ids; u16 flags; u16 max_seq; + u16 disc_id; u16 maxframe_size; unsigned int retries; unsigned int e_d_tov; @@ -678,6 +680,7 @@ struct fc_disc { unsigned char requested; unsigned short seq_count; unsigned char buf_len; + u16 disc_id; void (*disc_callback)(struct fc_lport *, enum fc_disc_event); -- cgit v1.2.3 From c762608bf75f792dcaf3658338189b9970951704 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:33 -0700 Subject: [SCSI] libfc: fix: empty zone causes endless discovery retries. On some switches, an empty zone causes GPN_FT to be rejected with reason 9 (unable) explanation 7 (FC-4 types not registered), which causes discovery to be retried endlessly. Treat this as just an empty response and consider discovery complete. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 3 +++ include/scsi/fc/fc_gs.h | 1 + 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 844376c1d8dc..9b8043bdeddb 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -617,6 +617,9 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, "(check zoning)\n", cp->ct_reason, cp->ct_explan); event = DISC_EV_FAILED; + if (cp->ct_reason == FC_FS_RJT_UNABL && + cp->ct_explan == FC_FS_EXP_FTNR) + event = DISC_EV_SUCCESS; } else { FC_DISC_DBG(disc, "GPN_FT unexpected response code " "%x\n", ntohs(cp->ct_cmd)); diff --git a/include/scsi/fc/fc_gs.h b/include/scsi/fc/fc_gs.h index ffab0272c65a..324dd0e3c622 100644 --- a/include/scsi/fc/fc_gs.h +++ b/include/scsi/fc/fc_gs.h @@ -87,6 +87,7 @@ enum fc_ct_explan { FC_FS_EXP_PNAM = 0x02, /* port name not registered */ FC_FS_EXP_NNAM = 0x03, /* node name not registered */ FC_FS_EXP_COS = 0x04, /* class of service not registered */ + FC_FS_EXP_FTNR = 0x07, /* FC-4 types not registered */ /* definitions not complete */ }; -- cgit v1.2.3 From 9737e6a7b5b8af48f983cd565df93493597c565b Mon Sep 17 00:00:00 2001 From: Robert Love Date: Tue, 25 Aug 2009 14:02:59 -0700 Subject: [SCSI] libfc: Initialize fc_rport_identifiers inside fc_rport_create Currently these values are initialized by the callers. This was exposed by a later patch that adds PLOGI request support. The patch failed to initialize the new remote port's roles and it caused problems. This patch has the rport_create routine initialize the identifiers and then the callers can override them with real values. Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 20 ++++++++------------ drivers/scsi/libfc/fc_lport.c | 19 ++++--------------- drivers/scsi/libfc/fc_rport.c | 18 +++++++++++------- include/scsi/libfc.h | 17 +++++++++-------- 4 files changed, 32 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 1a699f484c85..4242894cce7c 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -137,10 +137,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, break; } dp->lp = lport; - dp->ids.port_id = ntoh24(pp->rscn_fid); - dp->ids.port_name = -1; - dp->ids.node_name = -1; - dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; + dp->port_id = ntoh24(pp->rscn_fid); list_add_tail(&dp->peers, &disc_ports); break; case ELS_ADDR_FMT_AREA: @@ -162,7 +159,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, redisc, lport->state, disc->pending); list_for_each_entry_safe(dp, next, &disc_ports, peers) { list_del(&dp->peers); - rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); + rdata = lport->tt.rport_lookup(lport, dp->port_id); if (rdata) { lport->tt.rport_logoff(rdata); } @@ -435,15 +432,14 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) while (plen >= sizeof(*np)) { ids.port_id = ntoh24(np->fp_fid); ids.port_name = ntohll(np->fp_wwpn); - ids.node_name = -1; - ids.roles = FC_RPORT_ROLE_UNKNOWN; if (ids.port_id != fc_host_port_id(lport->host) && ids.port_name != lport->wwpn) { - rdata = lport->tt.rport_create(lport, &ids); - if (rdata) + rdata = lport->tt.rport_create(lport, ids.port_id); + if (rdata) { + rdata->ids.port_name = ids.port_name; rdata->disc_id = disc->disc_id; - else { + } else { printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " "(%6x)\n", ids.port_id); @@ -580,10 +576,10 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) lport = disc->lport; - if (dp->ids.port_id == fc_host_port_id(lport->host)) + if (dp->port_id == fc_host_port_id(lport->host)) goto out; - rdata = lport->tt.rport_create(lport, &dp->ids); + rdata = lport->tt.rport_create(lport, dp->port_id); if (rdata) { rdata->disc_id = disc->disc_id; kfree(dp); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 7000df573691..caf68240bddf 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -198,17 +198,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, u32 remote_fid, u64 remote_wwpn, u64 remote_wwnn) { - struct fc_rport_identifiers ids; - - ids.port_id = remote_fid; - ids.port_name = remote_wwpn; - ids.node_name = remote_wwnn; - ids.roles = FC_RPORT_ROLE_UNKNOWN; - mutex_lock(&lport->disc.disc_mutex); if (lport->ptp_rp) lport->tt.rport_logoff(lport->ptp_rp); - lport->ptp_rp = lport->tt.rport_create(lport, &ids); + lport->ptp_rp = lport->tt.rport_create(lport, remote_fid); + lport->ptp_rp->ids.port_name = remote_wwpn; + lport->ptp_rp->ids.node_name = remote_wwnn; mutex_unlock(&lport->disc.disc_mutex); lport->tt.rport_login(lport->ptp_rp); @@ -1287,12 +1282,6 @@ static struct fc_rport_operations fc_lport_rport_ops = { static void fc_lport_enter_dns(struct fc_lport *lport) { struct fc_rport_priv *rdata; - struct fc_rport_identifiers ids; - - ids.port_id = FC_FID_DIR_SERV; - ids.port_name = -1; - ids.node_name = -1; - ids.roles = FC_RPORT_ROLE_UNKNOWN; FC_LPORT_DBG(lport, "Entered DNS state from %s state\n", fc_lport_state(lport)); @@ -1300,7 +1289,7 @@ static void fc_lport_enter_dns(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_DNS); mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_create(lport, &ids); + rdata = lport->tt.rport_create(lport, FC_FID_DIR_SERV); mutex_unlock(&lport->disc.disc_mutex); if (!rdata) goto err; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 99ac056293f5..c667be879be6 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -104,18 +104,18 @@ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, } /** - * fc_rport_create() - create remote port in INIT state. - * @lport: local port. - * @ids: remote port identifiers. + * fc_rport_create() - Create a new remote port + * @lport: The local port that the new remote port is for + * @port_id: The port ID for the new remote port * * Locking note: must be called with the disc_mutex held. */ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, - struct fc_rport_identifiers *ids) + u32 port_id) { struct fc_rport_priv *rdata; - rdata = lport->tt.rport_lookup(lport, ids->port_id); + rdata = lport->tt.rport_lookup(lport, port_id); if (rdata) return rdata; @@ -123,7 +123,11 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, if (!rdata) return NULL; - rdata->ids = *ids; + rdata->ids.node_name = -1; + rdata->ids.port_name = -1; + rdata->ids.port_id = port_id; + rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; + kref_init(&rdata->kref); mutex_init(&rdata->rp_mutex); rdata->local_port = lport; @@ -135,7 +139,7 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); - if (ids->port_id != FC_FID_DIR_SERV) + if (port_id != FC_FID_DIR_SERV) list_add(&rdata->peers, &lport->disc.rports); return rdata; } diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 517dce5c8d0d..cd410c123b99 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -148,16 +148,16 @@ enum fc_rport_state { /** * struct fc_disc_port - temporary discovery port to hold rport identifiers - * @lp: Fibre Channel host port instance - * @peers: node for list management during discovery and RSCN processing - * @ids: identifiers structure to pass to fc_remote_port_add() - * @rport_work: work struct for starting the rport state machine + * @lp: Fibre Channel host port instance + * @peers: Node for list management during discovery and RSCN processing + * @rport_work: Work struct for starting the rport state machine + * @port_id: Port ID of the discovered port */ struct fc_disc_port { struct fc_lport *lp; struct list_head peers; - struct fc_rport_identifiers ids; struct work_struct rport_work; + u32 port_id; }; enum fc_rport_event { @@ -565,10 +565,11 @@ struct libfc_function_template { int (*lport_reset)(struct fc_lport *); /* - * Create a remote port + * Create a remote port with a given port ID + * + * STATUS: OPTIONAL */ - struct fc_rport_priv *(*rport_create)(struct fc_lport *, - struct fc_rport_identifiers *); + struct fc_rport_priv *(*rport_create)(struct fc_lport *, u32); /* * Initiates the RP state machine. It is called from the LP module. -- cgit v1.2.3 From 131203a1ef53f3a4deb3260031bc53c7e4db4a24 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:10 -0700 Subject: [SCSI] libfc: move remote port lookup for ELS requests into fc_rport.c. This moves the remote port lookup for incoming ELS requests into fc_rport.c, in preparation for handing PLOGI and LOGO from unknown rports. This changes the arg to rport_recv_req from an rdata to an lport. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 30 ++--------------- drivers/scsi/libfc/fc_rport.c | 78 +++++++++++++++++++++++-------------------- include/scsi/libfc.h | 2 +- 3 files changed, 44 insertions(+), 66 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index caf68240bddf..d3f4e0c34f5c 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -812,10 +812,6 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, { struct fc_frame_header *fh = fc_frame_header_get(fp); void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *); - struct fc_rport_priv *rdata; - u32 s_id; - u32 d_id; - struct fc_seq_els_data rjt_data; mutex_lock(&lport->lp_mutex); @@ -831,7 +827,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, /* * Check opcode. */ - recv = NULL; + recv = lport->tt.rport_recv_req; switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: recv = fc_lport_recv_flogi_req; @@ -858,29 +854,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, break; } - if (recv) - recv(sp, fp, lport); - else { - /* - * Find session. - * If this is a new incoming PLOGI, we won't find it. - */ - s_id = ntoh24(fh->fh_s_id); - d_id = ntoh24(fh->fh_d_id); - - rdata = lport->tt.rport_lookup(lport, s_id); - if (rdata) - lport->tt.rport_recv_req(sp, fp, rdata); - else { - rjt_data.fp = NULL; - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, - ELS_LS_RJT, - &rjt_data); - fc_frame_free(fp); - } - } + recv(sp, fp, lport); } else { FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n", fr_eof(fp)); diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index cb54115c26cb..acdc72d6b873 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -912,57 +912,61 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) * fc_rport_recv_req() - Receive a request from a rport * @sp: current sequence in the PLOGI exchange * @fp: response frame - * @rdata_arg: private remote port data + * @lport: Fibre Channel local port * - * Locking Note: Called without the rport lock held. This - * function will hold the rport lock, call an _enter_* - * function and then unlock the rport. + * Locking Note: Called with the lport lock held. */ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_rport_priv *rdata) + struct fc_lport *lport) { - struct fc_lport *lport = rdata->local_port; - + struct fc_rport_priv *rdata; struct fc_frame_header *fh; struct fc_seq_els_data els_data; + u32 s_id; u8 op; - mutex_lock(&rdata->rp_mutex); - els_data.fp = NULL; els_data.explan = ELS_EXPL_NONE; els_data.reason = ELS_RJT_NONE; fh = fc_frame_header_get(fp); + s_id = ntoh24(fh->fh_s_id); - if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) { - op = fc_frame_payload_op(fp); - switch (op) { - case ELS_PLOGI: - fc_rport_recv_plogi_req(rdata, sp, fp); - break; - case ELS_PRLI: - fc_rport_recv_prli_req(rdata, sp, fp); - break; - case ELS_PRLO: - fc_rport_recv_prlo_req(rdata, sp, fp); - break; - case ELS_LOGO: - fc_rport_recv_logo_req(rdata, sp, fp); - break; - case ELS_RRQ: - els_data.fp = fp; - lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); - break; - case ELS_REC: - els_data.fp = fp; - lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); - break; - default: - els_data.reason = ELS_RJT_UNSUP; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); - break; - } + rdata = lport->tt.rport_lookup(lport, s_id); + if (!rdata) { + els_data.reason = ELS_RJT_UNAB; + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + fc_frame_free(fp); + return; + } + mutex_lock(&rdata->rp_mutex); + + op = fc_frame_payload_op(fp); + switch (op) { + case ELS_PLOGI: + fc_rport_recv_plogi_req(rdata, sp, fp); + break; + case ELS_PRLI: + fc_rport_recv_prli_req(rdata, sp, fp); + break; + case ELS_PRLO: + fc_rport_recv_prlo_req(rdata, sp, fp); + break; + case ELS_LOGO: + fc_rport_recv_logo_req(rdata, sp, fp); + break; + case ELS_RRQ: + els_data.fp = fp; + lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); + break; + case ELS_REC: + els_data.fp = fp; + lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); + break; + default: + els_data.reason = ELS_RJT_UNSUP; + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + break; } mutex_unlock(&rdata->rp_mutex); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index cd410c123b99..265f106d9fd6 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -598,7 +598,7 @@ struct libfc_function_template { * STATUS: OPTIONAL */ void (*rport_recv_req)(struct fc_seq *, struct fc_frame *, - struct fc_rport_priv *); + struct fc_lport *); /* * lookup an rport by it's port ID. -- cgit v1.2.3 From f657d299cf05883e23e12a69e86842da1df378ad Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:21 -0700 Subject: [SCSI] libfc: improve debug messages for ELS response handlers Improve lport and rport debug messages to indicate whether the response is LS_ACC, LS_RJT, closed, or timeout. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_elsct.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/libfc/fc_lport.c | 20 ++++++++++---------- drivers/scsi/libfc/fc_rport.c | 8 ++++---- include/scsi/libfc.h | 5 +++++ 4 files changed, 57 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 5e8b011af50e..d655924d46b6 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -70,3 +70,41 @@ int fc_elsct_init(struct fc_lport *lport) return 0; } EXPORT_SYMBOL(fc_elsct_init); + +/** + * fc_els_resp_type() - return string describing ELS response for debug. + * @fp: frame pointer with possible error code. + */ +const char *fc_els_resp_type(struct fc_frame *fp) +{ + const char *msg; + if (IS_ERR(fp)) { + switch (-PTR_ERR(fp)) { + case FC_NO_ERR: + msg = "response no error"; + break; + case FC_EX_TIMEOUT: + msg = "response timeout"; + break; + case FC_EX_CLOSED: + msg = "response closed"; + break; + default: + msg = "response unknown error"; + break; + } + } else { + switch (fc_frame_payload_op(fp)) { + case ELS_LS_ACC: + msg = "accept"; + break; + case ELS_LS_RJT: + msg = "reject"; + break; + default: + msg = "response unknown ELS"; + break; + } + } + return msg; +} diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index d3f4e0c34f5c..3f2f72390145 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1006,13 +1006,13 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_frame_header *fh; struct fc_ct_hdr *ct; + FC_LPORT_DBG(lport, "Received a RFT_ID %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a RFT_ID response\n"); - if (lport->state != LPORT_ST_RFT_ID) { FC_LPORT_DBG(lport, "Received a RFT_ID response, but in state " "%s\n", fc_lport_state(lport)); @@ -1060,13 +1060,13 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_frame_header *fh; struct fc_ct_hdr *ct; + FC_LPORT_DBG(lport, "Received a RPN_ID %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a RPN_ID response\n"); - if (lport->state != LPORT_ST_RPN_ID) { FC_LPORT_DBG(lport, "Received a RPN_ID response, but in state " "%s\n", fc_lport_state(lport)); @@ -1112,13 +1112,13 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_lport *lport = lp_arg; u8 op; + FC_LPORT_DBG(lport, "Received a SCR %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a SCR response\n"); - if (lport->state != LPORT_ST_SCR) { FC_LPORT_DBG(lport, "Received a SCR response, but in state " "%s\n", fc_lport_state(lport)); @@ -1333,13 +1333,13 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_lport *lport = lp_arg; u8 op; + FC_LPORT_DBG(lport, "Received a LOGO %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a LOGO response\n"); - if (lport->state != LPORT_ST_LOGO) { FC_LPORT_DBG(lport, "Received a LOGO response, but in state " "%s\n", fc_lport_state(lport)); @@ -1415,13 +1415,13 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, unsigned int e_d_tov; u16 mfs; + FC_LPORT_DBG(lport, "Received a FLOGI %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a FLOGI response\n"); - if (lport->state != LPORT_ST_FLOGI) { FC_LPORT_DBG(lport, "Received a FLOGI response, but in state " "%s\n", fc_lport_state(lport)); diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 02200b26d897..d014b285cd1a 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -544,7 +544,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received a PLOGI response\n"); + FC_RPORT_DBG(rdata, "Received a PLOGI %s\n", fc_els_resp_type(fp)); if (rdata->rp_state != RPORT_ST_PLOGI) { FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state " @@ -651,7 +651,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received a PRLI response\n"); + FC_RPORT_DBG(rdata, "Received a PRLI %s\n", fc_els_resp_type(fp)); if (rdata->rp_state != RPORT_ST_PRLI) { FC_RPORT_DBG(rdata, "Received a PRLI response, but in state " @@ -717,7 +717,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received a LOGO response\n"); + FC_RPORT_DBG(rdata, "Received a LOGO %s\n", fc_els_resp_type(fp)); if (rdata->rp_state != RPORT_ST_LOGO) { FC_RPORT_DBG(rdata, "Received a LOGO response, but in state " @@ -801,7 +801,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received a RTV response\n"); + FC_RPORT_DBG(rdata, "Received a RTV %s\n", fc_els_resp_type(fp)); if (rdata->rp_state != RPORT_ST_RTV) { FC_RPORT_DBG(rdata, "Received a RTV response, but in state " diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 265f106d9fd6..e18e5ce5af51 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -1084,4 +1084,9 @@ void fc_destroy_exch_mgr(void); int fc_setup_rport(void); void fc_destroy_rport(void); +/* + * Internal libfc functions. + */ +const char *fc_els_resp_type(struct fc_frame *); + #endif /* _LIBFC_H_ */ -- cgit v1.2.3 From 370c3bd05cf02afabea9cd3f2de66202d6b516dc Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:47 -0700 Subject: [SCSI] libfc: use ADISC to verify rport login state When rport_login is called on an rport that is already thought to be logged in, use ADISC. If that fails, redo PLOGI. This is less disruptive after fabric changes that don't affect the state of the target. Implement the sending of ADISC via fc_els_fill. Add ADISC state to the rport state machine. This is entered from READY and returns to READY after successful completion. If it fails, the rport is either logged off and deleted or re-does PLOGI. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 122 ++++++++++++++++++++++++++++++++++++++++-- include/scsi/fc_encode.h | 21 ++++++++ include/scsi/libfc.h | 1 + 3 files changed, 139 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index b5bc8724e1a0..c33e25851082 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -62,6 +62,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *); static void fc_rport_enter_rtv(struct fc_rport_priv *); static void fc_rport_enter_ready(struct fc_rport_priv *); static void fc_rport_enter_logo(struct fc_rport_priv *); +static void fc_rport_enter_adisc(struct fc_rport_priv *); static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_seq *, struct fc_frame *); @@ -83,6 +84,7 @@ static const char *fc_rport_state_names[] = { [RPORT_ST_RTV] = "RTV", [RPORT_ST_READY] = "Ready", [RPORT_ST_LOGO] = "LOGO", + [RPORT_ST_ADISC] = "ADISC", [RPORT_ST_DELETE] = "Delete", }; @@ -326,15 +328,25 @@ static void fc_rport_work(struct work_struct *work) * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. + * + * This indicates the intent to be logged into the remote port. + * If it appears we are already logged in, ADISC is used to verify + * the setup. */ int fc_rport_login(struct fc_rport_priv *rdata) { mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Login to port\n"); - - fc_rport_enter_plogi(rdata); - + switch (rdata->rp_state) { + case RPORT_ST_READY: + FC_RPORT_DBG(rdata, "ADISC port\n"); + fc_rport_enter_adisc(rdata); + break; + default: + FC_RPORT_DBG(rdata, "Login to port\n"); + fc_rport_enter_plogi(rdata); + break; + } mutex_unlock(&rdata->rp_mutex); return 0; @@ -448,6 +460,9 @@ static void fc_rport_timeout(struct work_struct *work) case RPORT_ST_LOGO: fc_rport_enter_logo(rdata); break; + case RPORT_ST_ADISC: + fc_rport_enter_adisc(rdata); + break; case RPORT_ST_READY: case RPORT_ST_INIT: case RPORT_ST_DELETE: @@ -473,13 +488,16 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) switch (rdata->rp_state) { case RPORT_ST_PLOGI: - case RPORT_ST_PRLI: case RPORT_ST_LOGO: fc_rport_enter_delete(rdata, RPORT_EV_FAILED); break; case RPORT_ST_RTV: fc_rport_enter_ready(rdata); break; + case RPORT_ST_PRLI: + case RPORT_ST_ADISC: + fc_rport_enter_logo(rdata); + break; case RPORT_ST_DELETE: case RPORT_ST_READY: case RPORT_ST_INIT: @@ -906,6 +924,93 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) kref_get(&rdata->kref); } +/** + * fc_rport_els_adisc_resp() - Address Discovery response handler + * @sp: current sequence in the ADISC exchange + * @fp: response frame + * @rdata_arg: remote port private. + * + * Locking Note: This function will be called without the rport lock + * held, but it will lock, call an _enter_* function or fc_rport_error + * and then unlock the rport. + */ +static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rdata_arg) +{ + struct fc_rport_priv *rdata = rdata_arg; + struct fc_els_adisc *adisc; + u8 op; + + mutex_lock(&rdata->rp_mutex); + + FC_RPORT_DBG(rdata, "Received a ADISC response\n"); + + if (rdata->rp_state != RPORT_ST_ADISC) { + FC_RPORT_DBG(rdata, "Received a ADISC resp but in state %s\n", + fc_rport_state(rdata)); + if (IS_ERR(fp)) + goto err; + goto out; + } + + if (IS_ERR(fp)) { + fc_rport_error(rdata, fp); + goto err; + } + + /* + * If address verification failed. Consider us logged out of the rport. + * Since the rport is still in discovery, we want to be + * logged in, so go to PLOGI state. Otherwise, go back to READY. + */ + op = fc_frame_payload_op(fp); + adisc = fc_frame_payload_get(fp, sizeof(*adisc)); + if (op != ELS_LS_ACC || !adisc || + ntoh24(adisc->adisc_port_id) != rdata->ids.port_id || + get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name || + get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) { + FC_RPORT_DBG(rdata, "ADISC error or mismatch\n"); + fc_rport_enter_plogi(rdata); + } else { + FC_RPORT_DBG(rdata, "ADISC OK\n"); + fc_rport_enter_ready(rdata); + } +out: + fc_frame_free(fp); +err: + mutex_unlock(&rdata->rp_mutex); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); +} + +/** + * fc_rport_enter_adisc() - Send Address Discover (ADISC) request to peer + * @rdata: remote port private data + * + * Locking Note: The rport lock is expected to be held before calling + * this routine. + */ +static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) +{ + struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; + + FC_RPORT_DBG(rdata, "sending ADISC from %s state\n", + fc_rport_state(rdata)); + + fc_rport_state_enter(rdata, RPORT_ST_ADISC); + + fp = fc_frame_alloc(lport, sizeof(struct fc_els_adisc)); + if (!fp) { + fc_rport_error_retry(rdata, fp); + return; + } + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC, + fc_rport_adisc_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); + else + kref_get(&rdata->kref); +} + /** * fc_rport_recv_els_req() - handle a validated ELS request. * @lport: Fibre Channel local port @@ -943,6 +1048,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, case RPORT_ST_PRLI: case RPORT_ST_RTV: case RPORT_ST_READY: + case RPORT_ST_ADISC: break; default: mutex_unlock(&rdata->rp_mutex); @@ -1095,6 +1201,10 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, break; case RPORT_ST_PRLI: case RPORT_ST_READY: + case RPORT_ST_ADISC: + FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " + "- ignored for now\n", rdata->rp_state); + /* XXX TBD - should reset */ break; case RPORT_ST_DELETE: default: @@ -1178,6 +1288,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, case RPORT_ST_PRLI: case RPORT_ST_RTV: case RPORT_ST_READY: + case RPORT_ST_ADISC: reason = ELS_RJT_NONE; break; default: @@ -1283,6 +1394,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, fc_rport_enter_ready(rdata); break; case RPORT_ST_READY: + case RPORT_ST_ADISC: break; default: break; diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h index 24bf764f9884..c5ee6bb79e05 100644 --- a/include/scsi/fc_encode.h +++ b/include/scsi/fc_encode.h @@ -56,6 +56,23 @@ static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl, fh->fh_parm_offset = htonl(parm_offset); } +/** + * fc_adisc_fill() - Fill in adisc request frame + * @lport: local port. + * @fp: fc frame where payload will be placed. + */ +static inline void fc_adisc_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_adisc *adisc; + + adisc = fc_frame_payload_get(fp, sizeof(*adisc)); + memset(adisc, 0, sizeof(*adisc)); + adisc->adisc_cmd = ELS_ADISC; + put_unaligned_be64(lport->wwpn, &adisc->adisc_wwpn); + put_unaligned_be64(lport->wwnn, &adisc->adisc_wwnn); + hton24(adisc->adisc_port_id, fc_host_port_id(lport->host)); +} + /** * fc_ct_hdr_fill- fills ct header and reset ct payload * returns pointer to ct request. @@ -255,6 +272,10 @@ static inline int fc_els_fill(struct fc_lport *lport, enum fc_rctl *r_ctl, enum fc_fh_type *fh_type) { switch (op) { + case ELS_ADISC: + fc_adisc_fill(lport, fp); + break; + case ELS_PLOGI: fc_plogi_fill(lport, fp, ELS_PLOGI); break; diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index e18e5ce5af51..65dc9aacbf70 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -143,6 +143,7 @@ enum fc_rport_state { RPORT_ST_RTV, /* waiting for RTV completion */ RPORT_ST_READY, /* ready for use */ RPORT_ST_LOGO, /* port logout sent */ + RPORT_ST_ADISC, /* Discover Address sent */ RPORT_ST_DELETE, /* port being deleted */ }; -- cgit v1.2.3 From 2ab7e1ecb81ce35ed8e8df512e3fc6338a4c55bb Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:58 -0700 Subject: [SCSI] libfc: send GPN_ID in reaction to single-port RSCNs. When an RSCN indicates changes to individual remote ports, don't blindly log them out and then back in. Instead, determine whether they're still in the directory, by doing GPN_ID. If that is successful, call login, which will send ADISC and reverify, otherwise, call logoff. Perhaps we should just delete the rport, not send LOGO, but it seems safer. Also, fix a possible issue where if a mix of records in the RSCN cause us to queue disc_ports for disc_single and then we decide to do full rediscovery, we leak memory for those disc_ports queued. So, go through the list of disc_ports even if doing full discovery. Free the disc_ports in any case. If any of the disc_single() calls return error, do a full discovery. The ability to fill in GPN_ID requests was added to fc_ct_fill(). For this, it needs the FC_ID to be passed in as an arg. The did parameter for fc_elsct_send() is used for that, since the actual D_DID will always be 0xfffffc for all CT requests so far. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 137 ++++++++++++++++++++++++++++++++++-------- drivers/scsi/libfc/fc_elsct.c | 2 +- include/scsi/fc_encode.h | 16 ++++- 3 files changed, 128 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 4242894cce7c..c48799e9dd8e 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -47,7 +47,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static void fc_disc_done(struct fc_disc *, enum fc_disc_event); static void fc_disc_timeout(struct work_struct *); -static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); +static int fc_disc_single(struct fc_lport *, struct fc_disc_port *); static void fc_disc_restart(struct fc_disc *); /** @@ -83,7 +83,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_disc *disc) { struct fc_lport *lport; - struct fc_rport_priv *rdata; struct fc_els_rscn *rp; struct fc_els_rscn_page *pp; struct fc_seq_els_data rjt_data; @@ -150,6 +149,19 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, } } lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + + /* + * If not doing a complete rediscovery, do GPN_ID on + * the individual ports mentioned in the list. + * If any of these get an error, do a full rediscovery. + * In any case, go through the list and free the entries. + */ + list_for_each_entry_safe(dp, next, &disc_ports, peers) { + list_del(&dp->peers); + if (!redisc) + redisc = fc_disc_single(lport, dp); + kfree(dp); + } if (redisc) { FC_DISC_DBG(disc, "RSCN received: rediscovering\n"); fc_disc_restart(disc); @@ -157,14 +169,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, FC_DISC_DBG(disc, "RSCN received: not rediscovering. " "redisc %d state %d in_prog %d\n", redisc, lport->state, disc->pending); - list_for_each_entry_safe(dp, next, &disc_ports, peers) { - list_del(&dp->peers); - rdata = lport->tt.rport_lookup(lport, dp->port_id); - if (rdata) { - lport->tt.rport_logoff(rdata); - } - fc_disc_single(disc, dp); - } } fc_frame_free(fp); return; @@ -562,32 +566,117 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, } /** - * fc_disc_single() - Discover the directory information for a single target - * @lport: FC local port - * @dp: The port to rediscover + * fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID) + * @sp: exchange sequence + * @fp: response frame + * @rdata_arg: remote port private data * - * Locking Note: This function expects that the disc_mutex is locked - * before it is called. + * Locking Note: This function is called without disc mutex held. */ -static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) +static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rdata_arg) { + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport_priv *new_rdata; struct fc_lport *lport; - struct fc_rport_priv *rdata; + struct fc_disc *disc; + struct fc_ct_hdr *cp; + struct fc_ns_gid_pn *pn; + u64 port_name; - lport = disc->lport; + lport = rdata->local_port; + disc = &lport->disc; - if (dp->port_id == fc_host_port_id(lport->host)) + mutex_lock(&disc->disc_mutex); + if (PTR_ERR(fp) == -FC_EX_CLOSED) goto out; + if (IS_ERR(fp)) + goto redisc; + + cp = fc_frame_payload_get(fp, sizeof(*cp)); + if (!cp) + goto redisc; + if (ntohs(cp->ct_cmd) == FC_FS_ACC) { + if (fr_len(fp) < sizeof(struct fc_frame_header) + + sizeof(*cp) + sizeof(*pn)) + goto redisc; + pn = (struct fc_ns_gid_pn *)(cp + 1); + port_name = get_unaligned_be64(&pn->fn_wwpn); + if (rdata->ids.port_name == -1) + rdata->ids.port_name = port_name; + else if (rdata->ids.port_name != port_name) { + FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. " + "Port-id %x wwpn %llx\n", + rdata->ids.port_id, port_name); + lport->tt.rport_logoff(rdata); - rdata = lport->tt.rport_create(lport, dp->port_id); - if (rdata) { + new_rdata = lport->tt.rport_create(lport, + rdata->ids.port_id); + if (new_rdata) { + new_rdata->disc_id = disc->disc_id; + lport->tt.rport_login(new_rdata); + } + goto out; + } rdata->disc_id = disc->disc_id; - kfree(dp); lport->tt.rport_login(rdata); + } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { + FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n", + cp->ct_reason, cp->ct_explan); + lport->tt.rport_logoff(rdata); + } else { + FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n", + ntohs(cp->ct_cmd)); +redisc: + fc_disc_restart(disc); } - return; out: - kfree(dp); + mutex_unlock(&disc->disc_mutex); + kref_put(&rdata->kref, lport->tt.rport_destroy); +} + +/** + * fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request + * @lport: local port + * @rdata: remote port private data + * + * Locking Note: This function expects that the disc_mutex is locked + * before it is called. + * On failure, an error code is returned. + */ +static int fc_disc_gpn_id_req(struct fc_lport *lport, + struct fc_rport_priv *rdata) +{ + struct fc_frame *fp; + + fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + + sizeof(struct fc_ns_fid)); + if (!fp) + return -ENOMEM; + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID, + fc_disc_gpn_id_resp, rdata, lport->e_d_tov)) + return -ENOMEM; + kref_get(&rdata->kref); + return 0; +} + +/** + * fc_disc_single() - Discover the directory information for a single target + * @lport: local port + * @dp: The port to rediscover + * + * Locking Note: This function expects that the disc_mutex is locked + * before it is called. + */ +static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp) +{ + struct fc_rport_priv *rdata; + + rdata = lport->tt.rport_create(lport, dp->port_id); + if (!rdata) + return -ENOMEM; + rdata->disc_id = 0; + return fc_disc_gpn_id_req(lport, rdata); } /** diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index d655924d46b6..5cfa68732e9d 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -49,7 +49,7 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); else { /* CT requests */ - rc = fc_ct_fill(lport, fp, op, &r_ctl, &fh_type); + rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type); did = FC_FID_DIR_SERV; } diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h index c5ee6bb79e05..27dad703824f 100644 --- a/include/scsi/fc_encode.h +++ b/include/scsi/fc_encode.h @@ -32,6 +32,7 @@ struct fc_ct_req { struct fc_ns_gid_ft gid; struct fc_ns_rn_id rn; struct fc_ns_rft rft; + struct fc_ns_fid fid; } payload; }; @@ -94,10 +95,16 @@ static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp, } /** - * fc_ct_fill - Fill in a name service request frame + * fc_ct_fill() - Fill in a name service request frame + * @lport: local port. + * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries. + * @fp: frame to contain payload. + * @op: CT opcode. + * @r_ctl: pointer to FC header R_CTL. + * @fh_type: pointer to FC-4 type. */ static inline int fc_ct_fill(struct fc_lport *lport, - struct fc_frame *fp, + u32 fc_id, struct fc_frame *fp, unsigned int op, enum fc_rctl *r_ctl, enum fc_fh_type *fh_type) { @@ -109,6 +116,11 @@ static inline int fc_ct_fill(struct fc_lport *lport, ct->payload.gid.fn_fc4_type = FC_TYPE_FCP; break; + case FC_NS_GPN_ID: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_fid)); + hton24(ct->payload.fid.fp_fid, fc_id); + break; + case FC_NS_RFT_ID: ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft)); hton24(ct->payload.rft.fid.fp_fid, -- cgit v1.2.3 From 4c0ba5d2593b5156327263f3ef6d7399dc0717b8 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 5 Sep 2009 07:34:23 +0530 Subject: [SCSI] libiscsi: add completion function for drivers that do not need pdu processing beiscsi does not need the iscsi scsi cmd processing. It does not even get this info on the completion path. This adds a function to just update the sequencing numbers and complete a task. Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 38 +++++++++++++++++++++++++++++++++----- include/scsi/libiscsi.h | 2 ++ 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index a7ee4bb40708..67b2a2b00286 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -109,12 +109,9 @@ inline void iscsi_conn_queue_work(struct iscsi_conn *conn) } EXPORT_SYMBOL_GPL(iscsi_conn_queue_work); -void -iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) +static void __iscsi_update_cmdsn(struct iscsi_session *session, + uint32_t exp_cmdsn, uint32_t max_cmdsn) { - uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); - uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); - /* * standard specifies this check for when to update expected and * max sequence numbers @@ -138,6 +135,12 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) iscsi_conn_queue_work(session->leadconn); } } + +void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) +{ + __iscsi_update_cmdsn(session, be32_to_cpu(hdr->exp_cmdsn), + be32_to_cpu(hdr->max_cmdsn)); +} EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); /** @@ -499,6 +502,31 @@ static void iscsi_complete_task(struct iscsi_task *task, int state) __iscsi_put_task(task); } +/** + * iscsi_complete_scsi_task - finish scsi task normally + * @task: iscsi task for scsi cmd + * @exp_cmdsn: expected cmd sn in cpu format + * @max_cmdsn: max cmd sn in cpu format + * + * This is used when drivers do not need or cannot perform + * lower level pdu processing. + * + * Called with session lock + */ +void iscsi_complete_scsi_task(struct iscsi_task *task, + uint32_t exp_cmdsn, uint32_t max_cmdsn) +{ + struct iscsi_conn *conn = task->conn; + + ISCSI_DBG_SESSION(conn->session, "[itt 0x%x]\n", task->itt); + + conn->last_recv = jiffies; + __iscsi_update_cmdsn(conn->session, exp_cmdsn, max_cmdsn); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); +} +EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task); + + /* * session lock must be held and if not called for a task that is * still pending or from the xmit thread, then xmit thread must diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 61afeb59a836..439c8b75cb69 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -415,6 +415,8 @@ extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t); extern void iscsi_requeue_task(struct iscsi_task *task); extern void iscsi_put_task(struct iscsi_task *task); extern void __iscsi_get_task(struct iscsi_task *task); +extern void iscsi_complete_scsi_task(struct iscsi_task *task, + uint32_t exp_cmdsn, uint32_t max_cmdsn); /* * generic helpers -- cgit v1.2.3 From 661134ad3765348ecd6150a92e736bf28ba40f80 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 5 Sep 2009 07:35:33 +0530 Subject: [SCSI] libiscsi, bnx2i: make bound ep check common bnx2i currently has a check for if a ep is properly bound, so if iscsi_queuecommand/xmit_task is called while there is no ep we will not queue IO. be2iscsi sends IO from queuecommand/xmit_task like how bnx2i does and needs a similar test. This patch has us just use the suspend_bit test for this. When ep_poll has succeeed iscsid will call conn_bind, the LLD will then call iscsi_conn_bind which will clear the suspend bit. When ep_disconnect is called (or if there is a conn error) we set the suspend bit. For the ep_disconnect case I am adding a helper in this patch that will take the session lock to make sure iscsi_queuecommand/xmit_task is not running and it will set the suspend bit. Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 33 +++++++++++++++++++++++++++++++++ include/scsi/libiscsi.h | 1 + 2 files changed, 34 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 67b2a2b00286..8dc73c489a17 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1571,6 +1571,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) goto fault; } + if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) { + reason = FAILURE_SESSION_IN_RECOVERY; + sc->result = DID_REQUEUE; + goto fault; + } + if (iscsi_check_cmdsn_window_closed(conn)) { reason = FAILURE_WINDOW_CLOSED; goto reject; @@ -1810,6 +1816,33 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun, } } +/** + * iscsi_suspend_queue - suspend iscsi_queuecommand + * @conn: iscsi conn to stop queueing IO on + * + * This grabs the session lock to make sure no one is in + * xmit_task/queuecommand, and then sets suspend to prevent + * new commands from being queued. This only needs to be called + * by offload drivers that need to sync a path like ep disconnect + * with the iscsi_queuecommand/xmit_task. To start IO again libiscsi + * will call iscsi_start_tx and iscsi_unblock_session when in FFP. + */ +void iscsi_suspend_queue(struct iscsi_conn *conn) +{ + spin_lock_bh(&conn->session->lock); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + spin_unlock_bh(&conn->session->lock); +} +EXPORT_SYMBOL_GPL(iscsi_suspend_queue); + +/** + * iscsi_suspend_tx - suspend iscsi_data_xmit + * @conn: iscsi conn tp stop processing IO on. + * + * This function sets the suspend bit to prevent iscsi_data_xmit + * from sending new IO, and if work is queued on the xmit thread + * it will wait for it to be completed. + */ void iscsi_suspend_tx(struct iscsi_conn *conn) { struct Scsi_Host *shost = conn->session->host; diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 439c8b75cb69..887e57e3e223 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -390,6 +390,7 @@ extern void iscsi_session_failure(struct iscsi_session *session, extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf); extern void iscsi_suspend_tx(struct iscsi_conn *conn); +extern void iscsi_suspend_queue(struct iscsi_conn *conn); extern void iscsi_conn_queue_work(struct iscsi_conn *conn); #define iscsi_conn_printk(prefix, _c, fmt, a...) \ -- cgit v1.2.3