scsi: cxgb4i: add DCB support for iSCSI connections
Add IEEE and CEE DCBX support for iSCSI connections. Signed-off-by: Rohit Maheshwari <rohitm@chelsio.com> Signed-off-by: Varun Prakash <varun@chelsio.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Родитель
13eb34b669
Коммит
b5a5fe4ef7
|
@ -35,6 +35,11 @@ static unsigned int dbg_level;
|
|||
|
||||
#include "../libcxgbi.h"
|
||||
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
#include <net/dcbevent.h>
|
||||
#include "cxgb4_dcb.h"
|
||||
#endif
|
||||
|
||||
#define DRV_MODULE_NAME "cxgb4i"
|
||||
#define DRV_MODULE_DESC "Chelsio T4-T6 iSCSI Driver"
|
||||
#define DRV_MODULE_VERSION "0.9.5-ko"
|
||||
|
@ -155,6 +160,15 @@ static struct iscsi_transport cxgb4i_iscsi_transport = {
|
|||
.session_recovery_timedout = iscsi_session_recovery_timedout,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
static int
|
||||
cxgb4_dcb_change_notify(struct notifier_block *, unsigned long, void *);
|
||||
|
||||
static struct notifier_block cxgb4_dcb_change = {
|
||||
.notifier_call = cxgb4_dcb_change_notify,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct scsi_transport_template *cxgb4i_stt;
|
||||
|
||||
/*
|
||||
|
@ -574,6 +588,9 @@ static inline int tx_flowc_wr_credits(int *nparamsp, int *flowclenp)
|
|||
int nparams, flowclen16, flowclen;
|
||||
|
||||
nparams = FLOWC_WR_NPARAMS_MIN;
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
nparams++;
|
||||
#endif
|
||||
flowclen = offsetof(struct fw_flowc_wr, mnemval[nparams]);
|
||||
flowclen16 = DIV_ROUND_UP(flowclen, 16);
|
||||
flowclen = flowclen16 * 16;
|
||||
|
@ -595,6 +612,9 @@ static inline int send_tx_flowc_wr(struct cxgbi_sock *csk)
|
|||
struct fw_flowc_wr *flowc;
|
||||
int nparams, flowclen16, flowclen;
|
||||
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
u16 vlan = ((struct l2t_entry *)csk->l2t)->vlan;
|
||||
#endif
|
||||
flowclen16 = tx_flowc_wr_credits(&nparams, &flowclen);
|
||||
skb = alloc_wr(flowclen, 0, GFP_ATOMIC);
|
||||
flowc = (struct fw_flowc_wr *)skb->head;
|
||||
|
@ -622,6 +642,17 @@ static inline int send_tx_flowc_wr(struct cxgbi_sock *csk)
|
|||
flowc->mnemval[8].val = 0;
|
||||
flowc->mnemval[8].mnemonic = FW_FLOWC_MNEM_TXDATAPLEN_MAX;
|
||||
flowc->mnemval[8].val = 16384;
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
flowc->mnemval[9].mnemonic = FW_FLOWC_MNEM_DCBPRIO;
|
||||
if (vlan == CPL_L2T_VLAN_NONE) {
|
||||
pr_warn_ratelimited("csk %u without VLAN Tag on DCB Link\n",
|
||||
csk->tid);
|
||||
flowc->mnemval[9].val = cpu_to_be32(0);
|
||||
} else {
|
||||
flowc->mnemval[9].val = cpu_to_be32((vlan & VLAN_PRIO_MASK) >>
|
||||
VLAN_PRIO_SHIFT);
|
||||
}
|
||||
#endif
|
||||
|
||||
set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id);
|
||||
|
||||
|
@ -1600,6 +1631,46 @@ static void release_offload_resources(struct cxgbi_sock *csk)
|
|||
csk->dst = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
static inline u8 get_iscsi_dcb_state(struct net_device *ndev)
|
||||
{
|
||||
return ndev->dcbnl_ops->getstate(ndev);
|
||||
}
|
||||
|
||||
static int select_priority(int pri_mask)
|
||||
{
|
||||
if (!pri_mask)
|
||||
return 0;
|
||||
return (ffs(pri_mask) - 1);
|
||||
}
|
||||
|
||||
static u8 get_iscsi_dcb_priority(struct net_device *ndev)
|
||||
{
|
||||
int rv;
|
||||
u8 caps;
|
||||
|
||||
struct dcb_app iscsi_dcb_app = {
|
||||
.protocol = 3260
|
||||
};
|
||||
|
||||
rv = (int)ndev->dcbnl_ops->getcap(ndev, DCB_CAP_ATTR_DCBX, &caps);
|
||||
if (rv)
|
||||
return 0;
|
||||
|
||||
if (caps & DCB_CAP_DCBX_VER_IEEE) {
|
||||
iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
|
||||
rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
|
||||
} else if (caps & DCB_CAP_DCBX_VER_CEE) {
|
||||
iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM;
|
||||
rv = dcb_getapp(ndev, &iscsi_dcb_app);
|
||||
}
|
||||
|
||||
log_debug(1 << CXGBI_DBG_ISCSI,
|
||||
"iSCSI priority is set to %u\n", select_priority(rv));
|
||||
return select_priority(rv);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int init_act_open(struct cxgbi_sock *csk)
|
||||
{
|
||||
struct cxgbi_device *cdev = csk->cdev;
|
||||
|
@ -1613,7 +1684,9 @@ static int init_act_open(struct cxgbi_sock *csk)
|
|||
unsigned int size, size6;
|
||||
unsigned int linkspeed;
|
||||
unsigned int rcv_winf, snd_winf;
|
||||
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
u8 priority = 0;
|
||||
#endif
|
||||
log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK,
|
||||
"csk 0x%p,%u,0x%lx,%u.\n",
|
||||
csk, csk->state, csk->flags, csk->tid);
|
||||
|
@ -1647,7 +1720,15 @@ static int init_act_open(struct cxgbi_sock *csk)
|
|||
cxgbi_sock_set_flag(csk, CTPF_HAS_ATID);
|
||||
cxgbi_sock_get(csk);
|
||||
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
if (get_iscsi_dcb_state(ndev))
|
||||
priority = get_iscsi_dcb_priority(ndev);
|
||||
|
||||
csk->dcb_priority = priority;
|
||||
csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, priority);
|
||||
#else
|
||||
csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0);
|
||||
#endif
|
||||
if (!csk->l2t) {
|
||||
pr_err("%s, cannot alloc l2t.\n", ndev->name);
|
||||
goto rel_resource_without_clip;
|
||||
|
@ -2146,6 +2227,70 @@ static int t4_uld_state_change(void *handle, enum cxgb4_state state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
static int
|
||||
cxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
int i, port = 0xFF;
|
||||
struct net_device *ndev;
|
||||
struct cxgbi_device *cdev = NULL;
|
||||
struct dcb_app_type *iscsi_app = data;
|
||||
struct cxgbi_ports_map *pmap;
|
||||
u8 priority;
|
||||
|
||||
if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) {
|
||||
if (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
priority = iscsi_app->app.priority;
|
||||
} else if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_CEE) {
|
||||
if (iscsi_app->app.selector != DCB_APP_IDTYPE_PORTNUM)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (!iscsi_app->app.priority)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
priority = ffs(iscsi_app->app.priority) - 1;
|
||||
} else {
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
if (iscsi_app->app.protocol != 3260)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
log_debug(1 << CXGBI_DBG_ISCSI, "iSCSI priority for ifid %d is %u\n",
|
||||
iscsi_app->ifindex, priority);
|
||||
|
||||
ndev = dev_get_by_index(&init_net, iscsi_app->ifindex);
|
||||
if (!ndev)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
cdev = cxgbi_device_find_by_netdev_rcu(ndev, &port);
|
||||
|
||||
dev_put(ndev);
|
||||
if (!cdev)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
pmap = &cdev->pmap;
|
||||
|
||||
for (i = 0; i < pmap->used; i++) {
|
||||
if (pmap->port_csk[i]) {
|
||||
struct cxgbi_sock *csk = pmap->port_csk[i];
|
||||
|
||||
if (csk->dcb_priority != priority) {
|
||||
iscsi_conn_failure(csk->user_data,
|
||||
ISCSI_ERR_CONN_FAILED);
|
||||
pr_info("Restarting iSCSI connection %p with "
|
||||
"priority %u->%u.\n", csk,
|
||||
csk->dcb_priority, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init cxgb4i_init_module(void)
|
||||
{
|
||||
int rc;
|
||||
|
@ -2157,11 +2302,18 @@ static int __init cxgb4i_init_module(void)
|
|||
return rc;
|
||||
cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info);
|
||||
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
pr_info("%s dcb enabled.\n", DRV_MODULE_NAME);
|
||||
register_dcbevent_notifier(&cxgb4_dcb_change);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cxgb4i_exit_module(void)
|
||||
{
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
unregister_dcbevent_notifier(&cxgb4_dcb_change);
|
||||
#endif
|
||||
cxgb4_unregister_uld(CXGB4_ULD_ISCSI);
|
||||
cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4);
|
||||
cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt);
|
||||
|
|
|
@ -120,6 +120,9 @@ struct cxgbi_sock {
|
|||
int wr_max_cred;
|
||||
int wr_cred;
|
||||
int wr_una_cred;
|
||||
#ifdef CONFIG_CHELSIO_T4_DCB
|
||||
u8 dcb_priority;
|
||||
#endif
|
||||
unsigned char hcrc_len;
|
||||
unsigned char dcrc_len;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче