staticunsignedint port_scan_backoff = 500;
module_param(port_scan_backoff, uint, 0600);
MODULE_PARM_DESC(port_scan_backoff, "upper limit of port scan random backoff in msecs (default 500)");
staticunsignedint port_scan_ratelimit = 60000;
module_param(port_scan_ratelimit, uint, 0600);
MODULE_PARM_DESC(port_scan_ratelimit, "minimum interval between port scans in msecs (default 60000)");
unsignedint zfcp_fc_port_scan_backoff(void)
{ if (!port_scan_backoff) return 0; return get_random_u32_below(port_scan_backoff);
}
staticvoid zfcp_fc_port_scan(struct zfcp_adapter *adapter)
{ unsignedlong now = jiffies; unsignedlong next = adapter->next_port_scan; unsignedlong delay = 0, max;
/* delay only needed within waiting period */ if (time_before(now, next)) {
delay = next - now; /* paranoia: never ever delay scans longer than specified */
max = msecs_to_jiffies(port_scan_ratelimit + port_scan_backoff);
delay = min(delay, max);
}
/** * zfcp_fc_enqueue_event - safely enqueue FC HBA API event from irq context * @adapter: The adapter where to enqueue the event * @event_code: The event code (as defined in fc_host_event_code in * scsi_transport_fc.h) * @event_data: The event data (e.g. n_port page in case of els)
*/ void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter, enum fc_host_event_code event_code, u32 event_data)
{ struct zfcp_fc_event *event;
event = kmalloc(sizeof(struct zfcp_fc_event), GFP_ATOMIC); if (!event) return;
staticint zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port)
{ int ret = -EIO;
if (mutex_lock_interruptible(&wka_port->mutex)) return -ERESTARTSYS;
if (wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE ||
wka_port->status == ZFCP_FC_WKA_PORT_CLOSING) {
wka_port->status = ZFCP_FC_WKA_PORT_OPENING; if (zfcp_fsf_open_wka_port(wka_port)) { /* could not even send request, nothing to wait for */
wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; goto out;
}
}
wka_port->status = ZFCP_FC_WKA_PORT_CLOSING; if (zfcp_fsf_close_wka_port(wka_port)) { /* could not even send request, nothing to wait for */
wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; goto out;
}
wait_event(wka_port->closed,
wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE);
out:
mutex_unlock(&wka_port->mutex);
}
staticvoid zfcp_fc_wka_port_put(struct zfcp_fc_wka_port *wka_port)
{ if (atomic_dec_return(&wka_port->refcount) != 0) return; /* wait 10 milliseconds, other reqs might pop in */
queue_delayed_work(wka_port->adapter->work_queue, &wka_port->work,
msecs_to_jiffies(10));
}
for (i = 1; i < no_entries; i++) { /* skip head and start with 1st element */
page++;
afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK;
_zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt],
page);
zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN,
*(u32 *)page);
}
zfcp_fc_conditional_port_scan(fsf_req->adapter);
}
set_worker_desc("zgidpn%16llx", port->wwpn); /* < WORKER_DESC_LEN=24 */
ret = zfcp_fc_ns_gid_pn(port); if (ret) { /* could not issue gid_pn for some reason */
zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1"); goto out;
}
if (!port->d_id) {
zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); goto out;
}
/** * zfcp_fc_trigger_did_lookup - trigger the d_id lookup using a GID_PN request * @port: The zfcp_port to lookup the d_id for.
*/ void zfcp_fc_trigger_did_lookup(struct zfcp_port *port)
{
get_device(&port->dev); if (!queue_work(port->adapter->work_queue, &port->gid_pn_work))
put_device(&port->dev);
}
/** * zfcp_fc_plogi_evaluate - evaluate PLOGI playload * @port: zfcp_port structure * @plogi: plogi payload * * Evaluate PLOGI playload and copy important fields into zfcp_port structure
*/ void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fc_els_flogi *plogi)
{ if (be64_to_cpu(plogi->fl_wwpn) != port->wwpn) {
port->d_id = 0;
dev_warn(&port->adapter->ccw_device->dev, "A port opened with WWPN 0x%016Lx returned data that " "identifies it as WWPN 0x%016Lx\n",
(unsignedlonglong) port->wwpn,
(unsignedlonglong) be64_to_cpu(plogi->fl_wwpn)); return;
}
/* re-init to undo drop from zfcp_fc_adisc() */
port->d_id = ntoh24(adisc_resp->adisc_port_id); /* port is still good, nothing to do */
out:
atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status); /* * port ref comes from get_device() in zfcp_fc_test_link() and * work item zfcp_fc_link_test_work() passes ref via * zfcp_fc_adisc() to here, if zfcp_fc_adisc() could send ADISC
*/
put_device(&port->dev);
kmem_cache_free(zfcp_fc_req_cache, fc_req);
}
/* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports
without FC-AL-2 capability, so we don't set it */
fc_req->u.adisc.req.adisc_wwpn = cpu_to_be64(fc_host_port_name(shost));
fc_req->u.adisc.req.adisc_wwnn = cpu_to_be64(fc_host_node_name(shost));
fc_req->u.adisc.req.adisc_cmd = ELS_ADISC;
hton24(fc_req->u.adisc.req.adisc_port_id, fc_host_port_id(shost));
d_id = port->d_id; /* remember as destination for send els below */ /* * Force fresh GID_PN lookup on next port recovery. * Must happen after request setup and before sending request, * to prevent race with port->d_id re-init in zfcp_fc_adisc_handler().
*/
port->d_id = 0;
ret = zfcp_fsf_send_els(adapter, d_id, &fc_req->ct_els,
ZFCP_FC_CTELS_TMO); if (ret)
kmem_cache_free(zfcp_fc_req_cache, fc_req);
retval = zfcp_fc_adisc(port); if (retval == 0) return; /* port ref passed to zfcp_fc_adisc(), no put here */
/* send of ADISC was not possible */
atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1");
out:
put_device(&port->dev);
}
/** * zfcp_fc_test_link - lightweight link test procedure * @port: port to be tested * * Test status of a link to a remote port using the ELS command ADISC. * If there is a problem with the remote port, error recovery steps * will be triggered.
*/ void zfcp_fc_test_link(struct zfcp_port *port)
{
get_device(&port->dev); if (!queue_work(port->adapter->work_queue, &port->test_link_work))
put_device(&port->dev);
}
/** * zfcp_fc_sg_free_table - free memory used by scatterlists * @sg: pointer to scatterlist * @count: number of scatterlist which are to be free'ed * the scatterlist are expected to reference pages always
*/ staticvoid zfcp_fc_sg_free_table(struct scatterlist *sg, int count)
{ int i;
for (i = 0; i < count; i++, sg = sg_next(sg)) if (sg)
free_page((unsignedlong) sg_virt(sg)); else break;
}
/** * zfcp_fc_sg_setup_table - init scatterlist and allocate, assign buffers * @sg: pointer to struct scatterlist * @count: number of scatterlists which should be assigned with buffers * of size page * * Returns: 0 on success, -ENOMEM otherwise
*/ staticint zfcp_fc_sg_setup_table(struct scatterlist *sg, int count)
{ void *addr; int i;
sg_init_table(sg, count); for (i = 0; i < count; i++, sg = sg_next(sg)) {
addr = (void *) get_zeroed_page(GFP_KERNEL); if (!addr) {
zfcp_fc_sg_free_table(sg, i); return -ENOMEM;
}
sg_set_buf(sg, addr, PAGE_SIZE);
} return 0;
}
if (hdr->ct_cmd != cpu_to_be16(FC_FS_ACC)) { if (hdr->ct_reason == FC_FS_RJT_UNABL) return -EAGAIN; /* might be a temporary condition */ return -EIO;
}
if (hdr->ct_mr_size) {
dev_warn(&adapter->ccw_device->dev, "The name server reported %d words residual data\n",
hdr->ct_mr_size); return -E2BIG;
}
/* first entry is the header */ for (x = 1; x < max_entries && !last; x++) { if (x % (ZFCP_FC_GPN_FT_ENT_PAGE + 1))
acc++; else
acc = sg_virt(++sg);
last = acc->fp_flags & FC_NS_FID_LAST;
d_id = ntoh24(acc->fp_fid);
/* don't attach ports with a well known address */ if (d_id >= FC_FID_WELL_KNOWN_BASE) continue; /* skip the adapter's port and known remote ports */ if (be64_to_cpu(acc->fp_wwpn) ==
fc_host_port_name(adapter->scsi_host)) continue;
port = zfcp_port_enqueue(adapter, be64_to_cpu(acc->fp_wwpn),
ZFCP_STATUS_COMMON_NOESC, d_id); if (!IS_ERR(port))
zfcp_erp_port_reopen(port, 0, "fcegpf1"); elseif (PTR_ERR(port) != -EEXIST)
ret = PTR_ERR(port);
}
BUILD_BUG_ON(sizeof(rspn_req->name) != sizeof(fc_host_symbolic_name(shost)));
BUILD_BUG_ON(sizeof(rspn_req->name) !=
type_max(typeof(rspn_req->rspn.fr_name_len)) + 1);
len = strscpy(rspn_req->name, fc_host_symbolic_name(shost), sizeof(rspn_req->name)); /* * It should be impossible for this to truncate (see BUILD_BUG_ON() * above), but be robust anyway.
*/ if (WARN_ON(len < 0))
len = sizeof(rspn_req->name) - 1;
rspn_req->rspn.fr_name_len = len;
ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL,
ZFCP_FC_CTELS_TMO); if (!ret)
wait_for_completion(&completion);
}
/** * zfcp_fc_sym_name_update - Retrieve and update the symbolic port name * @work: ns_up_work of the adapter where to update the symbolic port name * * Retrieve the current symbolic port name that may have been set by * the hardware using the GSPN request and update the fc_host * symbolic_name sysfs attribute. When running in NPIV mode (and hence * the port name is unique for this system), update the symbolic port * name to add Linux specific information and update the FC nameserver * using the RSPN request.
*/ void zfcp_fc_sym_name_update(struct work_struct *work)
{ struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter,
ns_up_work); int ret; struct zfcp_fc_req *fc_req;
if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT &&
fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) return;
fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_KERNEL); if (!fc_req) return;
ret = zfcp_fc_wka_port_get(&adapter->gs->ds); if (ret) goto out_free;
ret = zfcp_fc_gspn(adapter, fc_req); if (ret || fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) goto out_ds_put;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.