|
@@ -20,6 +20,7 @@
|
|
|
#ifndef _FC_ENCODE_H_
|
|
|
#define _FC_ENCODE_H_
|
|
|
#include <asm/unaligned.h>
|
|
|
+#include <linux/utsname.h>
|
|
|
|
|
|
/*
|
|
|
* F_CTL values for simple requests and responses.
|
|
@@ -43,6 +44,10 @@ struct fc_ct_req {
|
|
|
struct fc_ns_fid fid;
|
|
|
struct fc_ns_rsnn snn;
|
|
|
struct fc_ns_rspn spn;
|
|
|
+ struct fc_fdmi_rhba rhba;
|
|
|
+ struct fc_fdmi_rpa rpa;
|
|
|
+ struct fc_fdmi_dprt dprt;
|
|
|
+ struct fc_fdmi_dhba dhba;
|
|
|
} payload;
|
|
|
};
|
|
|
|
|
@@ -198,6 +203,300 @@ static inline int fc_ct_ns_fill(struct fc_lport *lport,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * fc_ct_ms_fill() - Fill in a mgmt service request frame
|
|
|
+ * @lport: local port.
|
|
|
+ * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
|
|
|
+ * @fp: frame to contain payload.
|
|
|
+ * @op: CT opcode.
|
|
|
+ * @r_ctl: pointer to FC header R_CTL.
|
|
|
+ * @fh_type: pointer to FC-4 type.
|
|
|
+ */
|
|
|
+static inline int fc_ct_ms_fill(struct fc_lport *lport,
|
|
|
+ u32 fc_id, struct fc_frame *fp,
|
|
|
+ unsigned int op, enum fc_rctl *r_ctl,
|
|
|
+ enum fc_fh_type *fh_type)
|
|
|
+{
|
|
|
+ struct fc_ct_req *ct;
|
|
|
+ size_t len;
|
|
|
+ struct fc_fdmi_attr_entry *entry;
|
|
|
+ struct fs_fdmi_attrs *hba_attrs;
|
|
|
+ int numattrs = 0;
|
|
|
+
|
|
|
+ switch (op) {
|
|
|
+ case FC_FDMI_RHBA:
|
|
|
+ numattrs = 10;
|
|
|
+ len = sizeof(struct fc_fdmi_rhba);
|
|
|
+ len -= sizeof(struct fc_fdmi_attr_entry);
|
|
|
+ len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
|
|
|
+ len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_MODEL_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
|
|
|
+ ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
|
|
|
+ FC_FDMI_SUBTYPE);
|
|
|
+
|
|
|
+ /* HBA Identifier */
|
|
|
+ put_unaligned_be64(lport->wwpn, &ct->payload.rhba.hbaid.id);
|
|
|
+ /* Number of Ports - always 1 */
|
|
|
+ put_unaligned_be32(1, &ct->payload.rhba.port.numport);
|
|
|
+ /* Port Name */
|
|
|
+ put_unaligned_be64(lport->wwpn,
|
|
|
+ &ct->payload.rhba.port.port[0].portname);
|
|
|
+
|
|
|
+ /* HBA Attributes */
|
|
|
+ put_unaligned_be32(numattrs,
|
|
|
+ &ct->payload.rhba.hba_attrs.numattrs);
|
|
|
+ hba_attrs = &ct->payload.rhba.hba_attrs;
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr;
|
|
|
+ /* NodeName*/
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_NODENAME,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ put_unaligned_be64(lport->wwnn,
|
|
|
+ (__be64 *)&entry->value[0]);
|
|
|
+
|
|
|
+ /* Manufacturer */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_NODENAME_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_MANUFACTURER,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_manufacturer(lport->host),
|
|
|
+ FC_FDMI_HBA_ATTR_MANUFACTURER_LEN);
|
|
|
+
|
|
|
+ /* SerialNumber */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_MANUFACTURER_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_SERIALNUMBER,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_serial_number(lport->host),
|
|
|
+ FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN);
|
|
|
+
|
|
|
+ /* Model */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_MODEL_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_MODEL,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_model(lport->host),
|
|
|
+ FC_FDMI_HBA_ATTR_MODEL_LEN);
|
|
|
+
|
|
|
+ /* Model Description */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_MODEL_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_MODELDESCRIPTION,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_model_description(lport->host),
|
|
|
+ FC_FDMI_HBA_ATTR_MODELDESCR_LEN);
|
|
|
+
|
|
|
+ /* Hardware Version */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_MODELDESCR_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_HARDWAREVERSION,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_hardware_version(lport->host),
|
|
|
+ FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN);
|
|
|
+
|
|
|
+ /* Driver Version */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_DRIVERVERSION,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_driver_version(lport->host),
|
|
|
+ FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN);
|
|
|
+
|
|
|
+ /* OptionROM Version */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_OPTIONROMVERSION,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_optionrom_version(lport->host),
|
|
|
+ FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN);
|
|
|
+
|
|
|
+ /* Firmware Version */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_FIRMWAREVERSION,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_firmware_version(lport->host),
|
|
|
+ FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN);
|
|
|
+
|
|
|
+ /* OS Name and Version */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_OSNAMEVERSION,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ snprintf((char *)&entry->value,
|
|
|
+ FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN,
|
|
|
+ "%s v%s",
|
|
|
+ init_utsname()->sysname,
|
|
|
+ init_utsname()->release);
|
|
|
+ break;
|
|
|
+ case FC_FDMI_RPA:
|
|
|
+ numattrs = 6;
|
|
|
+ len = sizeof(struct fc_fdmi_rpa);
|
|
|
+ len -= sizeof(struct fc_fdmi_attr_entry);
|
|
|
+ len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
|
|
|
+ len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
|
|
|
+ ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
|
|
|
+ FC_FDMI_SUBTYPE);
|
|
|
+
|
|
|
+ /* Port Name */
|
|
|
+ put_unaligned_be64(lport->wwpn,
|
|
|
+ &ct->payload.rpa.port.portname);
|
|
|
+
|
|
|
+ /* Port Attributes */
|
|
|
+ put_unaligned_be32(numattrs,
|
|
|
+ &ct->payload.rpa.hba_attrs.numattrs);
|
|
|
+
|
|
|
+ hba_attrs = &ct->payload.rpa.hba_attrs;
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr;
|
|
|
+
|
|
|
+ /* FC4 types */
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_FC4TYPES,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ memcpy(&entry->value, fc_host_supported_fc4s(lport->host),
|
|
|
+ FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
|
|
|
+
|
|
|
+ /* Supported Speed */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_SUPPORTEDSPEED,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+
|
|
|
+ put_unaligned_be32(fc_host_supported_speeds(lport->host),
|
|
|
+ &entry->value);
|
|
|
+
|
|
|
+ /* Current Port Speed */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ put_unaligned_be32(lport->link_speed,
|
|
|
+ &entry->value);
|
|
|
+
|
|
|
+ /* Max Frame Size */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_MAXFRAMESIZE,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ put_unaligned_be32(fc_host_maxframe_size(lport->host),
|
|
|
+ &entry->value);
|
|
|
+
|
|
|
+ /* OS Device Name */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_OSDEVICENAME,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ /* Use the sysfs device name */
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ dev_name(&lport->host->shost_gendev),
|
|
|
+ strnlen(dev_name(&lport->host->shost_gendev),
|
|
|
+ FC_FDMI_PORT_ATTR_HOSTNAME_LEN));
|
|
|
+
|
|
|
+ /* Host Name */
|
|
|
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
|
|
|
+ FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN);
|
|
|
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
|
|
|
+ len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
|
|
|
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_HOSTNAME,
|
|
|
+ &entry->type);
|
|
|
+ put_unaligned_be16(len, &entry->len);
|
|
|
+ if (strlen(fc_host_system_hostname(lport->host)))
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ fc_host_system_hostname(lport->host),
|
|
|
+ strnlen(fc_host_system_hostname(lport->host),
|
|
|
+ FC_FDMI_PORT_ATTR_HOSTNAME_LEN));
|
|
|
+ else
|
|
|
+ strncpy((char *)&entry->value,
|
|
|
+ init_utsname()->nodename,
|
|
|
+ FC_FDMI_PORT_ATTR_HOSTNAME_LEN);
|
|
|
+ break;
|
|
|
+ case FC_FDMI_DPRT:
|
|
|
+ len = sizeof(struct fc_fdmi_dprt);
|
|
|
+ ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
|
|
|
+ FC_FDMI_SUBTYPE);
|
|
|
+ /* Port Name */
|
|
|
+ put_unaligned_be64(lport->wwpn,
|
|
|
+ &ct->payload.dprt.port.portname);
|
|
|
+ break;
|
|
|
+ case FC_FDMI_DHBA:
|
|
|
+ len = sizeof(struct fc_fdmi_dhba);
|
|
|
+ ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
|
|
|
+ FC_FDMI_SUBTYPE);
|
|
|
+ /* HBA Identifier */
|
|
|
+ put_unaligned_be64(lport->wwpn, &ct->payload.dhba.hbaid.id);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ *r_ctl = FC_RCTL_DD_UNSOL_CTL;
|
|
|
+ *fh_type = FC_TYPE_CT;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* fc_ct_fill() - Fill in a common transport service request frame
|
|
|
* @lport: local port.
|
|
@@ -215,6 +514,10 @@ static inline int fc_ct_fill(struct fc_lport *lport,
|
|
|
int rc = -EINVAL;
|
|
|
|
|
|
switch (fc_id) {
|
|
|
+ case FC_FID_MGMT_SERV:
|
|
|
+ rc = fc_ct_ms_fill(lport, fc_id, fp, op, r_ctl, fh_type);
|
|
|
+ *did = FC_FID_MGMT_SERV;
|
|
|
+ break;
|
|
|
case FC_FID_DIR_SERV:
|
|
|
default:
|
|
|
rc = fc_ct_ns_fill(lport, fc_id, fp, op, r_ctl, fh_type);
|