[SCSI] Merge scsi-misc-2.6 into scsi-rc-fixes-2.6
[safe/jmp/linux-2.6] / drivers / scsi / libfc / fc_lport.c
index 90930c4..79c9e3c 100644 (file)
@@ -56,7 +56,7 @@
  * at the same time.
  *
  * When discovery succeeds or fails a callback is made to the lport as
- * notification. Currently, succesful discovery causes the lport to take no
+ * notification. Currently, successful discovery causes the lport to take no
  * action. A failure will cause the lport to reset. There is likely a circular
  * locking problem with this implementation.
  */
@@ -88,6 +88,7 @@
  */
 
 #include <linux/timer.h>
+#include <linux/slab.h>
 #include <asm/unaligned.h>
 
 #include <scsi/fc/fc_gs.h>
@@ -122,6 +123,7 @@ static const char *fc_lport_state_names[] = {
        [LPORT_ST_RSNN_NN] =  "RSNN_NN",
        [LPORT_ST_RSPN_ID] =  "RSPN_ID",
        [LPORT_ST_RFT_ID] =   "RFT_ID",
+       [LPORT_ST_RFF_ID] =   "RFF_ID",
        [LPORT_ST_SCR] =      "SCR",
        [LPORT_ST_READY] =    "Ready",
        [LPORT_ST_LOGO] =     "LOGO",
@@ -170,7 +172,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
                                    struct fc_rport_priv *rdata,
                                    enum fc_rport_event event)
 {
-       FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event,
+       FC_LPORT_DBG(lport, "Received a %d event for port (%6.6x)\n", event,
                     rdata->ids.port_id);
 
        mutex_lock(&lport->lp_mutex);
@@ -181,7 +183,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
                        fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);
                } else {
                        FC_LPORT_DBG(lport, "Received an READY event "
-                                    "on port (%6x) for the directory "
+                                    "on port (%6.6x) for the directory "
                                     "server, but the lport is not "
                                     "in the DNS state, it's in the "
                                     "%d state", rdata->ids.port_id,
@@ -226,9 +228,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
                               u64 remote_wwnn)
 {
        mutex_lock(&lport->disc.disc_mutex);
-       if (lport->ptp_rdata)
+       if (lport->ptp_rdata) {
                lport->tt.rport_logoff(lport->ptp_rdata);
+               kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
+       }
        lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid);
+       kref_get(&lport->ptp_rdata->kref);
        lport->ptp_rdata->ids.port_name = remote_wwpn;
        lport->ptp_rdata->ids.node_name = remote_wwnn;
        mutex_unlock(&lport->disc.disc_mutex);
@@ -239,17 +244,6 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
 }
 
 /**
- * fc_get_host_port_type() - Return the port type of the given Scsi_Host
- * @shost: The SCSI host whose port type is to be determined
- */
-void fc_get_host_port_type(struct Scsi_Host *shost)
-{
-       /* TODO - currently just NPORT */
-       fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
-}
-EXPORT_SYMBOL(fc_get_host_port_type);
-
-/**
  * fc_get_host_port_state() - Return the port state of the given Scsi_Host
  * @shost:  The SCSI host whose port state is to be determined
  */
@@ -536,7 +530,9 @@ int fc_fabric_login(struct fc_lport *lport)
        int rc = -1;
 
        mutex_lock(&lport->lp_mutex);
