drivers/scsi/libfc/fc_disc.c

Source file repositories/reference/linux-study-clean/drivers/scsi/libfc/fc_disc.c

File Facts

System
Linux kernel
Corpus path
drivers/scsi/libfc/fc_disc.c
Extension
.c
Size
20059 bytes
Lines
747
Domain
Driver Families
Bucket
drivers/scsi
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (kref_get_unless_zero(&rdata->kref)) {
			fc_rport_logoff(rdata);
			kref_put(&rdata->kref, fc_rport_destroy);
		}
	}
}

/**
 * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
 * @disc:  The discovery object to which the RSCN applies
 * @fp:	   The RSCN frame
 */
static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp)
{
	struct fc_lport *lport;
	struct fc_els_rscn *rp;
	struct fc_els_rscn_page *pp;
	struct fc_seq_els_data rjt_data;
	unsigned int len;
	int redisc = 0;
	enum fc_els_rscn_addr_fmt fmt;
	LIST_HEAD(disc_ports);
	struct fc_disc_port *dp, *next;

	lockdep_assert_held(&disc->disc_mutex);

	lport = fc_disc_lport(disc);

	FC_DISC_DBG(disc, "Received an RSCN event\n");

	/* make sure the frame contains an RSCN message */
	rp = fc_frame_payload_get(fp, sizeof(*rp));
	if (!rp)
		goto reject;
	/* make sure the page length is as expected (4 bytes) */
	if (rp->rscn_page_len != sizeof(*pp))
		goto reject;
	/* get the RSCN payload length */
	len = ntohs(rp->rscn_plen);
	if (len < sizeof(*rp))
		goto reject;
	/* make sure the frame contains the expected payload */
	rp = fc_frame_payload_get(fp, len);
	if (!rp)
		goto reject;
	/* payload must be a multiple of the RSCN page size */
	len -= sizeof(*rp);
	if (len % sizeof(*pp))
		goto reject;

	for (pp = (void *)(rp + 1); len > 0; len -= sizeof(*pp), pp++) {
		fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT;
		fmt &= ELS_RSCN_ADDR_FMT_MASK;
		/*
		 * if we get an address format other than port
		 * (area, domain, fabric), then do a full discovery
		 */
		switch (fmt) {
		case ELS_ADDR_FMT_PORT:
			FC_DISC_DBG(disc, "Port address format for port "
				    "(%6.6x)\n", ntoh24(pp->rscn_fid));
			dp = kzalloc_obj(*dp);
			if (!dp) {
				redisc = 1;
				break;
			}
			dp->lp = lport;
			dp->port_id = ntoh24(pp->rscn_fid);
			list_add_tail(&dp->peers, &disc_ports);
			break;
		case ELS_ADDR_FMT_AREA:
		case ELS_ADDR_FMT_DOM:
		case ELS_ADDR_FMT_FAB:
		default:
			FC_DISC_DBG(disc, "Address format is (%d)\n", fmt);
			redisc = 1;
			break;
		}
	}
	fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL);

	/*
	 * If not doing a complete rediscovery, do GPN_ID on
	 * the individual ports mentioned in the list.
	 * If any of these get an error, do a full rediscovery.
	 * In any case, go through the list and free the entries.
	 */
	list_for_each_entry_safe(dp, next, &disc_ports, peers) {
		list_del(&dp->peers);
		if (!redisc)

Annotation

Implementation Notes