summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/sun_fc/common/TgtFCHBAPort.cc10
-rw-r--r--usr/src/uts/common/dtrace/sdt_subr.c9
-rw-r--r--usr/src/uts/common/io/comstar/port/fct/discovery.c50
-rw-r--r--usr/src/uts/common/io/comstar/port/fct/fct.c232
-rw-r--r--usr/src/uts/common/io/comstar/port/fct/fct_impl.h15
-rw-r--r--usr/src/uts/common/io/comstar/port/qlt/qlt.c59
-rw-r--r--usr/src/uts/common/sys/fct.h24
-rw-r--r--usr/src/uts/common/sys/fct_defines.h1
-rw-r--r--usr/src/uts/common/sys/fctio.h3
9 files changed, 380 insertions, 23 deletions
diff --git a/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc b/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc
index 511df32308..44c086d765 100644
--- a/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc
+++ b/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -401,6 +401,7 @@ void TgtFCHBAPort::sendRLS(uint64_t destWWN,
fctio_t fctio;
// fc_hba_adapter_port_stats_t fc_port_stat;
uint64_t en_portWWN;
+ uint64_t DestPortID;
// Validate the arguments
if (pRspBuffer == NULL ||
@@ -417,13 +418,14 @@ void TgtFCHBAPort::sendRLS(uint64_t destWWN,
/* The destWWN is either the adapter port or a discovered port. */
memset(&fctio, 0, sizeof (fctio));
- fctio.fctio_cmd = FCTIO_GET_ADAPTER_PORT_STATS;
+ fctio.fctio_cmd = FCTIO_GET_LINK_STATUS;
fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_portWWN;
fctio.fctio_ilen = (uint32_t)(sizeof (en_portWWN));
if (portWWN != destWWN) {
attrs = getDiscoveredAttributes(destWWN, tmp);
- fctio.fctio_abuf = (uint64_t)(uintptr_t)&attrs.PortFcId;
- fctio.fctio_alen = (uint32_t)(sizeof (attrs.PortFcId));
+ DestPortID = (uint64_t)attrs.PortFcId;
+ fctio.fctio_abuf = (uint64_t)(uintptr_t)&DestPortID;
+ fctio.fctio_alen = (uint32_t)(sizeof (DestPortID));
}
fctio.fctio_xfer = FCTIO_XFER_READ;
fctio.fctio_flags = 0;
diff --git a/usr/src/uts/common/dtrace/sdt_subr.c b/usr/src/uts/common/dtrace/sdt_subr.c
index 62e6cf52b4..a89403ea75 100644
--- a/usr/src/uts/common/dtrace/sdt_subr.c
+++ b/usr/src/uts/common/dtrace/sdt_subr.c
@@ -1085,6 +1085,15 @@ sdt_argdesc_t sdt_args[] = {
"fc_port_info_t *" },
{ "fc", "xfer-done", 4, 4, "stmf_data_buf_t *",
"fc_xferinfo_t *" },
+ { "fc", "rscn-receive", 0, 0, "fct_i_local_port_t *",
+ "conninfo_t *" },
+ { "fc", "rscn-receive", 1, 1, "int", "int"},
+ { "fc", "abts-receive", 0, 0, "fct_cmd_t *",
+ "conninfo_t *" },
+ { "fc", "abts-receive", 1, 1, "fct_i_local_port_t *",
+ "fc_port_info_t *" },
+ { "fc", "abts-receive", 2, 2, "fct_i_remote_port_t *",
+ "fc_port_info_t *" },
{ NULL }
diff --git a/usr/src/uts/common/io/comstar/port/fct/discovery.c b/usr/src/uts/common/io/comstar/port/fct/discovery.c
index 13ad485bfc..96a80c2558 100644
--- a/usr/src/uts/common/io/comstar/port/fct/discovery.c
+++ b/usr/src/uts/common/io/comstar/port/fct/discovery.c
@@ -2671,6 +2671,52 @@ fct_gspn_cb(fct_i_cmd_t *icmd)
rw_exit(&iport->iport_lock);
}
+void
+fct_rls_cb(fct_i_cmd_t *icmd)
+{
+ fct_els_t *els = ICMD_TO_ELS(icmd);
+ uint8_t *resp;
+ fct_rls_cb_data_t *rls_cb_data = NULL;
+ fct_port_link_status_t *rls_resp;
+ fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
+
+ rls_cb_data = icmd->icmd_cb_private;
+
+ if (!FCT_IS_ELS_ACC(icmd)) {
+ stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_rls_cb: "
+ "solicited RLS is not accepted - icmd/%p", icmd);
+ if (rls_cb_data) {
+ rls_cb_data->fct_els_res = FCT_FAILURE;
+ sema_v(&iport->iport_rls_sema);
+ }
+ return;
+ }
+
+ if (!rls_cb_data) {
+ sema_v(&iport->iport_rls_sema);
+ return;
+ }
+
+ resp = els->els_resp_payload;
+
+ rls_cb_data = icmd->icmd_cb_private;
+
+ /* Get the response and store it somewhere */
+ rls_resp = (fct_port_link_status_t *)rls_cb_data->fct_link_status;
+ rls_resp->LinkFailureCount = BE_32(*((uint32_t *)(resp + 4)));
+ rls_resp->LossOfSyncCount = BE_32(*((uint32_t *)(resp + 8)));
+ rls_resp->LossOfSignalsCount = BE_32(*((uint32_t *)(resp + 12)));
+ rls_resp->PrimitiveSeqProtocolErrorCount =
+ BE_32(*((uint32_t *)(resp + 16)));
+ rls_resp->InvalidTransmissionWordCount =
+ BE_32(*((uint32_t *)(resp + 20)));
+ rls_resp->InvalidCRCCount = BE_32(*((uint32_t *)(resp + 24)));
+
+ rls_cb_data->fct_els_res = FCT_SUCCESS;
+ sema_v(&iport->iport_rls_sema);
+ icmd->icmd_cb_private = NULL;
+}
+
/*
* For lookup functions, we move locking up one level
*/
@@ -2758,6 +2804,10 @@ fct_rscn_verify(fct_i_local_port_t *iport, uint8_t *rscn_req_payload,
page_format = 0x03 & page_buf[0];
page_portid = fct_netbuf_to_value(page_buf + 1, 3);
+ DTRACE_FC_2(rscn__receive,
+ fct_i_local_port_t, iport,
+ int, page_portid);
+
rw_enter(&iport->iport_lock, RW_READER);
if (!page_format) {
irp = fct_portid_to_portptr(iport, page_portid);
diff --git a/usr/src/uts/common/io/comstar/port/fct/fct.c b/usr/src/uts/common/io/comstar/port/fct/fct.c
index fb0e2fbd1d..7c1166837d 100644
--- a/usr/src/uts/common/io/comstar/port/fct/fct.c
+++ b/usr/src/uts/common/io/comstar/port/fct/fct.c
@@ -53,6 +53,7 @@ static int fct_close(dev_t dev, int flag, int otype, cred_t *credp);
static int fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
cred_t *credp, int *rval);
static int fct_fctiocmd(intptr_t data, int mode);
+void fct_init_kstats(fct_i_local_port_t *iport);
static dev_info_t *fct_dip;
static struct cb_ops fct_cb_ops = {
@@ -91,6 +92,7 @@ static struct dev_ops fct_ops = {
};
#define FCT_NAME "COMSTAR FCT"
+#define FCT_MODULE_NAME "fct"
extern struct mod_ops mod_driverops;
static struct modldrv modldrv = {
@@ -633,29 +635,111 @@ int
fct_get_port_stats(uint8_t *port_wwn,
fc_tgt_hba_adapter_port_stats_t *port_stats, uint32_t *error_detail)
{
+ int ret;
fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
+ fct_port_link_status_t stat;
+ uint32_t buf_size = sizeof (fc_tgt_hba_adapter_port_stats_t);
if (!iport)
return (ENXIO);
port_stats->version = FCT_HBA_ADAPTER_PORT_STATS_VERSION;
+
+ if (iport->iport_port->port_info == NULL) {
+ *error_detail = FCTIO_FAILURE;
+ return (EIO);
+ }
+ ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
+ iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
+ if (ret != STMF_SUCCESS) {
+ *error_detail = FCTIO_FAILURE;
+ return (EIO);
+ }
+
+ port_stats->SecondsSinceLastReset = 0;
+ port_stats->TxFrames = 0;
+ port_stats->TxWords = 0;
+ port_stats->RxFrames = 0;
+ port_stats->RxWords = 0;
+ port_stats->LIPCount = 0;
+ port_stats->NOSCount = 0;
+ port_stats->ErrorFrames = 0;
+ port_stats->DumpedFrames = 0;
+ port_stats->LinkFailureCount = stat.LinkFailureCount;
+ port_stats->LossOfSyncCount = stat.LossOfSyncCount;
+ port_stats->LossOfSignalCount = stat.LossOfSignalsCount;
+ port_stats->PrimitiveSeqProtocolErrCount =
+ stat.PrimitiveSeqProtocolErrorCount;
+ port_stats->InvalidTxWordCount =
+ stat.InvalidTransmissionWordCount;
+ port_stats->InvalidCRCCount = stat.InvalidCRCCount;
+
+ return (ret);
+}
+
+int
+fct_get_link_status(uint8_t *port_wwn, uint64_t *dest_id,
+ fct_port_link_status_t *link_status, uint32_t *error_detail)
+{
+ fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
+ fct_i_remote_port_t *irp = NULL;
+ uint32_t buf_size = sizeof (fct_port_link_status_t);
+ stmf_status_t ret = 0;
+ int i;
+ fct_cmd_t *cmd = NULL;
+
+ if (!iport) {
+ *error_detail = FCTIO_BADWWN;
+ return (ENXIO);
+ }
+
/*
- * port_stats->SecondsSinceLastReset = ;
- * port_stats->TxFrames = ;
- * port_stats->TxWords = ;
- * port_stats->RxFrames = ;
- * port_stats->RxWords = ;
- * port_stats->LIPCount = ;
- * port_stats->NOSCount = ;
- * port_stats->ErrorFrames = ;
- * port_stats->DumpedFrames = ;
- * port_stats->LinkFailureCount = ;
- * port_stats->LossOfSyncCount = ;
- * port_stats->LossOfSignalCount = ;
- * port_stats->PrimitiveSeqProtocol = ;
- * port_stats->InvalidTxWordCount = ;
- * port_stats->InvalidCRCCount = ;
+ * If what we are requesting is zero or same as local port,
+ * then we use port_info()
*/
- return (0);
+ if (dest_id == NULL || *dest_id == iport->iport_link_info.portid) {
+ if (iport->iport_port->port_info == NULL) {
+ *error_detail = FCTIO_FAILURE;
+ return (EIO);
+ }
+ ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
+ iport->iport_port, NULL,
+ (uint8_t *)link_status, &buf_size);
+ if (ret == STMF_SUCCESS) {
+ return (0);
+ } else {
+ *error_detail = FCTIO_FAILURE;
+ return (EIO);
+ }
+ }
+
+ /*
+ * For remote port, we will send RLS
+ */
+ for (i = 0; i < rportid_table_size; i++) {
+ irp = iport->iport_rp_tb[i];
+ while (irp) {
+ if (irp->irp_rp->rp_id == *dest_id &&
+ irp->irp_flags & IRP_PLOGI_DONE) {
+ goto SEND_RLS_ELS;
+ }
+ irp = irp->irp_next;
+ }
+ }
+ return (ENXIO);
+
+SEND_RLS_ELS:
+ cmd = fct_create_solels(iport->iport_port,
+ irp->irp_rp, 0, ELS_OP_RLS,
+ 0, fct_rls_cb);
+ if (!cmd)
+ return (ENOMEM);
+ iport->iport_rls_cb_data.fct_link_status = link_status;
+ CMD_TO_ICMD(cmd)->icmd_cb_private = &iport->iport_rls_cb_data;
+ fct_post_to_solcmd_queue(iport->iport_port, cmd);
+ sema_p(&iport->iport_rls_sema);
+ if (iport->iport_rls_cb_data.fct_els_res != FCT_SUCCESS)
+ ret = EIO;
+ return (ret);
}
static int
@@ -788,6 +872,19 @@ fct_fctiocmd(intptr_t data, int mode)
mutex_exit(&fct_global_mutex);
break;
}
+ case FCTIO_GET_LINK_STATUS: {
+ uint8_t *port_wwn = (uint8_t *)ibuf;
+ fct_port_link_status_t *link_status =
+ (fct_port_link_status_t *)obuf;
+ uint64_t *dest_id = abuf;
+
+ mutex_enter(&fct_global_mutex);
+ ret = fct_get_link_status(port_wwn, dest_id, link_status,
+ &fctio->fctio_errno);
+ mutex_exit(&fct_global_mutex);
+ break;
+ }
+
default:
break;
}
@@ -1018,6 +1115,7 @@ fct_register_local_port(fct_local_port_t *port)
mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
+ sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
/* Remote port mgmt */
iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
@@ -1088,6 +1186,8 @@ fct_register_local_port(fct_local_port_t *port)
fct_iport_list = iport;
mutex_exit(&fct_global_mutex);
+ fct_init_kstats(iport);
+
fct_log_local_port_event(port, ESC_SUNFC_PORT_ATTACH);
return (FCT_SUCCESS);
@@ -1169,6 +1269,7 @@ fct_deregister_local_port(fct_local_port_t *port)
sizeof (fct_i_remote_port_t *));
rw_destroy(&iport->iport_lock);
cv_destroy(&iport->iport_worker_cv);
+ sema_destroy(&iport->iport_rls_sema);
mutex_destroy(&iport->iport_worker_lock);
ddi_taskq_destroy(iport->iport_worker_taskq);
if (iport->iport_rp_tb) {
@@ -1176,6 +1277,10 @@ fct_deregister_local_port(fct_local_port_t *port)
sizeof (fct_i_remote_port_t *));
}
+ if (iport->iport_kstat_portstat) {
+ kstat_delete(iport->iport_kstat_portstat);
+ }
+
fct_log_local_port_event(port, ESC_SUNFC_PORT_DETACH);
return (FCT_SUCCESS);
@@ -2275,6 +2380,16 @@ fct_create_solels(fct_local_port_t *port, fct_remote_port_t *rp, int implicit,
kmem_zalloc(els->els_req_size, KM_SLEEP);
p[7] = FC_SCR_FULL_REGISTRATION;
break;
+ case ELS_OP_RLS:
+ els->els_resp_alloc_size = els->els_resp_size = 28;
+ els->els_resp_payload = (uint8_t *)
+ kmem_zalloc(els->els_resp_size, KM_SLEEP);
+ els->els_req_alloc_size = els->els_req_size = 8;
+ p = els->els_req_payload = (uint8_t *)
+ kmem_zalloc(els->els_req_size, KM_SLEEP);
+ ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
+ fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
+ break;
default:
ASSERT(0);
@@ -2737,6 +2852,12 @@ fct_handle_rcvd_abts(fct_cmd_t *cmd)
fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
return;
}
+
+ DTRACE_FC_3(abts__receive,
+ fct_cmd_t, cmd,
+ fct_local_port_t, port,
+ fct_i_remote_port_t, irp);
+
cmd->cmd_rp = irp->irp_rp;
/*
@@ -3339,3 +3460,82 @@ fct_wwn_to_str(char *to_ptr, const uint8_t *from_ptr)
from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
}
+
+static int
+fct_update_stats(kstat_t *ks, int rw)
+{
+ fct_i_local_port_t *iport;
+ fct_port_stat_t *port_kstat;
+ fct_port_link_status_t stat;
+ uint32_t buf_size = sizeof (stat);
+ int ret;
+
+ if (rw == KSTAT_WRITE)
+ return (EACCES);
+
+ iport = (fct_i_local_port_t *)ks->ks_private;
+ port_kstat = (fct_port_stat_t *)ks->ks_data;
+
+ if (iport->iport_port->port_info == NULL) {
+ return (EIO);
+ }
+ ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
+ iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
+ if (ret != STMF_SUCCESS) {
+ return (EIO);
+ }
+
+ port_kstat->link_failure_cnt.value.ui32 =
+ stat.LinkFailureCount;
+ port_kstat->loss_of_sync_cnt.value.ui32 =
+ stat.LossOfSyncCount;
+ port_kstat->loss_of_signals_cnt.value.ui32 =
+ stat.LossOfSignalsCount;
+ port_kstat->prim_seq_protocol_err_cnt.value.ui32 =
+ stat.PrimitiveSeqProtocolErrorCount;
+ port_kstat->invalid_tx_word_cnt.value.ui32 =
+ stat.InvalidTransmissionWordCount;
+ port_kstat->invalid_crc_cnt.value.ui32 =
+ stat.InvalidCRCCount;
+
+ return (0);
+}
+
+void
+fct_init_kstats(fct_i_local_port_t *iport)
+{
+ kstat_t *ks;
+ fct_port_stat_t *port_kstat;
+ char name[256];
+
+ if (iport->iport_alias)
+ (void) sprintf(name, "iport_%s", iport->iport_alias);
+ else
+ (void) sprintf(name, "iport_%"PRIxPTR"", (uintptr_t)iport);
+ ks = kstat_create(FCT_MODULE_NAME, 0, name, "rawdata",
+ KSTAT_TYPE_NAMED, sizeof (fct_port_stat_t) / sizeof (kstat_named_t),
+ 0);
+
+ if (ks == NULL) {
+ return;
+ }
+ port_kstat = (fct_port_stat_t *)ks->ks_data;
+
+ iport->iport_kstat_portstat = ks;
+ kstat_named_init(&port_kstat->link_failure_cnt,
+ "Link_failure_cnt", KSTAT_DATA_UINT32);
+ kstat_named_init(&port_kstat->loss_of_sync_cnt,
+ "Loss_of_sync_cnt", KSTAT_DATA_UINT32);
+ kstat_named_init(&port_kstat->loss_of_signals_cnt,
+ "Loss_of_signals_cnt", KSTAT_DATA_UINT32);
+ kstat_named_init(&port_kstat->prim_seq_protocol_err_cnt,
+ "Prim_seq_protocol_err_cnt", KSTAT_DATA_UINT32);
+ kstat_named_init(&port_kstat->invalid_tx_word_cnt,
+ "Invalid_tx_word_cnt", KSTAT_DATA_UINT32);
+ kstat_named_init(&port_kstat->invalid_crc_cnt,
+ "Invalid_crc_cnt", KSTAT_DATA_UINT32);
+ ks->ks_update = fct_update_stats;
+ ks->ks_private = (void *)iport;
+ kstat_install(ks);
+
+}
diff --git a/usr/src/uts/common/io/comstar/port/fct/fct_impl.h b/usr/src/uts/common/io/comstar/port/fct/fct_impl.h
index c1eab8bb2e..483b027cb2 100644
--- a/usr/src/uts/common/io/comstar/port/fct/fct_impl.h
+++ b/usr/src/uts/common/io/comstar/port/fct/fct_impl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _FCT_IMPL_H
@@ -154,6 +154,14 @@ typedef struct fct_i_remote_port {
} fct_i_remote_port_t;
/*
+ * structure used for fct_rls_cb() callback private data
+ */
+typedef struct fct_rls_cb_data {
+ struct fct_port_link_status *fct_link_status;
+ fct_status_t fct_els_res;
+} fct_rls_cb_data_t;
+
+/*
* irp flags
*/
#define IRP_PLOGI_DONE 0x0001
@@ -266,7 +274,9 @@ typedef struct fct_i_local_port {
/* rpwe = remote port with pending els(es) */
fct_i_remote_port_t *iport_rpwe_head;
fct_i_remote_port_t *iport_rpwe_tail;
-
+ kstat_t *iport_kstat_portstat;
+ ksema_t iport_rls_sema;
+ fct_rls_cb_data_t iport_rls_cb_data;
} fct_i_local_port_t;
#define IPORT_FLOGI_DONE(iport) PORT_FLOGI_DONE(&(iport)->iport_link_info)
@@ -423,6 +433,7 @@ void fct_gsnn_cb(fct_i_cmd_t *icmd);
void fct_gcs_cb(fct_i_cmd_t *icmd);
void fct_gft_cb(fct_i_cmd_t *icmd);
void fct_gspn_cb(fct_i_cmd_t *icmd);
+void fct_rls_cb(fct_i_cmd_t *icmd);
disc_action_t fct_process_link_init(fct_i_local_port_t *iport);
#ifdef __cplusplus
diff --git a/usr/src/uts/common/io/comstar/port/qlt/qlt.c b/usr/src/uts/common/io/comstar/port/qlt/qlt.c
index 17b8dcb1df..f171cce5b3 100644
--- a/usr/src/uts/common/io/comstar/port/qlt/qlt.c
+++ b/usr/src/uts/common/io/comstar/port/qlt/qlt.c
@@ -888,6 +888,64 @@ qlt_populate_hba_fru_details(struct fct_local_port *port,
FCHBA_MODEL_DESCRIPTION_LEN, "%s", qlt->nvram->model_name);
}
+/* ARGSUSED */
+fct_status_t
+qlt_info(uint32_t cmd, fct_local_port_t *port,
+ void *arg, uint8_t *buf, uint32_t *bufsizep)
+{
+ qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
+ mbox_cmd_t *mcp;
+ fct_status_t ret = FCT_SUCCESS;
+ uint8_t *p;
+ fct_port_link_status_t *link_status;
+
+ switch (cmd) {
+ case FC_TGT_PORT_RLS:
+ if ((*bufsizep) < sizeof (fct_port_link_status_t)) {
+ ret = FCT_FAILURE;
+ break;
+ }
+ /* send mailbox command to get link status */
+ mcp = qlt_alloc_mailbox_command(qlt, 156);
+ if (mcp == NULL) {
+ ret = FCT_ALLOC_FAILURE;
+ break;
+ }
+
+ /* GET LINK STATUS count */
+ mcp->to_fw[0] = 0x6d;
+ mcp->to_fw[8] = 156/4;
+ mcp->to_fw_mask |= BIT_1 | BIT_8;
+ mcp->from_fw_mask |= BIT_1 | BIT_2;
+
+ ret = qlt_mailbox_command(qlt, mcp);
+ if (ret != QLT_SUCCESS) {
+ qlt_free_mailbox_command(qlt, mcp);
+ break;
+ }
+ qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
+
+ p = mcp->dbuf->db_sglist[0].seg_addr;
+ link_status = (fct_port_link_status_t *)buf;
+ link_status->LinkFailureCount = LE_32(*((uint32_t *)p));
+ link_status->LossOfSyncCount = LE_32(*((uint32_t *)(p + 4)));
+ link_status->LossOfSignalsCount = LE_32(*((uint32_t *)(p + 8)));
+ link_status->PrimitiveSeqProtocolErrorCount =
+ LE_32(*((uint32_t *)(p + 12)));
+ link_status->InvalidTransmissionWordCount =
+ LE_32(*((uint32_t *)(p + 16)));
+ link_status->InvalidCRCCount =
+ LE_32(*((uint32_t *)(p + 20)));
+
+ qlt_free_mailbox_command(qlt, mcp);
+ break;
+ default:
+ ret = FCT_FAILURE;
+ break;
+ }
+ return (ret);
+}
+
fct_status_t
qlt_port_start(caddr_t arg)
{
@@ -940,6 +998,7 @@ qlt_port_start(caddr_t arg)
port->port_ctl = qlt_ctl;
port->port_flogi_xchg = qlt_do_flogi;
port->port_populate_hba_details = qlt_populate_hba_fru_details;
+ port->port_info = qlt_info;
if (fct_register_local_port(port) != FCT_SUCCESS) {
goto qlt_pstart_fail_2_5;
diff --git a/usr/src/uts/common/sys/fct.h b/usr/src/uts/common/sys/fct.h
index 43940a90d2..09ec2c8c0f 100644
--- a/usr/src/uts/common/sys/fct.h
+++ b/usr/src/uts/common/sys/fct.h
@@ -158,6 +158,9 @@ typedef struct fct_rcvd_abts {
#define FCHBA_DRIVER_NAME_LEN 256
#define FCHBA_SYMB_NAME_LEN 255
+#define FC_TGT_PORT_INFO_CMD (((uint32_t)'I') << 24)
+#define FC_TGT_PORT_RLS FC_TGT_PORT_INFO_CMD + 0x1
+
typedef struct fct_port_attrs {
char manufacturer[FCHBA_MANUFACTURER_LEN];
char serial_number[FCHBA_SERIAL_NUMBER_LEN];
@@ -174,6 +177,15 @@ typedef struct fct_port_attrs {
uint32_t max_frame_size;
} fct_port_attrs_t;
+typedef struct fct_port_link_status {
+ uint32_t LinkFailureCount;
+ uint32_t LossOfSyncCount;
+ uint32_t LossOfSignalsCount;
+ uint32_t PrimitiveSeqProtocolErrorCount;
+ uint32_t InvalidTransmissionWordCount;
+ uint32_t InvalidCRCCount;
+} fct_port_link_status_t;
+
typedef struct fct_dbuf_store {
void *fds_fct_private;
void *fds_fca_private;
@@ -232,6 +244,9 @@ typedef struct fct_local_port {
struct fct_flogi_xchg *fx);
void (*port_populate_hba_details)(
struct fct_local_port *port, struct fct_port_attrs *port_attrs);
+ fct_status_t (*port_info)(uint32_t cmd,
+ struct fct_local_port *port, void *arg, uint8_t *buf,
+ uint32_t *bufsizep);
} fct_local_port_t;
/*
@@ -277,6 +292,15 @@ typedef struct fct_link_info {
uint8_t port_rpwwn[8];
} fct_link_info_t;
+typedef struct fct_port_stat {
+ kstat_named_t link_failure_cnt;
+ kstat_named_t loss_of_sync_cnt;
+ kstat_named_t loss_of_signals_cnt;
+ kstat_named_t prim_seq_protocol_err_cnt;
+ kstat_named_t invalid_tx_word_cnt;
+ kstat_named_t invalid_crc_cnt;
+} fct_port_stat_t;
+
/*
* port topology
*/
diff --git a/usr/src/uts/common/sys/fct_defines.h b/usr/src/uts/common/sys/fct_defines.h
index cd4f8324c5..79db9f1293 100644
--- a/usr/src/uts/common/sys/fct_defines.h
+++ b/usr/src/uts/common/sys/fct_defines.h
@@ -71,6 +71,7 @@ typedef stmf_status_t fct_status_t;
#define ELS_OP_FLOGI 0x04
#define ELS_OP_LOGO 0x05
#define ELS_OP_ABTX 0x06
+#define ELS_OP_RLS 0x0f
#define ELS_OP_ECHO 0x10
#define ELS_OP_REC 0x13
#define ELS_OP_SRR 0x14
diff --git a/usr/src/uts/common/sys/fctio.h b/usr/src/uts/common/sys/fctio.h
index 875d632b6c..698914941b 100644
--- a/usr/src/uts/common/sys/fctio.h
+++ b/usr/src/uts/common/sys/fctio.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _FCTIO_H
@@ -38,6 +38,7 @@ extern "C" {
#define FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES (FCTIO_SUB_CMD + 0x04)
#define FCTIO_GET_PORT_ATTRIBUTES (FCTIO_SUB_CMD + 0x05)
#define FCTIO_GET_ADAPTER_PORT_STATS (FCTIO_SUB_CMD + 0x06)
+#define FCTIO_GET_LINK_STATUS (FCTIO_SUB_CMD + 0x07)
/*
* fcio_xfer definitions