-       if (lport->state == LPORT_ST_DISABLED) {
+       if (lport->state == LPORT_ST_DISABLED ||
+           lport->state == LPORT_ST_LOGO) {
+               fc_lport_state_enter(lport, LPORT_ST_RESET);
                fc_lport_enter_reset(lport);
                rc = 0;
        }
@@ -568,8 +564,8 @@ void __fc_linkup(struct fc_lport *lport)
  */
 void fc_linkup(struct fc_lport *lport)
 {
-       printk(KERN_INFO "libfc: Link up on port (%6x)\n",
-              fc_host_port_id(lport->host));
+       printk(KERN_INFO "host%d: libfc: Link up on port (%6.6x)\n",
+              lport->host->host_no, lport->port_id);
 
        mutex_lock(&lport->lp_mutex);
        __fc_linkup(lport);
@@ -598,8 +594,8 @@ void __fc_linkdown(struct fc_lport *lport)
  */
 void fc_linkdown(struct fc_lport *lport)
 {
-       printk(KERN_INFO "libfc: Link down on port (%6x)\n",
-              fc_host_port_id(lport->host));
+       printk(KERN_INFO "host%d: libfc: Link down on port (%6.6x)\n",
+              lport->host->host_no, lport->port_id);
 
        mutex_lock(&lport->lp_mutex);
        __fc_linkdown(lport);
@@ -699,8 +695,9 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
                FC_LPORT_DBG(lport, "Discovery succeeded\n");
                break;
        case DISC_EV_FAILED:
-               printk(KERN_ERR "libfc: Discovery failed for port (%6x)\n",
-                      fc_host_port_id(lport->host));
+               printk(KERN_ERR "host%d: libfc: "
+                      "Discovery failed for port (%6.6x)\n",
+                      lport->host->host_no, lport->port_id);
                mutex_lock(&lport->lp_mutex);
                fc_lport_enter_reset(lport);
                mutex_unlock(&lport->lp_mutex);
@@ -733,6 +730,31 @@ static void fc_lport_enter_ready(struct fc_lport *lport)
 }
 
 /**
+ * fc_lport_set_port_id() - set the local port Port ID
+ * @lport: The local port which will have its Port ID set.
+ * @port_id: The new port ID.
+ * @fp: The frame containing the incoming request, or NULL.
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this function.
+ */
+static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,
+                                struct fc_frame *fp)
+{
+       if (port_id)
+               printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n",
+                      lport->host->host_no, port_id);
+
+       lport->port_id = port_id;
+
+       /* Update the fc_host */
+       fc_host_port_id(lport->host) = port_id;
+
+       if (lport->tt.lport_set_port_id)
+               lport->tt.lport_set_port_id(lport, port_id, fp);
+}
+
+/**
  * fc_lport_recv_flogi_req() - Receive a FLOGI request
  * @sp_in: The sequence the FLOGI is on
  * @rx_fp: The FLOGI frame
@@ -770,11 +792,12 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
                goto out;
        remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);
        if (remote_wwpn == lport->wwpn) {
-               printk(KERN_WARNING "libfc: Received FLOGI from port "
-                      "with same WWPN %llx\n", remote_wwpn);
+               printk(KERN_WARNING "host%d: libfc: Received FLOGI from port "
+                      "with same WWPN %16.16llx\n",
+                      lport->host->host_no, remote_wwpn);
                goto out;
        }
-       FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn);
+       FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn);
 
        /*
         * XXX what is the right thing to do for FIDs?
@@ -790,7 +813,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
                remote_fid = FC_LOCAL_PTP_FID_HI;
        }
 
-       fc_host_port_id(lport->host) = local_fid;
+       fc_lport_set_port_id(lport, local_fid, rx_fp);
 
        fp = fc_frame_alloc(lport, sizeof(*flp));
        if (fp) {
@@ -805,7 +828,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
                 */
                f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
                ep = fc_seq_exch(sp);
-               fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
+               fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid,
                               FC_TYPE_ELS, f_ctl, 0);
                lport->tt.seq_send(lport, sp, fp);
 
@@ -920,13 +943,19 @@ static void fc_lport_reset_locked(struct fc_lport *lport)
        if (lport->dns_rdata)
                lport->tt.rport_logoff(lport->dns_rdata);
 
-       lport->ptp_rdata = NULL;
+       if (lport->ptp_rdata) {
+               lport->tt.rport_logoff(lport->ptp_rdata);
+               kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
+               lport->ptp_rdata = NULL;
+       }
 
        lport->tt.disc_stop(lport);
 
        lport->tt.exch_mgr_reset(lport, 0, 0);
        fc_host_fabric_name(lport->host) = 0;
