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)
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_libfc_priv *rdata;
+ struct fc_rport_priv *rdata;
rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL);
if (!rport)
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
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);
/*
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)
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;
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;
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;
ids.port_name = rport->port_name;
ids.node_name = rport->node_name;
+ rdata->event = RPORT_EV_NONE;
mutex_unlock(&rdata->rp_mutex);
new_rport = fc_remote_port_add(lport->host, 0, &ids);
mutex_unlock(&rdata->rp_mutex);
if (rport_ops->event_callback)
rport_ops->event_callback(lport, rport, event);
+ cancel_delayed_work_sync(&rdata->retry_work);
if (trans_state == FC_PORTSTATE_ROGUE)
put_device(&rport->dev);
else {
*/
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);
return 0;
}
+/**
+ * fc_rport_enter_delete() - schedule a remote port to be deleted.
+ * @rport: Fibre Channel remote port
+ * @event: event to report as the reason for deletion
+ *
+ * Locking Note: Called with the rport lock held.
+ *
+ * Allow state change into DELETE only once.
+ *
+ * Call queue_work only if there's no event already pending.
+ * Set the new event so that the old pending event will not occur.
+ * 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,
+ 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_state_enter(rport, RPORT_ST_DELETE);
+
+ if (rdata->event == RPORT_EV_NONE)
+ queue_work(rport_event_queue, &rdata->event_work);
+ rdata->event = event;
+}
+
/**
* fc_rport_logoff() - Logoff and remove an rport
* @rport: Fibre Channel remote port to be removed
*/
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);
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;
}
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);
-
- mutex_unlock(&rdata->rp_mutex);
-
- cancel_delayed_work_sync(&rdata->retry_work);
-
- mutex_lock(&rdata->rp_mutex);
-
- rdata->event = RPORT_EV_STOP;
- queue_work(rport_event_queue, &rdata->event_work);
-
+ fc_rport_enter_delete(rport, RPORT_EV_STOP);
mutex_unlock(&rdata->rp_mutex);
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);
FC_RPORT_DBG(rport, "Port is Ready\n");
+ if (rdata->event == RPORT_EV_NONE)
+ queue_work(rport_event_queue, &rdata->event_work);
rdata->event = RPORT_EV_CREATED;
- queue_work(rport_event_queue, &rdata->event_work);
}
/**
* 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_*
*/
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);
break;
case RPORT_ST_READY:
case RPORT_ST_INIT:
- case RPORT_ST_NONE:
+ case RPORT_ST_DELETE:
break;
}
mutex_unlock(&rdata->rp_mutex);
- put_device(&rport->dev);
}
/**
*/
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);
case RPORT_ST_PLOGI:
case RPORT_ST_PRLI:
case RPORT_ST_LOGO:
- rdata->event = RPORT_EV_FAILED;
- fc_rport_state_enter(rport, RPORT_ST_NONE);
- queue_work(rport_event_queue,
- &rdata->event_work);
+ fc_rport_enter_delete(rport, RPORT_EV_FAILED);
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;
*/
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 */
/* no additional delay on exchange timeouts */
if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
delay = 0;
- get_device(&rport->dev);
schedule_delayed_work(&rdata->retry_work, delay);
return;
}
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;
*/
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;
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;
} 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);
- queue_work(rport_event_queue, &rdata->event_work);
+ fc_rport_enter_delete(rport, RPORT_EV_FAILED);
}
out:
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);
fc_rport_enter_rtv(rport);
} 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);
- queue_work(rport_event_queue, &rdata->event_work);
+ fc_rport_enter_delete(rport, RPORT_EV_LOGO);
}
out:
*/
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;
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);
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",
*/
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;
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;
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;
"- 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);
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;
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;
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;
}
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);
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);
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);