2201 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright(c) 2007 Intel Corporation. All rights reserved.4 *5 * Maintained at www.Open-FCoE.org6 */7 8/*9 * PORT LOCKING NOTES10 *11 * These comments only apply to the 'port code' which consists of the lport,12 * disc and rport blocks.13 *14 * MOTIVATION15 *16 * The lport, disc and rport blocks all have mutexes that are used to protect17 * those objects. The main motivation for these locks is to prevent from18 * having an lport reset just before we send a frame. In that scenario the19 * lport's FID would get set to zero and then we'd send a frame with an20 * invalid SID. We also need to ensure that states don't change unexpectedly21 * while processing another state.22 *23 * HIERARCHY24 *25 * The following hierarchy defines the locking rules. A greater lock26 * may be held before acquiring a lesser lock, but a lesser lock should never27 * be held while attempting to acquire a greater lock. Here is the hierarchy-28 *29 * lport > disc, lport > rport, disc > rport30 *31 * CALLBACKS32 *33 * The callbacks cause complications with this scheme. There is a callback34 * from the rport (to either lport or disc) and a callback from disc35 * (to the lport).36 *37 * As rports exit the rport state machine a callback is made to the owner of38 * the rport to notify success or failure. Since the callback is likely to39 * cause the lport or disc to grab its lock we cannot hold the rport lock40 * while making the callback. To ensure that the rport is not free'd while41 * processing the callback the rport callbacks are serialized through a42 * single-threaded workqueue. An rport would never be free'd while in a43 * callback handler because no other rport work in this queue can be executed44 * at the same time.45 *46 * When discovery succeeds or fails a callback is made to the lport as47 * notification. Currently, successful discovery causes the lport to take no48 * action. A failure will cause the lport to reset. There is likely a circular49 * locking problem with this implementation.50 */51 52/*53 * LPORT LOCKING54 *55 * The critical sections protected by the lport's mutex are quite broad and56 * may be improved upon in the future. The lport code and its locking doesn't57 * influence the I/O path, so excessive locking doesn't penalize I/O58 * performance.59 *60 * The strategy is to lock whenever processing a request or response. Note61 * that every _enter_* function corresponds to a state change. They generally62 * change the lports state and then send a request out on the wire. We lock63 * before calling any of these functions to protect that state change. This64 * means that the entry points into the lport block manage the locks while65 * the state machine can transition between states (i.e. _enter_* functions)66 * while always staying protected.67 *68 * When handling responses we also hold the lport mutex broadly. When the69 * lport receives the response frame it locks the mutex and then calls the70 * appropriate handler for the particuar response. Generally a response will71 * trigger a state change and so the lock must already be held.72 *73 * Retries also have to consider the locking. The retries occur from a work74 * context and the work function will lock the lport and then retry the state75 * (i.e. _enter_* function).76 */77 78#include <linux/timer.h>79#include <linux/delay.h>80#include <linux/module.h>81#include <linux/slab.h>82#include <linux/unaligned.h>83 84#include <scsi/fc/fc_gs.h>85 86#include <scsi/libfc.h>87#include <linux/scatterlist.h>88 89#include "fc_encode.h"90#include "fc_libfc.h"91 92/* Fabric IDs to use for point-to-point mode, chosen on whims. */93#define FC_LOCAL_PTP_FID_LO 0x01010194#define FC_LOCAL_PTP_FID_HI 0x01010295 96#define DNS_DELAY 3 /* Discovery delay after RSCN (in seconds)*/97#define MAX_CT_PAYLOAD 204898#define DISCOVERED_PORTS 499#define NUMBER_OF_PORTS 1100 101static void fc_lport_error(struct fc_lport *, struct fc_frame *);102 103static void fc_lport_enter_reset(struct fc_lport *);104static void fc_lport_enter_flogi(struct fc_lport *);105static void fc_lport_enter_dns(struct fc_lport *);106static void fc_lport_enter_ns(struct fc_lport *, enum fc_lport_state);107static void fc_lport_enter_scr(struct fc_lport *);108static void fc_lport_enter_ready(struct fc_lport *);109static void fc_lport_enter_logo(struct fc_lport *);110static void fc_lport_enter_fdmi(struct fc_lport *lport);111static void fc_lport_enter_ms(struct fc_lport *, enum fc_lport_state);112 113static const char *fc_lport_state_names[] = {114 [LPORT_ST_DISABLED] = "disabled",115 [LPORT_ST_FLOGI] = "FLOGI",116 [LPORT_ST_DNS] = "dNS",117 [LPORT_ST_RNN_ID] = "RNN_ID",118 [LPORT_ST_RSNN_NN] = "RSNN_NN",119 [LPORT_ST_RSPN_ID] = "RSPN_ID",120 [LPORT_ST_RFT_ID] = "RFT_ID",121 [LPORT_ST_RFF_ID] = "RFF_ID",122 [LPORT_ST_FDMI] = "FDMI",123 [LPORT_ST_RHBA] = "RHBA",124 [LPORT_ST_RPA] = "RPA",125 [LPORT_ST_DHBA] = "DHBA",126 [LPORT_ST_DPRT] = "DPRT",127 [LPORT_ST_SCR] = "SCR",128 [LPORT_ST_READY] = "Ready",129 [LPORT_ST_LOGO] = "LOGO",130 [LPORT_ST_RESET] = "reset",131};132 133/**134 * struct fc_bsg_info - FC Passthrough managemet structure135 * @job: The passthrough job136 * @lport: The local port to pass through a command137 * @rsp_code: The expected response code138 * @sg: job->reply_payload.sg_list139 * @nents: job->reply_payload.sg_cnt140 * @offset: The offset into the response data141 */142struct fc_bsg_info {143 struct bsg_job *job;144 struct fc_lport *lport;145 u16 rsp_code;146 struct scatterlist *sg;147 u32 nents;148 size_t offset;149};150 151/**152 * fc_frame_drop() - Dummy frame handler153 * @lport: The local port the frame was received on154 * @fp: The received frame155 */156static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp)157{158 fc_frame_free(fp);159 return 0;160}161 162/**163 * fc_lport_rport_callback() - Event handler for rport events164 * @lport: The lport which is receiving the event165 * @rdata: private remote port data166 * @event: The event that occurred167 *168 * Locking Note: The rport lock should not be held when calling169 * this function.170 */171static void fc_lport_rport_callback(struct fc_lport *lport,172 struct fc_rport_priv *rdata,173 enum fc_rport_event event)174{175 FC_LPORT_DBG(lport, "Received a %d event for port (%6.6x)\n", event,176 rdata->ids.port_id);177 178 mutex_lock(&lport->lp_mutex);179 switch (event) {180 case RPORT_EV_READY:181 if (lport->state == LPORT_ST_DNS) {182 lport->dns_rdata = rdata;183 fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);184 } else if (lport->state == LPORT_ST_FDMI) {185 lport->ms_rdata = rdata;186 fc_lport_enter_ms(lport, LPORT_ST_DHBA);187 } else {188 FC_LPORT_DBG(lport, "Received an READY event "189 "on port (%6.6x) for the directory "190 "server, but the lport is not "191 "in the DNS or FDMI state, it's in the "192 "%d state", rdata->ids.port_id,193 lport->state);194 fc_rport_logoff(rdata);195 }196 break;197 case RPORT_EV_LOGO:198 case RPORT_EV_FAILED:199 case RPORT_EV_STOP:200 if (rdata->ids.port_id == FC_FID_DIR_SERV)201 lport->dns_rdata = NULL;202 else if (rdata->ids.port_id == FC_FID_MGMT_SERV)203 lport->ms_rdata = NULL;204 break;205 case RPORT_EV_NONE:206 break;207 }208 mutex_unlock(&lport->lp_mutex);209}210 211/**212 * fc_lport_state() - Return a string which represents the lport's state213 * @lport: The lport whose state is to converted to a string214 */215static const char *fc_lport_state(struct fc_lport *lport)216{217 const char *cp;218 219 cp = fc_lport_state_names[lport->state];220 if (!cp)221 cp = "unknown";222 return cp;223}224 225/**226 * fc_lport_ptp_setup() - Create an rport for point-to-point mode227 * @lport: The lport to attach the ptp rport to228 * @remote_fid: The FID of the ptp rport229 * @remote_wwpn: The WWPN of the ptp rport230 * @remote_wwnn: The WWNN of the ptp rport231 */232static void fc_lport_ptp_setup(struct fc_lport *lport,233 u32 remote_fid, u64 remote_wwpn,234 u64 remote_wwnn)235{236 lockdep_assert_held(&lport->lp_mutex);237 238 if (lport->ptp_rdata) {239 fc_rport_logoff(lport->ptp_rdata);240 kref_put(&lport->ptp_rdata->kref, fc_rport_destroy);241 }242 mutex_lock(&lport->disc.disc_mutex);243 lport->ptp_rdata = fc_rport_create(lport, remote_fid);244 if (!lport->ptp_rdata) {245 printk(KERN_WARNING "libfc: Failed to setup lport 0x%x\n",246 lport->port_id);247 mutex_unlock(&lport->disc.disc_mutex);248 return;249 }250 kref_get(&lport->ptp_rdata->kref);251 lport->ptp_rdata->ids.port_name = remote_wwpn;252 lport->ptp_rdata->ids.node_name = remote_wwnn;253 mutex_unlock(&lport->disc.disc_mutex);254 255 fc_rport_login(lport->ptp_rdata);256 257 fc_lport_enter_ready(lport);258}259 260/**261 * fc_get_host_port_state() - Return the port state of the given Scsi_Host262 * @shost: The SCSI host whose port state is to be determined263 */264void fc_get_host_port_state(struct Scsi_Host *shost)265{266 struct fc_lport *lport = shost_priv(shost);267 268 mutex_lock(&lport->lp_mutex);269 if (!lport->link_up)270 fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;271 else272 switch (lport->state) {273 case LPORT_ST_READY:274 fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;275 break;276 default:277 fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;278 }279 mutex_unlock(&lport->lp_mutex);280}281EXPORT_SYMBOL(fc_get_host_port_state);282 283/**284 * fc_get_host_speed() - Return the speed of the given Scsi_Host285 * @shost: The SCSI host whose port speed is to be determined286 */287void fc_get_host_speed(struct Scsi_Host *shost)288{289 struct fc_lport *lport = shost_priv(shost);290 291 fc_host_speed(shost) = lport->link_speed;292}293EXPORT_SYMBOL(fc_get_host_speed);294 295/**296 * fc_get_host_stats() - Return the Scsi_Host's statistics297 * @shost: The SCSI host whose statistics are to be returned298 */299struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)300{301 struct fc_host_statistics *fc_stats;302 struct fc_lport *lport = shost_priv(shost);303 unsigned int cpu;304 u64 fcp_in_bytes = 0;305 u64 fcp_out_bytes = 0;306 307 fc_stats = &lport->host_stats;308 memset(fc_stats, 0, sizeof(struct fc_host_statistics));309 310 fc_stats->seconds_since_last_reset = (jiffies - lport->boot_time) / HZ;311 312 for_each_possible_cpu(cpu) {313 struct fc_stats *stats;314 315 stats = per_cpu_ptr(lport->stats, cpu);316 317 fc_stats->tx_frames += READ_ONCE(stats->TxFrames);318 fc_stats->tx_words += READ_ONCE(stats->TxWords);319 fc_stats->rx_frames += READ_ONCE(stats->RxFrames);320 fc_stats->rx_words += READ_ONCE(stats->RxWords);321 fc_stats->error_frames += READ_ONCE(stats->ErrorFrames);322 fc_stats->invalid_crc_count += READ_ONCE(stats->InvalidCRCCount);323 fc_stats->fcp_input_requests += READ_ONCE(stats->InputRequests);324 fc_stats->fcp_output_requests += READ_ONCE(stats->OutputRequests);325 fc_stats->fcp_control_requests += READ_ONCE(stats->ControlRequests);326 fcp_in_bytes += READ_ONCE(stats->InputBytes);327 fcp_out_bytes += READ_ONCE(stats->OutputBytes);328 fc_stats->fcp_packet_alloc_failures += READ_ONCE(stats->FcpPktAllocFails);329 fc_stats->fcp_packet_aborts += READ_ONCE(stats->FcpPktAborts);330 fc_stats->fcp_frame_alloc_failures += READ_ONCE(stats->FcpFrameAllocFails);331 fc_stats->link_failure_count += READ_ONCE(stats->LinkFailureCount);332 }333 fc_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000);334 fc_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000);335 fc_stats->lip_count = -1;336 fc_stats->nos_count = -1;337 fc_stats->loss_of_sync_count = -1;338 fc_stats->loss_of_signal_count = -1;339 fc_stats->prim_seq_protocol_err_count = -1;340 fc_stats->dumped_frames = -1;341 342 /* update exches stats */343 fc_exch_update_stats(lport);344 345 return fc_stats;346}347EXPORT_SYMBOL(fc_get_host_stats);348 349/**350 * fc_lport_flogi_fill() - Fill in FLOGI command for request351 * @lport: The local port the FLOGI is for352 * @flogi: The FLOGI command353 * @op: The opcode354 */355static void fc_lport_flogi_fill(struct fc_lport *lport,356 struct fc_els_flogi *flogi,357 unsigned int op)358{359 struct fc_els_csp *sp;360 struct fc_els_cssp *cp;361 362 memset(flogi, 0, sizeof(*flogi));363 flogi->fl_cmd = (u8) op;364 put_unaligned_be64(lport->wwpn, &flogi->fl_wwpn);365 put_unaligned_be64(lport->wwnn, &flogi->fl_wwnn);366 sp = &flogi->fl_csp;367 sp->sp_hi_ver = 0x20;368 sp->sp_lo_ver = 0x20;369 sp->sp_bb_cred = htons(10); /* this gets set by gateway */370 sp->sp_bb_data = htons((u16) lport->mfs);371 cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */372 cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);373 if (op != ELS_FLOGI) {374 sp->sp_features = htons(FC_SP_FT_CIRO);375 sp->sp_tot_seq = htons(255); /* seq. we accept */376 sp->sp_rel_off = htons(0x1f);377 sp->sp_e_d_tov = htonl(lport->e_d_tov);378 379 cp->cp_rdfs = htons((u16) lport->mfs);380 cp->cp_con_seq = htons(255);381 cp->cp_open_seq = 1;382 }383}384 385/**386 * fc_lport_add_fc4_type() - Add a supported FC-4 type to a local port387 * @lport: The local port to add a new FC-4 type to388 * @type: The new FC-4 type389 */390static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type)391{392 __be32 *mp;393 394 mp = &lport->fcts.ff_type_map[type / FC_NS_BPW];395 *mp = htonl(ntohl(*mp) | 1UL << (type % FC_NS_BPW));396}397 398/**399 * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report.400 * @lport: Fibre Channel local port receiving the RLIR401 * @fp: The RLIR request frame402 */403static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp)404{405 lockdep_assert_held(&lport->lp_mutex);406 407 FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n",408 fc_lport_state(lport));409 410 fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL);411 fc_frame_free(fp);412}413 414/**415 * fc_lport_recv_echo_req() - Handle received ECHO request416 * @lport: The local port receiving the ECHO417 * @in_fp: ECHO request frame418 */419static void fc_lport_recv_echo_req(struct fc_lport *lport,420 struct fc_frame *in_fp)421{422 struct fc_frame *fp;423 unsigned int len;424 void *pp;425 void *dp;426 427 lockdep_assert_held(&lport->lp_mutex);428 429 FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n",430 fc_lport_state(lport));431 432 len = fr_len(in_fp) - sizeof(struct fc_frame_header);433 pp = fc_frame_payload_get(in_fp, len);434 435 if (len < sizeof(__be32))436 len = sizeof(__be32);437 438 fp = fc_frame_alloc(lport, len);439 if (fp) {440 dp = fc_frame_payload_get(fp, len);441 memcpy(dp, pp, len);442 *((__be32 *)dp) = htonl(ELS_LS_ACC << 24);443 fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);444 lport->tt.frame_send(lport, fp);445 }446 fc_frame_free(in_fp);447}448 449/**450 * fc_lport_recv_rnid_req() - Handle received Request Node ID data request451 * @lport: The local port receiving the RNID452 * @in_fp: The RNID request frame453 */454static void fc_lport_recv_rnid_req(struct fc_lport *lport,455 struct fc_frame *in_fp)456{457 struct fc_frame *fp;458 struct fc_els_rnid *req;459 struct {460 struct fc_els_rnid_resp rnid;461 struct fc_els_rnid_cid cid;462 struct fc_els_rnid_gen gen;463 } *rp;464 struct fc_seq_els_data rjt_data;465 u8 fmt;466 size_t len;467 468 lockdep_assert_held(&lport->lp_mutex);469 470 FC_LPORT_DBG(lport, "Received RNID request while in state %s\n",471 fc_lport_state(lport));472 473 req = fc_frame_payload_get(in_fp, sizeof(*req));474 if (!req) {475 rjt_data.reason = ELS_RJT_LOGIC;476 rjt_data.explan = ELS_EXPL_NONE;477 fc_seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data);478 } else {479 fmt = req->rnid_fmt;480 len = sizeof(*rp);481 if (fmt != ELS_RNIDF_GEN ||482 ntohl(lport->rnid_gen.rnid_atype) == 0) {483 fmt = ELS_RNIDF_NONE; /* nothing to provide */484 len -= sizeof(rp->gen);485 }486 fp = fc_frame_alloc(lport, len);487 if (fp) {488 rp = fc_frame_payload_get(fp, len);489 memset(rp, 0, len);490 rp->rnid.rnid_cmd = ELS_LS_ACC;491 rp->rnid.rnid_fmt = fmt;492 rp->rnid.rnid_cid_len = sizeof(rp->cid);493 rp->cid.rnid_wwpn = htonll(lport->wwpn);494 rp->cid.rnid_wwnn = htonll(lport->wwnn);495 if (fmt == ELS_RNIDF_GEN) {496 rp->rnid.rnid_sid_len = sizeof(rp->gen);497 memcpy(&rp->gen, &lport->rnid_gen,498 sizeof(rp->gen));499 }500 fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);501 lport->tt.frame_send(lport, fp);502 }503 }504 fc_frame_free(in_fp);505}506 507/**508 * fc_lport_recv_logo_req() - Handle received fabric LOGO request509 * @lport: The local port receiving the LOGO510 * @fp: The LOGO request frame511 */512static void fc_lport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)513{514 lockdep_assert_held(&lport->lp_mutex);515 516 fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL);517 fc_lport_enter_reset(lport);518 fc_frame_free(fp);519}520 521/**522 * fc_fabric_login() - Start the lport state machine523 * @lport: The local port that should log into the fabric524 *525 * Locking Note: This function should not be called526 * with the lport lock held.527 */528int fc_fabric_login(struct fc_lport *lport)529{530 int rc = -1;531 532 mutex_lock(&lport->lp_mutex);533 if (lport->state == LPORT_ST_DISABLED ||534 lport->state == LPORT_ST_LOGO) {535 fc_lport_state_enter(lport, LPORT_ST_RESET);536 fc_lport_enter_reset(lport);537 rc = 0;538 }539 mutex_unlock(&lport->lp_mutex);540 541 return rc;542}543EXPORT_SYMBOL(fc_fabric_login);544 545/**546 * __fc_linkup() - Handler for transport linkup events547 * @lport: The lport whose link is up548 */549void __fc_linkup(struct fc_lport *lport)550{551 lockdep_assert_held(&lport->lp_mutex);552 553 if (!lport->link_up) {554 lport->link_up = 1;555 556 if (lport->state == LPORT_ST_RESET)557 fc_lport_enter_flogi(lport);558 }559}560 561/**562 * fc_linkup() - Handler for transport linkup events563 * @lport: The local port whose link is up564 */565void fc_linkup(struct fc_lport *lport)566{567 printk(KERN_INFO "host%d: libfc: Link up on port (%6.6x)\n",568 lport->host->host_no, lport->port_id);569 570 mutex_lock(&lport->lp_mutex);571 __fc_linkup(lport);572 mutex_unlock(&lport->lp_mutex);573}574EXPORT_SYMBOL(fc_linkup);575 576/**577 * __fc_linkdown() - Handler for transport linkdown events578 * @lport: The lport whose link is down579 */580void __fc_linkdown(struct fc_lport *lport)581{582 lockdep_assert_held(&lport->lp_mutex);583 584 if (lport->link_up) {585 lport->link_up = 0;586 fc_lport_enter_reset(lport);587 lport->tt.fcp_cleanup(lport);588 }589}590 591/**592 * fc_linkdown() - Handler for transport linkdown events593 * @lport: The local port whose link is down594 */595void fc_linkdown(struct fc_lport *lport)596{597 printk(KERN_INFO "host%d: libfc: Link down on port (%6.6x)\n",598 lport->host->host_no, lport->port_id);599 600 mutex_lock(&lport->lp_mutex);601 __fc_linkdown(lport);602 mutex_unlock(&lport->lp_mutex);603}604EXPORT_SYMBOL(fc_linkdown);605 606/**607 * fc_fabric_logoff() - Logout of the fabric608 * @lport: The local port to logoff the fabric609 *610 * Return value:611 * 0 for success, -1 for failure612 */613int fc_fabric_logoff(struct fc_lport *lport)614{615 lport->tt.disc_stop_final(lport);616 mutex_lock(&lport->lp_mutex);617 if (lport->dns_rdata)618 fc_rport_logoff(lport->dns_rdata);619 mutex_unlock(&lport->lp_mutex);620 fc_rport_flush_queue();621 mutex_lock(&lport->lp_mutex);622 fc_lport_enter_logo(lport);623 mutex_unlock(&lport->lp_mutex);624 cancel_delayed_work_sync(&lport->retry_work);625 return 0;626}627EXPORT_SYMBOL(fc_fabric_logoff);628 629/**630 * fc_lport_destroy() - Unregister a fc_lport631 * @lport: The local port to unregister632 *633 * Note:634 * exit routine for fc_lport instance635 * clean-up all the allocated memory636 * and free up other system resources.637 *638 */639int fc_lport_destroy(struct fc_lport *lport)640{641 mutex_lock(&lport->lp_mutex);642 lport->state = LPORT_ST_DISABLED;643 lport->link_up = 0;644 lport->tt.frame_send = fc_frame_drop;645 mutex_unlock(&lport->lp_mutex);646 647 lport->tt.fcp_abort_io(lport);648 lport->tt.disc_stop_final(lport);649 lport->tt.exch_mgr_reset(lport, 0, 0);650 cancel_delayed_work_sync(&lport->retry_work);651 fc_fc4_del_lport(lport);652 return 0;653}654EXPORT_SYMBOL(fc_lport_destroy);655 656/**657 * fc_set_mfs() - Set the maximum frame size for a local port658 * @lport: The local port to set the MFS for659 * @mfs: The new MFS660 */661int fc_set_mfs(struct fc_lport *lport, u32 mfs)662{663 unsigned int old_mfs;664 int rc = -EINVAL;665 666 mutex_lock(&lport->lp_mutex);667 668 old_mfs = lport->mfs;669 670 if (mfs >= FC_MIN_MAX_FRAME) {671 mfs &= ~3;672 if (mfs > FC_MAX_FRAME)673 mfs = FC_MAX_FRAME;674 mfs -= sizeof(struct fc_frame_header);675 lport->mfs = mfs;676 rc = 0;677 }678 679 if (!rc && mfs < old_mfs)680 fc_lport_enter_reset(lport);681 682 mutex_unlock(&lport->lp_mutex);683 684 return rc;685}686EXPORT_SYMBOL(fc_set_mfs);687 688/**689 * fc_lport_disc_callback() - Callback for discovery events690 * @lport: The local port receiving the event691 * @event: The discovery event692 */693static void fc_lport_disc_callback(struct fc_lport *lport,694 enum fc_disc_event event)695{696 switch (event) {697 case DISC_EV_SUCCESS:698 FC_LPORT_DBG(lport, "Discovery succeeded\n");699 break;700 case DISC_EV_FAILED:701 printk(KERN_ERR "host%d: libfc: "702 "Discovery failed for port (%6.6x)\n",703 lport->host->host_no, lport->port_id);704 mutex_lock(&lport->lp_mutex);705 fc_lport_enter_reset(lport);706 mutex_unlock(&lport->lp_mutex);707 break;708 case DISC_EV_NONE:709 WARN_ON(1);710 break;711 }712}713 714/**715 * fc_lport_enter_ready() - Enter the ready state and start discovery716 * @lport: The local port that is ready717 */718static void fc_lport_enter_ready(struct fc_lport *lport)719{720 lockdep_assert_held(&lport->lp_mutex);721 722 FC_LPORT_DBG(lport, "Entered READY from state %s\n",723 fc_lport_state(lport));724 725 fc_lport_state_enter(lport, LPORT_ST_READY);726 if (lport->vport)727 fc_vport_set_state(lport->vport, FC_VPORT_ACTIVE);728 fc_vports_linkchange(lport);729 730 if (!lport->ptp_rdata)731 lport->tt.disc_start(fc_lport_disc_callback, lport);732}733 734/**735 * fc_lport_set_port_id() - set the local port Port ID736 * @lport: The local port which will have its Port ID set.737 * @port_id: The new port ID.738 * @fp: The frame containing the incoming request, or NULL.739 */740static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,741 struct fc_frame *fp)742{743 lockdep_assert_held(&lport->lp_mutex);744 745 if (port_id)746 printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n",747 lport->host->host_no, port_id);748 749 lport->port_id = port_id;750 751 /* Update the fc_host */752 fc_host_port_id(lport->host) = port_id;753 754 if (lport->tt.lport_set_port_id)755 lport->tt.lport_set_port_id(lport, port_id, fp);756}757 758/**759 * fc_lport_set_local_id() - set the local port Port ID for point-to-multipoint760 * @lport: The local port which will have its Port ID set.761 * @port_id: The new port ID.762 *763 * Called by the lower-level driver when transport sets the local port_id.764 * This is used in VN_port to VN_port mode for FCoE, and causes FLOGI and765 * discovery to be skipped.766 */767void fc_lport_set_local_id(struct fc_lport *lport, u32 port_id)768{769 mutex_lock(&lport->lp_mutex);770 771 fc_lport_set_port_id(lport, port_id, NULL);772 773 switch (lport->state) {774 case LPORT_ST_RESET:775 case LPORT_ST_FLOGI:776 if (port_id)777 fc_lport_enter_ready(lport);778 break;779 default:780 break;781 }782 mutex_unlock(&lport->lp_mutex);783}784EXPORT_SYMBOL(fc_lport_set_local_id);785 786/**787 * fc_lport_recv_flogi_req() - Receive a FLOGI request788 * @lport: The local port that received the request789 * @rx_fp: The FLOGI frame790 *791 * A received FLOGI request indicates a point-to-point connection.792 * Accept it with the common service parameters indicating our N port.793 * Set up to do a PLOGI if we have the higher-number WWPN.794 */795static void fc_lport_recv_flogi_req(struct fc_lport *lport,796 struct fc_frame *rx_fp)797{798 struct fc_frame *fp;799 struct fc_frame_header *fh;800 struct fc_els_flogi *flp;801 struct fc_els_flogi *new_flp;802 u64 remote_wwpn;803 u32 remote_fid;804 u32 local_fid;805 806 lockdep_assert_held(&lport->lp_mutex);807 808 FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n",809 fc_lport_state(lport));810 811 remote_fid = fc_frame_sid(rx_fp);812 flp = fc_frame_payload_get(rx_fp, sizeof(*flp));813 if (!flp)814 goto out;815 remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);816 if (remote_wwpn == lport->wwpn) {817 printk(KERN_WARNING "host%d: libfc: Received FLOGI from port "818 "with same WWPN %16.16llx\n",819 lport->host->host_no, remote_wwpn);820 goto out;821 }822 FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn);823 824 /*825 * XXX what is the right thing to do for FIDs?826 * The originator might expect our S_ID to be 0xfffffe.827 * But if so, both of us could end up with the same FID.828 */829 local_fid = FC_LOCAL_PTP_FID_LO;830 if (remote_wwpn < lport->wwpn) {831 local_fid = FC_LOCAL_PTP_FID_HI;832 if (!remote_fid || remote_fid == local_fid)833 remote_fid = FC_LOCAL_PTP_FID_LO;834 } else if (!remote_fid) {835 remote_fid = FC_LOCAL_PTP_FID_HI;836 }837 838 fc_lport_set_port_id(lport, local_fid, rx_fp);839 840 fp = fc_frame_alloc(lport, sizeof(*flp));841 if (fp) {842 new_flp = fc_frame_payload_get(fp, sizeof(*flp));843 fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI);844 new_flp->fl_cmd = (u8) ELS_LS_ACC;845 846 /*847 * Send the response. If this fails, the originator should848 * repeat the sequence.849 */850 fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);851 fh = fc_frame_header_get(fp);852 hton24(fh->fh_s_id, local_fid);853 hton24(fh->fh_d_id, remote_fid);854 lport->tt.frame_send(lport, fp);855 856 } else {857 fc_lport_error(lport, fp);858 }859 fc_lport_ptp_setup(lport, remote_fid, remote_wwpn,860 get_unaligned_be64(&flp->fl_wwnn));861out:862 fc_frame_free(rx_fp);863}864 865/**866 * fc_lport_recv_els_req() - The generic lport ELS request handler867 * @lport: The local port that received the request868 * @fp: The request frame869 *870 * This function will see if the lport handles the request or871 * if an rport should handle the request.872 *873 * Locking Note: This function should not be called with the lport874 * lock held because it will grab the lock.875 */876static void fc_lport_recv_els_req(struct fc_lport *lport,877 struct fc_frame *fp)878{879 mutex_lock(&lport->lp_mutex);880 881 /*882 * Handle special ELS cases like FLOGI, LOGO, and883 * RSCN here. These don't require a session.884 * Even if we had a session, it might not be ready.885 */886 if (!lport->link_up)887 fc_frame_free(fp);888 else {889 /*890 * Check opcode.891 */892 switch (fc_frame_payload_op(fp)) {893 case ELS_FLOGI:894 if (!lport->point_to_multipoint)895 fc_lport_recv_flogi_req(lport, fp);896 else897 fc_rport_recv_req(lport, fp);898 break;899 case ELS_LOGO:900 if (fc_frame_sid(fp) == FC_FID_FLOGI)901 fc_lport_recv_logo_req(lport, fp);902 else903 fc_rport_recv_req(lport, fp);904 break;905 case ELS_RSCN:906 lport->tt.disc_recv_req(lport, fp);907 break;908 case ELS_ECHO:909 fc_lport_recv_echo_req(lport, fp);910 break;911 case ELS_RLIR:912 fc_lport_recv_rlir_req(lport, fp);913 break;914 case ELS_RNID:915 fc_lport_recv_rnid_req(lport, fp);916 break;917 default:918 fc_rport_recv_req(lport, fp);919 break;920 }921 }922 mutex_unlock(&lport->lp_mutex);923}924 925static int fc_lport_els_prli(struct fc_rport_priv *rdata, u32 spp_len,926 const struct fc_els_spp *spp_in,927 struct fc_els_spp *spp_out)928{929 return FC_SPP_RESP_INVL;930}931 932struct fc4_prov fc_lport_els_prov = {933 .prli = fc_lport_els_prli,934 .recv = fc_lport_recv_els_req,935};936 937/**938 * fc_lport_recv() - The generic lport request handler939 * @lport: The lport that received the request940 * @fp: The frame the request is in941 *942 * Locking Note: This function should not be called with the lport943 * lock held because it may grab the lock.944 */945void fc_lport_recv(struct fc_lport *lport, struct fc_frame *fp)946{947 struct fc_frame_header *fh = fc_frame_header_get(fp);948 struct fc_seq *sp = fr_seq(fp);949 struct fc4_prov *prov;950 951 /*952 * Use RCU read lock and module_lock to be sure module doesn't953 * deregister and get unloaded while we're calling it.954 * try_module_get() is inlined and accepts a NULL parameter.955 * Only ELSes and FCP target ops should come through here.956 * The locking is unfortunate, and a better scheme is being sought.957 */958 959 rcu_read_lock();960 if (fh->fh_type >= FC_FC4_PROV_SIZE)961 goto drop;962 prov = rcu_dereference(fc_passive_prov[fh->fh_type]);963 if (!prov || !try_module_get(prov->module))964 goto drop;965 rcu_read_unlock();966 prov->recv(lport, fp);967 module_put(prov->module);968 return;969drop:970 rcu_read_unlock();971 FC_LPORT_DBG(lport, "dropping unexpected frame type %x\n", fh->fh_type);972 fc_frame_free(fp);973 if (sp)974 fc_exch_done(sp);975}976EXPORT_SYMBOL(fc_lport_recv);977 978/**979 * fc_lport_reset() - Reset a local port980 * @lport: The local port which should be reset981 *982 * Locking Note: This functions should not be called with the983 * lport lock held.984 */985int fc_lport_reset(struct fc_lport *lport)986{987 cancel_delayed_work_sync(&lport->retry_work);988 mutex_lock(&lport->lp_mutex);989 fc_lport_enter_reset(lport);990 mutex_unlock(&lport->lp_mutex);991 return 0;992}993EXPORT_SYMBOL(fc_lport_reset);994 995/**996 * fc_lport_reset_locked() - Reset the local port w/ the lport lock held997 * @lport: The local port to be reset998 */999static void fc_lport_reset_locked(struct fc_lport *lport)1000{1001 lockdep_assert_held(&lport->lp_mutex);1002 1003 if (lport->dns_rdata) {1004 fc_rport_logoff(lport->dns_rdata);1005 lport->dns_rdata = NULL;1006 }1007 1008 if (lport->ptp_rdata) {1009 fc_rport_logoff(lport->ptp_rdata);1010 kref_put(&lport->ptp_rdata->kref, fc_rport_destroy);1011 lport->ptp_rdata = NULL;1012 }1013 1014 lport->tt.disc_stop(lport);1015 1016 lport->tt.exch_mgr_reset(lport, 0, 0);1017 fc_host_fabric_name(lport->host) = 0;1018 1019 if (lport->port_id && (!lport->point_to_multipoint || !lport->link_up))1020 fc_lport_set_port_id(lport, 0, NULL);1021}1022 1023/**1024 * fc_lport_enter_reset() - Reset the local port1025 * @lport: The local port to be reset1026 */1027static void fc_lport_enter_reset(struct fc_lport *lport)1028{1029 lockdep_assert_held(&lport->lp_mutex);1030 1031 FC_LPORT_DBG(lport, "Entered RESET state from %s state\n",1032 fc_lport_state(lport));1033 1034 if (lport->state == LPORT_ST_DISABLED || lport->state == LPORT_ST_LOGO)1035 return;1036 1037 if (lport->vport) {1038 if (lport->link_up)1039 fc_vport_set_state(lport->vport, FC_VPORT_INITIALIZING);1040 else1041 fc_vport_set_state(lport->vport, FC_VPORT_LINKDOWN);1042 }1043 fc_lport_state_enter(lport, LPORT_ST_RESET);1044 fc_host_post_event(lport->host, fc_get_event_number(),1045 FCH_EVT_LIPRESET, 0);1046 fc_vports_linkchange(lport);1047 fc_lport_reset_locked(lport);1048 if (lport->link_up)1049 fc_lport_enter_flogi(lport);1050}1051 1052/**1053 * fc_lport_enter_disabled() - Disable the local port1054 * @lport: The local port to be reset1055 */1056static void fc_lport_enter_disabled(struct fc_lport *lport)1057{1058 lockdep_assert_held(&lport->lp_mutex);1059 1060 FC_LPORT_DBG(lport, "Entered disabled state from %s state\n",1061 fc_lport_state(lport));1062 1063 fc_lport_state_enter(lport, LPORT_ST_DISABLED);1064 fc_vports_linkchange(lport);1065 fc_lport_reset_locked(lport);1066}1067 1068/**1069 * fc_lport_error() - Handler for any errors1070 * @lport: The local port that the error was on1071 * @fp: The error code encoded in a frame pointer1072 *1073 * If the error was caused by a resource allocation failure1074 * then wait for half a second and retry, otherwise retry1075 * after the e_d_tov time.1076 */1077static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)1078{1079 unsigned long delay = 0;1080 FC_LPORT_DBG(lport, "Error %ld in state %s, retries %d\n",1081 IS_ERR(fp) ? -PTR_ERR(fp) : 0, fc_lport_state(lport),1082 lport->retry_count);1083 1084 if (PTR_ERR(fp) == -FC_EX_CLOSED)1085 return;1086 1087 /*1088 * Memory allocation failure, or the exchange timed out1089 * or we received LS_RJT.1090 * Retry after delay1091 */1092 if (lport->retry_count < lport->max_retry_count) {1093 lport->retry_count++;1094 if (!fp)1095 delay = msecs_to_jiffies(500);1096 else1097 delay = msecs_to_jiffies(lport->e_d_tov);1098 1099 schedule_delayed_work(&lport->retry_work, delay);1100 } else1101 fc_lport_enter_reset(lport);1102}1103 1104/**1105 * fc_lport_ns_resp() - Handle response to a name server1106 * registration exchange1107 * @sp: current sequence in exchange1108 * @fp: response frame1109 * @lp_arg: Fibre Channel host port instance1110 *1111 * Locking Note: This function will be called without the lport lock1112 * held, but it will lock, call an _enter_* function or fc_lport_error()1113 * and then unlock the lport.1114 */1115static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp,1116 void *lp_arg)1117{1118 struct fc_lport *lport = lp_arg;1119 struct fc_frame_header *fh;1120 struct fc_ct_hdr *ct;1121 1122 FC_LPORT_DBG(lport, "Received a ns %s\n", fc_els_resp_type(fp));1123 1124 if (fp == ERR_PTR(-FC_EX_CLOSED))1125 return;1126 1127 mutex_lock(&lport->lp_mutex);1128 1129 if (lport->state < LPORT_ST_RNN_ID || lport->state > LPORT_ST_RFF_ID) {1130 FC_LPORT_DBG(lport, "Received a name server response, "1131 "but in state %s\n", fc_lport_state(lport));1132 if (IS_ERR(fp))1133 goto err;1134 goto out;1135 }1136 1137 if (IS_ERR(fp)) {1138 fc_lport_error(lport, fp);1139 goto err;1140 }1141 1142 fh = fc_frame_header_get(fp);1143 ct = fc_frame_payload_get(fp, sizeof(*ct));1144 1145 if (fh && ct && fh->fh_type == FC_TYPE_CT &&1146 ct->ct_fs_type == FC_FST_DIR &&1147 ct->ct_fs_subtype == FC_NS_SUBTYPE &&1148 ntohs(ct->ct_cmd) == FC_FS_ACC)1149 switch (lport->state) {1150 case LPORT_ST_RNN_ID:1151 fc_lport_enter_ns(lport, LPORT_ST_RSNN_NN);1152 break;1153 case LPORT_ST_RSNN_NN:1154 fc_lport_enter_ns(lport, LPORT_ST_RSPN_ID);1155 break;1156 case LPORT_ST_RSPN_ID:1157 fc_lport_enter_ns(lport, LPORT_ST_RFT_ID);1158 break;1159 case LPORT_ST_RFT_ID:1160 fc_lport_enter_ns(lport, LPORT_ST_RFF_ID);1161 break;1162 case LPORT_ST_RFF_ID:1163 if (lport->fdmi_enabled)1164 fc_lport_enter_fdmi(lport);1165 else1166 fc_lport_enter_scr(lport);1167 break;1168 default:1169 /* should have already been caught by state checks */1170 break;1171 }1172 else1173 fc_lport_error(lport, fp);1174out:1175 fc_frame_free(fp);1176err:1177 mutex_unlock(&lport->lp_mutex);1178}1179 1180/**1181 * fc_lport_ms_resp() - Handle response to a management server1182 * exchange1183 * @sp: current sequence in exchange1184 * @fp: response frame1185 * @lp_arg: Fibre Channel host port instance1186 *1187 * Locking Note: This function will be called without the lport lock1188 * held, but it will lock, call an _enter_* function or fc_lport_error()1189 * and then unlock the lport.1190 */1191static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp,1192 void *lp_arg)1193{1194 struct fc_lport *lport = lp_arg;1195 struct fc_frame_header *fh;1196 struct fc_ct_hdr *ct;1197 struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host);1198 FC_LPORT_DBG(lport, "Received a ms %s\n", fc_els_resp_type(fp));1199 1200 if (fp == ERR_PTR(-FC_EX_CLOSED))1201 return;1202 1203 mutex_lock(&lport->lp_mutex);1204 1205 if (lport->state < LPORT_ST_RHBA || lport->state > LPORT_ST_DPRT) {1206 FC_LPORT_DBG(lport, "Received a management server response, "1207 "but in state %s\n", fc_lport_state(lport));1208 if (IS_ERR(fp))1209 goto err;1210 goto out;1211 }1212 1213 if (IS_ERR(fp)) {1214 fc_lport_error(lport, fp);1215 goto err;1216 }1217 1218 fh = fc_frame_header_get(fp);1219 ct = fc_frame_payload_get(fp, sizeof(*ct));1220 1221 if (fh && ct && fh->fh_type == FC_TYPE_CT &&1222 ct->ct_fs_type == FC_FST_MGMT &&1223 ct->ct_fs_subtype == FC_FDMI_SUBTYPE) {1224 FC_LPORT_DBG(lport, "Received a management server response, "1225 "reason=%d explain=%d\n",1226 ct->ct_reason,1227 ct->ct_explan);1228 1229 switch (lport->state) {1230 case LPORT_ST_RHBA:1231 if ((ntohs(ct->ct_cmd) == FC_FS_RJT) && fc_host->fdmi_version == FDMI_V2) {1232 FC_LPORT_DBG(lport, "Error for FDMI-V2, fall back to FDMI-V1\n");1233 fc_host->fdmi_version = FDMI_V1;1234 1235 fc_lport_enter_ms(lport, LPORT_ST_RHBA);1236 1237 } else if (ntohs(ct->ct_cmd) == FC_FS_ACC)1238 fc_lport_enter_ms(lport, LPORT_ST_RPA);1239 else /* Error Skip RPA */1240 fc_lport_enter_scr(lport);1241 break;1242 case LPORT_ST_RPA:1243 fc_lport_enter_scr(lport);1244 break;1245 case LPORT_ST_DPRT:1246 fc_lport_enter_ms(lport, LPORT_ST_RHBA);1247 break;1248 case LPORT_ST_DHBA:1249 fc_lport_enter_ms(lport, LPORT_ST_DPRT);1250 break;1251 default:1252 /* should have already been caught by state checks */1253 break;1254 }1255 } else {1256 /* Invalid Frame? */1257 fc_lport_error(lport, fp);1258 }1259out:1260 fc_frame_free(fp);1261err:1262 mutex_unlock(&lport->lp_mutex);1263}1264 1265/**1266 * fc_lport_scr_resp() - Handle response to State Change Register (SCR) request1267 * @sp: current sequence in SCR exchange1268 * @fp: response frame1269 * @lp_arg: Fibre Channel lport port instance that sent the registration request1270 *1271 * Locking Note: This function will be called without the lport lock1272 * held, but it will lock, call an _enter_* function or fc_lport_error1273 * and then unlock the lport.1274 */1275static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp,1276 void *lp_arg)1277{1278 struct fc_lport *lport = lp_arg;1279 u8 op;1280 1281 FC_LPORT_DBG(lport, "Received a SCR %s\n", fc_els_resp_type(fp));1282 1283 if (fp == ERR_PTR(-FC_EX_CLOSED))1284 return;1285 1286 mutex_lock(&lport->lp_mutex);1287 1288 if (lport->state != LPORT_ST_SCR) {1289 FC_LPORT_DBG(lport, "Received a SCR response, but in state "1290 "%s\n", fc_lport_state(lport));1291 if (IS_ERR(fp))1292 goto err;1293 goto out;1294 }1295 1296 if (IS_ERR(fp)) {1297 fc_lport_error(lport, fp);1298 goto err;1299 }1300 1301 op = fc_frame_payload_op(fp);1302 if (op == ELS_LS_ACC)1303 fc_lport_enter_ready(lport);1304 else1305 fc_lport_error(lport, fp);1306 1307out:1308 fc_frame_free(fp);1309err:1310 mutex_unlock(&lport->lp_mutex);1311}1312 1313/**1314 * fc_lport_enter_scr() - Send a SCR (State Change Register) request1315 * @lport: The local port to register for state changes1316 */1317static void fc_lport_enter_scr(struct fc_lport *lport)1318{1319 struct fc_frame *fp;1320 1321 lockdep_assert_held(&lport->lp_mutex);1322 1323 FC_LPORT_DBG(lport, "Entered SCR state from %s state\n",1324 fc_lport_state(lport));1325 1326 fc_lport_state_enter(lport, LPORT_ST_SCR);1327 1328 fp = fc_frame_alloc(lport, sizeof(struct fc_els_scr));1329 if (!fp) {1330 fc_lport_error(lport, fp);1331 return;1332 }1333 1334 if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR,1335 fc_lport_scr_resp, lport,1336 2 * lport->r_a_tov))1337 fc_lport_error(lport, NULL);1338}1339 1340/**1341 * fc_lport_enter_ns() - register some object with the name server1342 * @lport: Fibre Channel local port to register1343 * @state: Local port state1344 */1345static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state)1346{1347 struct fc_frame *fp;1348 enum fc_ns_req cmd;1349 int size = sizeof(struct fc_ct_hdr);1350 size_t len;1351 1352 lockdep_assert_held(&lport->lp_mutex);1353 1354 FC_LPORT_DBG(lport, "Entered %s state from %s state\n",1355 fc_lport_state_names[state],1356 fc_lport_state(lport));1357 1358 fc_lport_state_enter(lport, state);1359 1360 switch (state) {1361 case LPORT_ST_RNN_ID:1362 cmd = FC_NS_RNN_ID;1363 size += sizeof(struct fc_ns_rn_id);1364 break;1365 case LPORT_ST_RSNN_NN:1366 len = strnlen(fc_host_symbolic_name(lport->host), 255);1367 /* if there is no symbolic name, skip to RFT_ID */1368 if (!len)1369 return fc_lport_enter_ns(lport, LPORT_ST_RFT_ID);1370 cmd = FC_NS_RSNN_NN;1371 size += sizeof(struct fc_ns_rsnn) + len;1372 break;1373 case LPORT_ST_RSPN_ID:1374 len = strnlen(fc_host_symbolic_name(lport->host), 255);1375 /* if there is no symbolic name, skip to RFT_ID */1376 if (!len)1377 return fc_lport_enter_ns(lport, LPORT_ST_RFT_ID);1378 cmd = FC_NS_RSPN_ID;1379 size += sizeof(struct fc_ns_rspn) + len;1380 break;1381 case LPORT_ST_RFT_ID:1382 cmd = FC_NS_RFT_ID;1383 size += sizeof(struct fc_ns_rft);1384 break;1385 case LPORT_ST_RFF_ID:1386 cmd = FC_NS_RFF_ID;1387 size += sizeof(struct fc_ns_rff_id);1388 break;1389 default:1390 fc_lport_error(lport, NULL);1391 return;1392 }1393 1394 fp = fc_frame_alloc(lport, size);1395 if (!fp) {1396 fc_lport_error(lport, fp);1397 return;1398 }1399 1400 if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, cmd,1401 fc_lport_ns_resp,1402 lport, 3 * lport->r_a_tov))1403 fc_lport_error(lport, fp);1404}1405 1406static struct fc_rport_operations fc_lport_rport_ops = {1407 .event_callback = fc_lport_rport_callback,1408};1409 1410/**1411 * fc_lport_enter_dns() - Create a fc_rport for the name server1412 * @lport: The local port requesting a remote port for the name server1413 */1414static void fc_lport_enter_dns(struct fc_lport *lport)1415{1416 struct fc_rport_priv *rdata;1417 1418 lockdep_assert_held(&lport->lp_mutex);1419 1420 FC_LPORT_DBG(lport, "Entered DNS state from %s state\n",1421 fc_lport_state(lport));1422 1423 fc_lport_state_enter(lport, LPORT_ST_DNS);1424 1425 mutex_lock(&lport->disc.disc_mutex);1426 rdata = fc_rport_create(lport, FC_FID_DIR_SERV);1427 mutex_unlock(&lport->disc.disc_mutex);1428 if (!rdata)1429 goto err;1430 1431 rdata->ops = &fc_lport_rport_ops;1432 fc_rport_login(rdata);1433 return;1434 1435err:1436 fc_lport_error(lport, NULL);1437}1438 1439/**1440 * fc_lport_enter_ms() - management server commands1441 * @lport: Fibre Channel local port to register1442 * @state: Local port state1443 */1444static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)1445{1446 struct fc_frame *fp;1447 enum fc_fdmi_req cmd;1448 int size = sizeof(struct fc_ct_hdr);1449 size_t len;1450 int numattrs;1451 struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host);1452 lockdep_assert_held(&lport->lp_mutex);1453 1454 FC_LPORT_DBG(lport, "Entered %s state from %s state\n",1455 fc_lport_state_names[state],1456 fc_lport_state(lport));1457 1458 fc_lport_state_enter(lport, state);1459 1460 switch (state) {1461 case LPORT_ST_RHBA:1462 cmd = FC_FDMI_RHBA;1463 /* Number of HBA Attributes */1464 numattrs = 11;1465 len = sizeof(struct fc_fdmi_rhba);1466 len -= sizeof(struct fc_fdmi_attr_entry);1467 1468 len += FC_FDMI_HBA_ATTR_NODENAME_LEN;1469 len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;1470 len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;1471 len += FC_FDMI_HBA_ATTR_MODEL_LEN;1472 len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;1473 len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;1474 len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;1475 len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;1476 len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;1477 len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;1478 len += FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN;1479 1480 1481 if (fc_host->fdmi_version == FDMI_V2) {1482 numattrs += 7;1483 len += FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN;1484 len += FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN;1485 len += FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN;1486 len += FC_FDMI_HBA_ATTR_FABRICNAME_LEN;1487 len += FC_FDMI_HBA_ATTR_BIOSVERSION_LEN;1488 len += FC_FDMI_HBA_ATTR_BIOSSTATE_LEN;1489 len += FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN;1490 }1491 1492 len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);1493 1494 size += len;1495 break;1496 case LPORT_ST_RPA:1497 cmd = FC_FDMI_RPA;1498 /* Number of Port Attributes */1499 numattrs = 6;1500 len = sizeof(struct fc_fdmi_rpa);1501 len -= sizeof(struct fc_fdmi_attr_entry);1502 len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;1503 len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;1504 len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;1505 len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;1506 len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;1507 len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;1508 1509 if (fc_host->fdmi_version == FDMI_V2) {1510 numattrs += 10;1511 len += FC_FDMI_PORT_ATTR_NODENAME_LEN;1512 len += FC_FDMI_PORT_ATTR_PORTNAME_LEN;1513 len += FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN;1514 len += FC_FDMI_PORT_ATTR_PORTTYPE_LEN;1515 len += FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN;1516 len += FC_FDMI_PORT_ATTR_FABRICNAME_LEN;1517 len += FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN;1518 len += FC_FDMI_PORT_ATTR_PORTSTATE_LEN;1519 len += FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN;1520 len += FC_FDMI_PORT_ATTR_PORTID_LEN;1521 }1522 1523 len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);1524 1525 size += len;1526 break;1527 case LPORT_ST_DPRT:1528 cmd = FC_FDMI_DPRT;1529 len = sizeof(struct fc_fdmi_dprt);1530 size += len;1531 break;1532 case LPORT_ST_DHBA:1533 cmd = FC_FDMI_DHBA;1534 len = sizeof(struct fc_fdmi_dhba);1535 size += len;1536 break;1537 default:1538 fc_lport_error(lport, NULL);1539 return;1540 }1541 1542 FC_LPORT_DBG(lport, "Cmd=0x%x Len %d size %d\n",1543 cmd, (int)len, size);1544 fp = fc_frame_alloc(lport, size);1545 if (!fp) {1546 fc_lport_error(lport, fp);1547 return;1548 }1549 1550 if (!lport->tt.elsct_send(lport, FC_FID_MGMT_SERV, fp, cmd,1551 fc_lport_ms_resp,1552 lport, 3 * lport->r_a_tov))1553 fc_lport_error(lport, fp);1554}1555 1556/**1557 * fc_lport_enter_fdmi() - Create a fc_rport for the management server1558 * @lport: The local port requesting a remote port for the management server1559 */1560static void fc_lport_enter_fdmi(struct fc_lport *lport)1561{1562 struct fc_rport_priv *rdata;1563 1564 lockdep_assert_held(&lport->lp_mutex);1565 1566 FC_LPORT_DBG(lport, "Entered FDMI state from %s state\n",1567 fc_lport_state(lport));1568 1569 fc_lport_state_enter(lport, LPORT_ST_FDMI);1570 1571 mutex_lock(&lport->disc.disc_mutex);1572 rdata = fc_rport_create(lport, FC_FID_MGMT_SERV);1573 mutex_unlock(&lport->disc.disc_mutex);1574 if (!rdata)1575 goto err;1576 1577 rdata->ops = &fc_lport_rport_ops;1578 fc_rport_login(rdata);1579 return;1580 1581err:1582 fc_lport_error(lport, NULL);1583}1584 1585/**1586 * fc_lport_timeout() - Handler for the retry_work timer1587 * @work: The work struct of the local port1588 */1589static void fc_lport_timeout(struct work_struct *work)1590{1591 struct fc_lport *lport =1592 container_of(work, struct fc_lport,1593 retry_work.work);1594 struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host);1595 1596 mutex_lock(&lport->lp_mutex);1597 1598 switch (lport->state) {1599 case LPORT_ST_DISABLED:1600 break;1601 case LPORT_ST_READY:1602 break;1603 case LPORT_ST_RESET:1604 break;1605 case LPORT_ST_FLOGI:1606 fc_lport_enter_flogi(lport);1607 break;1608 case LPORT_ST_DNS:1609 fc_lport_enter_dns(lport);1610 break;1611 case LPORT_ST_RNN_ID:1612 case LPORT_ST_RSNN_NN:1613 case LPORT_ST_RSPN_ID:1614 case LPORT_ST_RFT_ID:1615 case LPORT_ST_RFF_ID:1616 fc_lport_enter_ns(lport, lport->state);1617 break;1618 case LPORT_ST_FDMI:1619 fc_lport_enter_fdmi(lport);1620 break;1621 case LPORT_ST_RHBA:1622 if (fc_host->fdmi_version == FDMI_V2) {1623 FC_LPORT_DBG(lport, "timeout for FDMI-V2 RHBA,fall back to FDMI-V1\n");1624 fc_host->fdmi_version = FDMI_V1;1625 fc_lport_enter_ms(lport, LPORT_ST_RHBA);1626 break;1627 }1628 fallthrough;1629 case LPORT_ST_RPA:1630 case LPORT_ST_DHBA:1631 case LPORT_ST_DPRT:1632 FC_LPORT_DBG(lport, "Skipping lport state %s to SCR\n",1633 fc_lport_state(lport));1634 fallthrough;1635 case LPORT_ST_SCR:1636 fc_lport_enter_scr(lport);1637 break;1638 case LPORT_ST_LOGO:1639 fc_lport_enter_logo(lport);1640 break;1641 }1642 1643 mutex_unlock(&lport->lp_mutex);1644}1645 1646/**1647 * fc_lport_logo_resp() - Handle response to LOGO request1648 * @sp: The sequence that the LOGO was on1649 * @fp: The LOGO frame1650 * @lp_arg: The lport port that received the LOGO request1651 *1652 * Locking Note: This function will be called without the lport lock1653 * held, but it will lock, call an _enter_* function or fc_lport_error()1654 * and then unlock the lport.1655 */1656void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,1657 void *lp_arg)1658{1659 struct fc_lport *lport = lp_arg;1660 u8 op;1661 1662 FC_LPORT_DBG(lport, "Received a LOGO %s\n", fc_els_resp_type(fp));1663 1664 if (fp == ERR_PTR(-FC_EX_CLOSED))1665 return;1666 1667 mutex_lock(&lport->lp_mutex);1668 1669 if (lport->state != LPORT_ST_LOGO) {1670 FC_LPORT_DBG(lport, "Received a LOGO response, but in state "1671 "%s\n", fc_lport_state(lport));1672 if (IS_ERR(fp))1673 goto err;1674 goto out;1675 }1676 1677 if (IS_ERR(fp)) {1678 fc_lport_error(lport, fp);1679 goto err;1680 }1681 1682 op = fc_frame_payload_op(fp);1683 if (op == ELS_LS_ACC)1684 fc_lport_enter_disabled(lport);1685 else1686 fc_lport_error(lport, fp);1687 1688out:1689 fc_frame_free(fp);1690err:1691 mutex_unlock(&lport->lp_mutex);1692}1693EXPORT_SYMBOL(fc_lport_logo_resp);1694 1695/**1696 * fc_lport_enter_logo() - Logout of the fabric1697 * @lport: The local port to be logged out1698 */1699static void fc_lport_enter_logo(struct fc_lport *lport)1700{1701 struct fc_frame *fp;1702 struct fc_els_logo *logo;1703 1704 lockdep_assert_held(&lport->lp_mutex);1705 1706 FC_LPORT_DBG(lport, "Entered LOGO state from %s state\n",1707 fc_lport_state(lport));1708 1709 fc_lport_state_enter(lport, LPORT_ST_LOGO);1710 fc_vports_linkchange(lport);1711 1712 fp = fc_frame_alloc(lport, sizeof(*logo));1713 if (!fp) {1714 fc_lport_error(lport, fp);1715 return;1716 }1717 1718 if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO,1719 fc_lport_logo_resp, lport,1720 2 * lport->r_a_tov))1721 fc_lport_error(lport, NULL);1722}1723 1724/**1725 * fc_lport_flogi_resp() - Handle response to FLOGI request1726 * @sp: The sequence that the FLOGI was on1727 * @fp: The FLOGI response frame1728 * @lp_arg: The lport port that received the FLOGI response1729 *1730 * Locking Note: This function will be called without the lport lock1731 * held, but it will lock, call an _enter_* function or fc_lport_error()1732 * and then unlock the lport.1733 */1734void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,1735 void *lp_arg)1736{1737 struct fc_lport *lport = lp_arg;1738 struct fc_frame_header *fh;1739 struct fc_els_flogi *flp;1740 u32 did;1741 u16 csp_flags;1742 unsigned int r_a_tov;1743 unsigned int e_d_tov;1744 u16 mfs;1745 1746 FC_LPORT_DBG(lport, "Received a FLOGI %s\n", fc_els_resp_type(fp));1747 1748 if (fp == ERR_PTR(-FC_EX_CLOSED))1749 return;1750 1751 mutex_lock(&lport->lp_mutex);1752 1753 if (lport->state != LPORT_ST_FLOGI) {1754 FC_LPORT_DBG(lport, "Received a FLOGI response, but in state "1755 "%s\n", fc_lport_state(lport));1756 if (IS_ERR(fp))1757 goto err;1758 goto out;1759 }1760 1761 if (IS_ERR(fp)) {1762 fc_lport_error(lport, fp);1763 goto err;1764 }1765 1766 fh = fc_frame_header_get(fp);1767 did = fc_frame_did(fp);1768 if (fh->fh_r_ctl != FC_RCTL_ELS_REP || did == 0 ||1769 fc_frame_payload_op(fp) != ELS_LS_ACC) {1770 FC_LPORT_DBG(lport, "FLOGI not accepted or bad response\n");1771 fc_lport_error(lport, fp);1772 goto out;1773 }1774 1775 flp = fc_frame_payload_get(fp, sizeof(*flp));1776 if (!flp) {1777 FC_LPORT_DBG(lport, "FLOGI bad response\n");1778 fc_lport_error(lport, fp);1779 goto out;1780 }1781 1782 mfs = ntohs(flp->fl_csp.sp_bb_data) &1783 FC_SP_BB_DATA_MASK;1784 1785 if (mfs < FC_SP_MIN_MAX_PAYLOAD || mfs > FC_SP_MAX_MAX_PAYLOAD) {1786 FC_LPORT_DBG(lport, "FLOGI bad mfs:%hu response, "1787 "lport->mfs:%u\n", mfs, lport->mfs);1788 fc_lport_error(lport, fp);1789 goto out;1790 }1791 1792 if (mfs <= lport->mfs) {1793 lport->mfs = mfs;1794 fc_host_maxframe_size(lport->host) = mfs;1795 }1796 1797 csp_flags = ntohs(flp->fl_csp.sp_features);1798 r_a_tov = ntohl(flp->fl_csp.sp_r_a_tov);1799 e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov);1800 if (csp_flags & FC_SP_FT_EDTR)1801 e_d_tov /= 1000000;1802 1803 lport->npiv_enabled = !!(csp_flags & FC_SP_FT_NPIV_ACC);1804 1805 if ((csp_flags & FC_SP_FT_FPORT) == 0) {1806 if (e_d_tov > lport->e_d_tov)1807 lport->e_d_tov = e_d_tov;1808 lport->r_a_tov = 2 * lport->e_d_tov;1809 fc_lport_set_port_id(lport, did, fp);1810 printk(KERN_INFO "host%d: libfc: "1811 "Port (%6.6x) entered "1812 "point-to-point mode\n",1813 lport->host->host_no, did);1814 fc_lport_ptp_setup(lport, fc_frame_sid(fp),1815 get_unaligned_be64(1816 &flp->fl_wwpn),1817 get_unaligned_be64(1818 &flp->fl_wwnn));1819 } else {1820 if (e_d_tov > lport->e_d_tov)1821 lport->e_d_tov = e_d_tov;1822 if (r_a_tov > lport->r_a_tov)1823 lport->r_a_tov = r_a_tov;1824 fc_host_fabric_name(lport->host) =1825 get_unaligned_be64(&flp->fl_wwnn);1826 fc_lport_set_port_id(lport, did, fp);1827 fc_lport_enter_dns(lport);1828 }1829 1830out:1831 fc_frame_free(fp);1832err:1833 mutex_unlock(&lport->lp_mutex);1834}1835EXPORT_SYMBOL(fc_lport_flogi_resp);1836 1837/**1838 * fc_lport_enter_flogi() - Send a FLOGI request to the fabric manager1839 * @lport: Fibre Channel local port to be logged in to the fabric1840 */1841static void fc_lport_enter_flogi(struct fc_lport *lport)1842{1843 struct fc_frame *fp;1844 1845 lockdep_assert_held(&lport->lp_mutex);1846 1847 FC_LPORT_DBG(lport, "Entered FLOGI state from %s state\n",1848 fc_lport_state(lport));1849 1850 fc_lport_state_enter(lport, LPORT_ST_FLOGI);1851 1852 if (lport->point_to_multipoint) {1853 if (lport->port_id)1854 fc_lport_enter_ready(lport);1855 return;1856 }1857 1858 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));1859 if (!fp)1860 return fc_lport_error(lport, fp);1861 1862 if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp,1863 lport->vport ? ELS_FDISC : ELS_FLOGI,1864 fc_lport_flogi_resp, lport,1865 lport->vport ? 2 * lport->r_a_tov :1866 lport->e_d_tov))1867 fc_lport_error(lport, NULL);1868}1869 1870/**1871 * fc_lport_config() - Configure a fc_lport1872 * @lport: The local port to be configured1873 */1874int fc_lport_config(struct fc_lport *lport)1875{1876 INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout);1877 mutex_init(&lport->lp_mutex);1878 1879 fc_lport_state_enter(lport, LPORT_ST_DISABLED);1880 1881 fc_lport_add_fc4_type(lport, FC_TYPE_FCP);1882 fc_lport_add_fc4_type(lport, FC_TYPE_CT);1883 fc_fc4_conf_lport_params(lport, FC_TYPE_FCP);1884 1885 return 0;1886}1887EXPORT_SYMBOL(fc_lport_config);1888 1889/**1890 * fc_lport_init() - Initialize the lport layer for a local port1891 * @lport: The local port to initialize the exchange layer for1892 */1893int fc_lport_init(struct fc_lport *lport)1894{1895 struct fc_host_attrs *fc_host;1896 1897 fc_host = shost_to_fc_host(lport->host);1898 1899 /* Set FDMI version to FDMI-2 specification*/1900 fc_host->fdmi_version = FDMI_V2;1901 1902 fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT;1903 fc_host_node_name(lport->host) = lport->wwnn;1904 fc_host_port_name(lport->host) = lport->wwpn;1905 fc_host_supported_classes(lport->host) = FC_COS_CLASS3;1906 memset(fc_host_supported_fc4s(lport->host), 0,1907 sizeof(fc_host_supported_fc4s(lport->host)));1908 fc_host_supported_fc4s(lport->host)[2] = 1;1909 fc_host_supported_fc4s(lport->host)[7] = 1;1910 fc_host_num_discovered_ports(lport->host) = 4;1911 1912 /* This value is also unchanging */1913 memset(fc_host_active_fc4s(lport->host), 0,1914 sizeof(fc_host_active_fc4s(lport->host)));1915 fc_host_active_fc4s(lport->host)[2] = 1;1916 fc_host_active_fc4s(lport->host)[7] = 1;1917 fc_host_maxframe_size(lport->host) = lport->mfs;1918 fc_host_supported_speeds(lport->host) = 0;1919 if (lport->link_supported_speeds & FC_PORTSPEED_1GBIT)1920 fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_1GBIT;1921 if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)1922 fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;1923 if (lport->link_supported_speeds & FC_PORTSPEED_40GBIT)1924 fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_40GBIT;1925 if (lport->link_supported_speeds & FC_PORTSPEED_100GBIT)1926 fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_100GBIT;1927 if (lport->link_supported_speeds & FC_PORTSPEED_25GBIT)1928 fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_25GBIT;1929 if (lport->link_supported_speeds & FC_PORTSPEED_50GBIT)1930 fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_50GBIT;1931 if (lport->link_supported_speeds & FC_PORTSPEED_100GBIT)1932 fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_100GBIT;1933 1934 fc_fc4_add_lport(lport);1935 1936 fc_host_num_discovered_ports(lport->host) = DISCOVERED_PORTS;1937 fc_host_port_state(lport->host) = FC_PORTSTATE_ONLINE;1938 fc_host_max_ct_payload(lport->host) = MAX_CT_PAYLOAD;1939 fc_host_num_ports(lport->host) = NUMBER_OF_PORTS;1940 fc_host_bootbios_state(lport->host) = 0X00000000;1941 snprintf(fc_host_bootbios_version(lport->host),1942 FC_SYMBOLIC_NAME_SIZE, "%s", "Unknown");1943 1944 return 0;1945}1946EXPORT_SYMBOL(fc_lport_init);1947 1948/**1949 * fc_lport_bsg_resp() - The common response handler for FC Passthrough requests1950 * @sp: The sequence for the FC Passthrough response1951 * @fp: The response frame1952 * @info_arg: The BSG info that the response is for1953 */1954static void fc_lport_bsg_resp(struct fc_seq *sp, struct fc_frame *fp,1955 void *info_arg)1956{1957 struct fc_bsg_info *info = info_arg;1958 struct bsg_job *job = info->job;1959 struct fc_bsg_reply *bsg_reply = job->reply;1960 struct fc_lport *lport = info->lport;1961 struct fc_frame_header *fh;1962 size_t len;1963 void *buf;1964 1965 if (IS_ERR(fp)) {1966 bsg_reply->result = (PTR_ERR(fp) == -FC_EX_CLOSED) ?1967 -ECONNABORTED : -ETIMEDOUT;1968 job->reply_len = sizeof(uint32_t);1969 bsg_job_done(job, bsg_reply->result,1970 bsg_reply->reply_payload_rcv_len);1971 kfree(info);1972 return;1973 }1974 1975 mutex_lock(&lport->lp_mutex);1976 fh = fc_frame_header_get(fp);1977 len = fr_len(fp) - sizeof(*fh);1978 buf = fc_frame_payload_get(fp, 0);1979 1980 if (fr_sof(fp) == FC_SOF_I3 && !ntohs(fh->fh_seq_cnt)) {1981 /* Get the response code from the first frame payload */1982 unsigned short cmd = (info->rsp_code == FC_FS_ACC) ?1983 ntohs(((struct fc_ct_hdr *)buf)->ct_cmd) :1984 (unsigned short)fc_frame_payload_op(fp);1985 1986 /* Save the reply status of the job */1987 bsg_reply->reply_data.ctels_reply.status =1988 (cmd == info->rsp_code) ?1989 FC_CTELS_STATUS_OK : FC_CTELS_STATUS_REJECT;1990 }1991 1992 bsg_reply->reply_payload_rcv_len +=1993 fc_copy_buffer_to_sglist(buf, len, info->sg, &info->nents,1994 &info->offset, NULL);1995 1996 if (fr_eof(fp) == FC_EOF_T &&1997 (ntoh24(fh->fh_f_ctl) & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) ==1998 (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) {1999 if (bsg_reply->reply_payload_rcv_len >2000 job->reply_payload.payload_len)2001 bsg_reply->reply_payload_rcv_len =2002 job->reply_payload.payload_len;2003 bsg_reply->result = 0;2004 bsg_job_done(job, bsg_reply->result,2005 bsg_reply->reply_payload_rcv_len);2006 kfree(info);2007 }2008 fc_frame_free(fp);2009 mutex_unlock(&lport->lp_mutex);2010}2011 2012/**2013 * fc_lport_els_request() - Send ELS passthrough request2014 * @job: The BSG Passthrough job2015 * @lport: The local port sending the request2016 * @did: The destination port id2017 * @tov: The timeout period (in ms)2018 */2019static int fc_lport_els_request(struct bsg_job *job,2020 struct fc_lport *lport,2021 u32 did, u32 tov)2022{2023 struct fc_bsg_info *info;2024 struct fc_frame *fp;2025 struct fc_frame_header *fh;2026 char *pp;2027 int len;2028 2029 lockdep_assert_held(&lport->lp_mutex);2030 2031 fp = fc_frame_alloc(lport, job->request_payload.payload_len);2032 if (!fp)2033 return -ENOMEM;2034 2035 len = job->request_payload.payload_len;2036 pp = fc_frame_payload_get(fp, len);2037 2038 sg_copy_to_buffer(job->request_payload.sg_list,2039 job->request_payload.sg_cnt,2040 pp, len);2041 2042 fh = fc_frame_header_get(fp);2043 fh->fh_r_ctl = FC_RCTL_ELS_REQ;2044 hton24(fh->fh_d_id, did);2045 hton24(fh->fh_s_id, lport->port_id);2046 fh->fh_type = FC_TYPE_ELS;2047 hton24(fh->fh_f_ctl, FC_FCTL_REQ);2048 fh->fh_cs_ctl = 0;2049 fh->fh_df_ctl = 0;2050 fh->fh_parm_offset = 0;2051 2052 info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL);2053 if (!info) {2054 fc_frame_free(fp);2055 return -ENOMEM;2056 }2057 2058 info->job = job;2059 info->lport = lport;2060 info->rsp_code = ELS_LS_ACC;2061 info->nents = job->reply_payload.sg_cnt;2062 info->sg = job->reply_payload.sg_list;2063 2064 if (!fc_exch_seq_send(lport, fp, fc_lport_bsg_resp,2065 NULL, info, tov)) {2066 kfree(info);2067 return -ECOMM;2068 }2069 return 0;2070}2071 2072/**2073 * fc_lport_ct_request() - Send CT Passthrough request2074 * @job: The BSG Passthrough job2075 * @lport: The local port sending the request2076 * @did: The destination FC-ID2077 * @tov: The timeout period to wait for the response2078 */2079static int fc_lport_ct_request(struct bsg_job *job,2080 struct fc_lport *lport, u32 did, u32 tov)2081{2082 struct fc_bsg_info *info;2083 struct fc_frame *fp;2084 struct fc_frame_header *fh;2085 struct fc_ct_req *ct;2086 size_t len;2087 2088 lockdep_assert_held(&lport->lp_mutex);2089 2090 fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +2091 job->request_payload.payload_len);2092 if (!fp)2093 return -ENOMEM;2094 2095 len = job->request_payload.payload_len;2096 ct = fc_frame_payload_get(fp, len);2097 2098 sg_copy_to_buffer(job->request_payload.sg_list,2099 job->request_payload.sg_cnt,2100 ct, len);2101 2102 fh = fc_frame_header_get(fp);2103 fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL;2104 hton24(fh->fh_d_id, did);2105 hton24(fh->fh_s_id, lport->port_id);2106 fh->fh_type = FC_TYPE_CT;2107 hton24(fh->fh_f_ctl, FC_FCTL_REQ);2108 fh->fh_cs_ctl = 0;2109 fh->fh_df_ctl = 0;2110 fh->fh_parm_offset = 0;2111 2112 info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL);2113 if (!info) {2114 fc_frame_free(fp);2115 return -ENOMEM;2116 }2117 2118 info->job = job;2119 info->lport = lport;2120 info->rsp_code = FC_FS_ACC;2121 info->nents = job->reply_payload.sg_cnt;2122 info->sg = job->reply_payload.sg_list;2123 2124 if (!fc_exch_seq_send(lport, fp, fc_lport_bsg_resp,2125 NULL, info, tov)) {2126 kfree(info);2127 return -ECOMM;2128 }2129 return 0;2130}2131 2132/**2133 * fc_lport_bsg_request() - The common entry point for sending2134 * FC Passthrough requests2135 * @job: The BSG passthrough job2136 */2137int fc_lport_bsg_request(struct bsg_job *job)2138{2139 struct fc_bsg_request *bsg_request = job->request;2140 struct fc_bsg_reply *bsg_reply = job->reply;2141 struct Scsi_Host *shost = fc_bsg_to_shost(job);2142 struct fc_lport *lport = shost_priv(shost);2143 struct fc_rport *rport;2144 struct fc_rport_priv *rdata;2145 int rc = -EINVAL;2146 u32 did, tov;2147 2148 bsg_reply->reply_payload_rcv_len = 0;2149 2150 mutex_lock(&lport->lp_mutex);2151 2152 switch (bsg_request->msgcode) {2153 case FC_BSG_RPT_ELS:2154 rport = fc_bsg_to_rport(job);2155 if (!rport)2156 break;2157 2158 rdata = rport->dd_data;2159 rc = fc_lport_els_request(job, lport, rport->port_id,2160 rdata->e_d_tov);2161 break;2162 2163 case FC_BSG_RPT_CT:2164 rport = fc_bsg_to_rport(job);2165 if (!rport)2166 break;2167 2168 rdata = rport->dd_data;2169 rc = fc_lport_ct_request(job, lport, rport->port_id,2170 rdata->e_d_tov);2171 break;2172 2173 case FC_BSG_HST_CT:2174 did = ntoh24(bsg_request->rqst_data.h_ct.port_id);2175 if (did == FC_FID_DIR_SERV) {2176 rdata = lport->dns_rdata;2177 if (!rdata)2178 break;2179 tov = rdata->e_d_tov;2180 } else {2181 rdata = fc_rport_lookup(lport, did);2182 if (!rdata)2183 break;2184 tov = rdata->e_d_tov;2185 kref_put(&rdata->kref, fc_rport_destroy);2186 }2187 2188 rc = fc_lport_ct_request(job, lport, did, tov);2189 break;2190 2191 case FC_BSG_HST_ELS_NOLOGIN:2192 did = ntoh24(bsg_request->rqst_data.h_els.port_id);2193 rc = fc_lport_els_request(job, lport, did, lport->e_d_tov);2194 break;2195 }2196 2197 mutex_unlock(&lport->lp_mutex);2198 return rc;2199}2200EXPORT_SYMBOL(fc_lport_bsg_request);2201