-       fc_host_port_id(lport->host) = 0;
+
+       if (lport->port_id)
+               fc_lport_set_port_id(lport, 0, NULL);
 }
 
 /**
@@ -941,6 +970,9 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
        FC_LPORT_DBG(lport, "Entered RESET state from %s state\n",
                     fc_lport_state(lport));
 
+       if (lport->state == LPORT_ST_DISABLED || lport->state == LPORT_ST_LOGO)
+               return;
+
        if (lport->vport) {
                if (lport->link_up)
                        fc_vport_set_state(lport->vport, FC_VPORT_INITIALIZING);
@@ -1009,6 +1041,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
                        case LPORT_ST_RSNN_NN:
                        case LPORT_ST_RSPN_ID:
                        case LPORT_ST_RFT_ID:
+                       case LPORT_ST_RFF_ID:
                        case LPORT_ST_SCR:
                        case LPORT_ST_DNS:
                        case LPORT_ST_FLOGI:
@@ -1045,7 +1078,7 @@ static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&lport->lp_mutex);
 
-       if (lport->state < LPORT_ST_RNN_ID || lport->state > LPORT_ST_RFT_ID) {
+       if (lport->state < LPORT_ST_RNN_ID || lport->state > LPORT_ST_RFF_ID) {
                FC_LPORT_DBG(lport, "Received a name server response, "
                             "but in state %s\n", fc_lport_state(lport));
                if (IS_ERR(fp))
@@ -1076,6 +1109,9 @@ static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp,
                        fc_lport_enter_ns(lport, LPORT_ST_RFT_ID);
                        break;
                case LPORT_ST_RFT_ID:
+                       fc_lport_enter_ns(lport, LPORT_ST_RFF_ID);
+                       break;
+               case LPORT_ST_RFF_ID:
                        fc_lport_enter_scr(lport);
                        break;
                default:
@@ -1161,7 +1197,8 @@ static void fc_lport_enter_scr(struct fc_lport *lport)
        }
 
        if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR,
-                                 fc_lport_scr_resp, lport, lport->e_d_tov))
+                                 fc_lport_scr_resp, lport,
+                                 2 * lport->r_a_tov))
                fc_lport_error(lport, NULL);
 }
 
@@ -1210,6 +1247,10 @@ static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state)
                cmd = FC_NS_RFT_ID;
                size += sizeof(struct fc_ns_rft);
                break;
+       case LPORT_ST_RFF_ID:
+               cmd = FC_NS_RFF_ID;
+               size += sizeof(struct fc_ns_rff_id);
+               break;
        default:
                fc_lport_error(lport, NULL);
                return;
@@ -1223,7 +1264,7 @@ static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state)
 
        if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, cmd,
                                  fc_lport_ns_resp,
-                                 lport, lport->e_d_tov))
+                                 lport, 3 * lport->r_a_tov))
                fc_lport_error(lport, fp);
 }
 
@@ -1292,6 +1333,7 @@ static void fc_lport_timeout(struct work_struct *work)
        case LPORT_ST_RSNN_NN:
        case LPORT_ST_RSPN_ID:
        case LPORT_ST_RFT_ID:
+       case LPORT_ST_RFF_ID:
                fc_lport_enter_ns(lport, lport->state);
                break;
        case LPORT_ST_SCR:
@@ -1379,7 +1421,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport)
        }
 
        if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO,
-                                 fc_lport_logo_resp, lport, lport->e_d_tov))
+                                 fc_lport_logo_resp, lport,
+                                 2 * lport->r_a_tov))
                fc_lport_error(lport, NULL);
 }
 
@@ -1428,11 +1471,6 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
        fh = fc_frame_header_get(fp);
        did = ntoh24(fh->fh_d_id);
        if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
-
-               printk(KERN_INFO "libfc: Assigned FID (%6x) in FLOGI response\n",
-                      did);
-               fc_host_port_id(lport->host) = did;
-
                flp = fc_frame_payload_get(fp, sizeof(*flp));
                if (flp) {
                        mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1452,8 +1490,11 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
                                if (e_d_tov > lport->e_d_tov)
                                        lport->e_d_tov = e_d_tov;
                                lport->r_a_tov = 2 * e_d_tov;
-                               printk(KERN_INFO "libfc: Port (%6x) entered "
-                                      "point to point mode\n", did);
+                               fc_lport_set_port_id(lport, did, fp);
+                               printk(KERN_INFO "host%d: libfc: "
+                                      "Port (%6.6x) entered "
+                                      "point-to-point mode\n",
+                                      lport->host->host_no, did);
                                fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
                                                   get_unaligned_be64(
                                                           &flp->fl_wwpn),
@@ -1464,6 +1505,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
                                lport->r_a_tov = r_a_tov;
                                fc_host_fabric_name(lport->host) =
                                        get_unaligned_be64(&flp->fl_wwnn);
+                               fc_lport_set_port_id(lport, did, fp);
                                fc_lport_enter_dns(lport);
                        }
                }
@@ -1500,7 +1542,9 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
 
        if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp,
                                  lport->vport ? ELS_FDISC : ELS_FLOGI,
-                                 fc_lport_flogi_resp, lport, lport->e_d_tov))
+                                 fc_lport_flogi_resp, lport,
+                                 lport->vport ? 2 * lport->r_a_tov :
+                                 lport->e_d_tov))
                fc_lport_error(lport, NULL);
 }
 
@@ -1641,8 +1685,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job,
        char *pp;
        int len;
 
-       fp = fc_frame_alloc(lport, sizeof(struct fc_frame_header) +
-                           job->request_payload.payload_len);
+       fp = fc_frame_alloc(lport, job->request_payload.payload_len);
        if (!fp)
                return -ENOMEM;
 
@@ -1656,7 +1699,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job,
        fh = fc_frame_header_get(fp);
        fh->fh_r_ctl = FC_RCTL_ELS_REQ;
        hton24(fh->fh_d_id, did);
-       hton24(fh->fh_s_id, fc_host_port_id(lport->host));
+       hton24(fh->fh_s_id, lport->port_id);
        fh->fh_type = FC_TYPE_ELS;
        hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
               FC_FC_END_SEQ | FC_FC_SEQ_INIT);
@@ -1716,7 +1759,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job,
        fh = fc_frame_header_get(fp);
        fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL;
        hton24(fh->fh_d_id, did);
-       hton24(fh->fh_s_id, fc_host_port_id(lport->host));
+       hton24(fh->fh_s_id, lport->port_id);
        fh->fh_type = FC_TYPE_CT;
        hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
               FC_FC_END_SEQ | FC_FC_SEQ_INIT);
@@ -1758,7 +1801,8 @@ int fc_lport_bsg_request(struct fc_bsg_job *job)
        u32 did;
 
        job->reply->reply_payload_rcv_len = 0;
-       rsp->resid_len = job->reply_payload.payload_len;
+       if (rsp)
+               rsp->resid_len = job->reply_payload.payload_len;
 
        mutex_lock(&lport->lp_mutex);