diff options
Diffstat (limited to 'drivers/scsi/cxgbi')
| -rw-r--r-- | drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 3 | ||||
| -rw-r--r-- | drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 132 | ||||
| -rw-r--r-- | drivers/scsi/cxgbi/libcxgbi.c | 46 | ||||
| -rw-r--r-- | drivers/scsi/cxgbi/libcxgbi.h | 10 |
4 files changed, 128 insertions, 63 deletions
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index 000294a9df8..49692a1ac44 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -966,7 +966,8 @@ static int init_act_open(struct cxgbi_sock *csk) csk->saddr.sin_addr.s_addr = chba->ipv4addr; csk->rss_qid = 0; - csk->l2t = t3_l2t_get(t3dev, dst_get_neighbour(dst), ndev); + csk->l2t = t3_l2t_get(t3dev, dst, ndev, + &csk->daddr.sin_addr.s_addr); if (!csk->l2t) { pr_err("NO l2t available.\n"); return -EINVAL; diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index ac7a9b1e3e2..e8ee5e5fe0e 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -20,6 +20,7 @@ #include <net/dst.h> #include <linux/netdevice.h> +#include "t4_regs.h" #include "t4_msg.h" #include "cxgb4.h" #include "cxgb4_uld.h" @@ -32,13 +33,12 @@ static unsigned int dbg_level; #include "../libcxgbi.h" #define DRV_MODULE_NAME "cxgb4i" -#define DRV_MODULE_DESC "Chelsio T4 iSCSI Driver" -#define DRV_MODULE_VERSION "0.9.1" -#define DRV_MODULE_RELDATE "Aug. 2010" +#define DRV_MODULE_DESC "Chelsio T4/T5 iSCSI Driver" +#define DRV_MODULE_VERSION "0.9.4" static char version[] = DRV_MODULE_DESC " " DRV_MODULE_NAME - " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + " v" DRV_MODULE_VERSION "\n"; MODULE_AUTHOR("Chelsio Communications, Inc."); MODULE_DESCRIPTION(DRV_MODULE_DESC); @@ -178,7 +178,7 @@ static inline int is_ofld_imm(const struct sk_buff *skb) static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, struct l2t_entry *e) { - struct cpl_act_open_req *req; + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); unsigned long long opt0; unsigned int opt2; @@ -195,29 +195,59 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, RCV_BUFSIZ(cxgb4i_rcv_win >> 10); opt2 = RX_CHANNEL(0) | RSS_QUEUE_VALID | - (1 << 20) | (1 << 22) | + (1 << 20) | RSS_QUEUE(csk->rss_qid); - set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); - req = (struct cpl_act_open_req *)skb->head; + if (is_t4(lldi->adapter_type)) { + struct cpl_act_open_req *req = + (struct cpl_act_open_req *)skb->head; - INIT_TP_WR(req, 0); - OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, + INIT_TP_WR(req, 0); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, qid_atid)); - req->local_port = csk->saddr.sin_port; - req->peer_port = csk->daddr.sin_port; - req->local_ip = csk->saddr.sin_addr.s_addr; - req->peer_ip = csk->daddr.sin_addr.s_addr; - req->opt0 = cpu_to_be64(opt0); - req->params = 0; - req->opt2 = cpu_to_be32(opt2); + req->local_port = csk->saddr.sin_port; + req->peer_port = csk->daddr.sin_port; + req->local_ip = csk->saddr.sin_addr.s_addr; + req->peer_ip = csk->daddr.sin_addr.s_addr; + req->opt0 = cpu_to_be64(opt0); + req->params = cpu_to_be32(cxgb4_select_ntuple( + csk->cdev->ports[csk->port_id], + csk->l2t)); + opt2 |= 1 << 22; + req->opt2 = cpu_to_be32(opt2); - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", - csk, &req->local_ip, ntohs(req->local_port), - &req->peer_ip, ntohs(req->peer_port), - csk->atid, csk->rss_qid); + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk t4 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", + csk, &req->local_ip, ntohs(req->local_port), + &req->peer_ip, ntohs(req->peer_port), + csk->atid, csk->rss_qid); + } else { + struct cpl_t5_act_open_req *req = + (struct cpl_t5_act_open_req *)skb->head; + + INIT_TP_WR(req, 0); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, + qid_atid)); + req->local_port = csk->saddr.sin_port; + req->peer_port = csk->daddr.sin_port; + req->local_ip = csk->saddr.sin_addr.s_addr; + req->peer_ip = csk->daddr.sin_addr.s_addr; + req->opt0 = cpu_to_be64(opt0); + req->params = cpu_to_be64(V_FILTER_TUPLE( + cxgb4_select_ntuple( + csk->cdev->ports[csk->port_id], + csk->l2t))); + opt2 |= 1 << 31; + req->opt2 = cpu_to_be32(opt2); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk t5 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", + csk, &req->local_ip, ntohs(req->local_port), + &req->peer_ip, ntohs(req->peer_port), + csk->atid, csk->rss_qid); + } + set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); } @@ -358,7 +388,7 @@ static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) return DIV_ROUND_UP(skb->len, 8); flits = skb_transport_offset(skb) / 8; cnt = skb_shinfo(skb)->nr_frags; - if (skb->tail != skb->transport_header) + if (skb_tail_pointer(skb) != skb_transport_header(skb)) cnt++; return flits + sgl_len(cnt); } @@ -438,8 +468,8 @@ static inline void make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, if (submode) wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE(ULP2_MODE_ISCSI) | FW_OFLD_TX_DATA_WR_ULPSUBMODE(submode); - req->tunnel_to_proxy = htonl(wr_ulp_mode) | - FW_OFLD_TX_DATA_WR_SHOVE(skb_peek(&csk->write_queue) ? 0 : 1); + req->tunnel_to_proxy = htonl(wr_ulp_mode | + FW_OFLD_TX_DATA_WR_SHOVE(skb_peek(&csk->write_queue) ? 0 : 1)); req->plen = htonl(len); if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); @@ -632,6 +662,7 @@ static void csk_act_open_retry_timer(unsigned long data) { struct sk_buff *skb; struct cxgbi_sock *csk = (struct cxgbi_sock *)data; + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", @@ -639,7 +670,10 @@ static void csk_act_open_retry_timer(unsigned long data) cxgbi_sock_get(csk); spin_lock_bh(&csk->lock); - skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_ATOMIC); + skb = alloc_wr(is_t4(lldi->adapter_type) ? + sizeof(struct cpl_act_open_req) : + sizeof(struct cpl_t5_act_open_req), + 0, GFP_ATOMIC); if (!skb) cxgbi_sock_fail_act_open(csk, -ENOMEM); else { @@ -871,7 +905,7 @@ static void do_rx_iscsi_hdr(struct cxgbi_device *cdev, struct sk_buff *skb) if (!csk->skb_ulp_lhdr) { unsigned char *bhs; - unsigned int hlen, dlen; + unsigned int hlen, dlen, plen; log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p header.\n", @@ -890,11 +924,15 @@ static void do_rx_iscsi_hdr(struct cxgbi_device *cdev, struct sk_buff *skb) hlen = ntohs(cpl->len); dlen = ntohl(*(unsigned int *)(bhs + 4)) & 0xFFFFFF; - if ((hlen + dlen) != ISCSI_PDU_LEN(pdu_len_ddp) - 40) { + plen = ISCSI_PDU_LEN(pdu_len_ddp); + if (is_t4(lldi->adapter_type)) + plen -= 40; + + if ((hlen + dlen) != plen) { pr_info("tid 0x%x, CPL_ISCSI_HDR, pdu len " "mismatch %u != %u + %u, seq 0x%x.\n", - csk->tid, ISCSI_PDU_LEN(pdu_len_ddp) - 40, - hlen, dlen, cxgbi_skcb_tcp_seq(skb)); + csk->tid, plen, hlen, dlen, + cxgbi_skcb_tcp_seq(skb)); goto abort_conn; } @@ -1127,6 +1165,7 @@ static int init_act_open(struct cxgbi_sock *csk) struct net_device *ndev = cdev->ports[csk->port_id]; struct port_info *pi = netdev_priv(ndev); struct sk_buff *skb = NULL; + struct neighbour *n; unsigned int step; log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, @@ -1141,14 +1180,22 @@ static int init_act_open(struct cxgbi_sock *csk) cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); cxgbi_sock_get(csk); - csk->l2t = cxgb4_l2t_get(lldi->l2t, dst_get_neighbour(csk->dst), ndev, 0); + n = dst_neigh_lookup(csk->dst, &csk->daddr.sin_addr.s_addr); + if (!n) { + pr_err("%s, can't get neighbour of csk->dst.\n", ndev->name); + goto rel_resource; + } + csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0); if (!csk->l2t) { pr_err("%s, cannot alloc l2t.\n", ndev->name); goto rel_resource; } cxgbi_sock_get(csk); - skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_KERNEL); + skb = alloc_wr(is_t4(lldi->adapter_type) ? + sizeof(struct cpl_act_open_req) : + sizeof(struct cpl_t5_act_open_req), + 0, GFP_ATOMIC); if (!skb) goto rel_resource; skb->sk = (struct sock *)csk; @@ -1176,14 +1223,19 @@ static int init_act_open(struct cxgbi_sock *csk) cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); send_act_open_req(csk, skb, csk->l2t); + neigh_release(n); return 0; rel_resource: + if (n) + neigh_release(n); if (skb) __kfree_skb(skb); return -EINVAL; } +#define CPL_ISCSI_DATA 0xB2 +#define CPL_RX_ISCSI_DDP 0x49 cxgb4i_cplhandler_func cxgb4i_cplhandlers[NUM_CPL_CMDS] = { [CPL_ACT_ESTABLISH] = do_act_establish, [CPL_ACT_OPEN_RPL] = do_act_open_rpl, @@ -1193,8 +1245,10 @@ cxgb4i_cplhandler_func cxgb4i_cplhandlers[NUM_CPL_CMDS] = { [CPL_CLOSE_CON_RPL] = do_close_con_rpl, [CPL_FW4_ACK] = do_fw4_ack, [CPL_ISCSI_HDR] = do_rx_iscsi_hdr, + [CPL_ISCSI_DATA] = do_rx_iscsi_hdr, [CPL_SET_TCB_RPL] = do_set_tcb_rpl, [CPL_RX_DATA_DDP] = do_rx_data_ddp, + [CPL_RX_ISCSI_DDP] = do_rx_data_ddp, }; int cxgb4i_ofld_init(struct cxgbi_device *cdev) @@ -1225,14 +1279,20 @@ int cxgb4i_ofld_init(struct cxgbi_device *cdev) * functions to program the pagepod in h/w */ #define ULPMEM_IDATA_MAX_NPPODS 4 /* 256/PPOD_SIZE */ -static inline void ulp_mem_io_set_hdr(struct ulp_mem_io *req, +static inline void ulp_mem_io_set_hdr(struct cxgb4_lld_info *lldi, + struct ulp_mem_io *req, unsigned int wr_len, unsigned int dlen, unsigned int pm_addr) { struct ulptx_idata *idata = (struct ulptx_idata *)(req + 1); INIT_ULPTX_WR(req, wr_len, 0, 0); - req->cmd = htonl(ULPTX_CMD(ULP_TX_MEM_WRITE) | (1 << 23)); + if (is_t4(lldi->adapter_type)) + req->cmd = htonl(ULPTX_CMD(ULP_TX_MEM_WRITE) | + (ULP_MEMIO_ORDER(1))); + else + req->cmd = htonl(ULPTX_CMD(ULP_TX_MEM_WRITE) | + (V_T5_ULP_MEMIO_IMM(1))); req->dlen = htonl(ULP_MEMIO_DATA_LEN(dlen >> 5)); req->lock_addr = htonl(ULP_MEMIO_ADDR(pm_addr >> 5)); req->len16 = htonl(DIV_ROUND_UP(wr_len - sizeof(req->wr), 16)); @@ -1248,6 +1308,7 @@ static int ddp_ppod_write_idata(struct cxgbi_device *cdev, unsigned int port_id, unsigned int gl_pidx) { struct cxgbi_ddp_info *ddp = cdev->ddp; + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); struct sk_buff *skb; struct ulp_mem_io *req; struct ulptx_idata *idata; @@ -1267,7 +1328,7 @@ static int ddp_ppod_write_idata(struct cxgbi_device *cdev, unsigned int port_id, req = (struct ulp_mem_io *)skb->head; set_queue(skb, CPL_PRIORITY_CONTROL, NULL); - ulp_mem_io_set_hdr(req, wr_len, dlen, pm_addr); + ulp_mem_io_set_hdr(lldi, req, wr_len, dlen, pm_addr); idata = (struct ulptx_idata *)(req + 1); ppod = (struct cxgbi_pagepod *)(idata + 1); @@ -1555,6 +1616,7 @@ static int t4_uld_state_change(void *handle, enum cxgb4_state state) break; case CXGB4_STATE_DETACH: pr_info("cdev 0x%p, DETACH.\n", cdev); + cxgbi_device_unregister(cdev); break; default: pr_info("cdev 0x%p, unknown state %d.\n", cdev, state); diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index c363a4b260f..b44c1cff311 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -25,6 +25,7 @@ #include <net/dst.h> #include <net/route.h> #include <linux/inetdevice.h> /* ip_dev_find */ +#include <linux/module.h> #include <net/tcp.h> static unsigned int dbg_level; @@ -471,6 +472,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) struct net_device *ndev; struct cxgbi_device *cdev; struct rtable *rt = NULL; + struct neighbour *n; struct flowi4 fl4; struct cxgbi_sock *csk = NULL; unsigned int mtu = 0; @@ -492,21 +494,26 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) goto err_out; } dst = &rt->dst; - ndev = dst_get_neighbour(dst)->dev; + n = dst_neigh_lookup(dst, &daddr->sin_addr.s_addr); + if (!n) { + err = -ENODEV; + goto rel_rt; + } + ndev = n->dev; if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { pr_info("multi-cast route %pI4, port %u, dev %s.\n", &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), ndev->name); err = -ENETUNREACH; - goto rel_rt; + goto rel_neigh; } if (ndev->flags & IFF_LOOPBACK) { ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr); mtu = ndev->mtu; pr_info("rt dev %s, loopback -> %s, mtu %u.\n", - dst_get_neighbour(dst)->dev->name, ndev->name, mtu); + n->dev->name, ndev->name, mtu); } cdev = cxgbi_device_find_by_netdev(ndev, &port); @@ -514,7 +521,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) pr_info("dst %pI4, %s, NOT cxgbi device.\n", &daddr->sin_addr.s_addr, ndev->name); err = -ENETUNREACH; - goto rel_rt; + goto rel_neigh; } log_debug(1 << CXGBI_DBG_SOCK, "route to %pI4 :%u, ndev p#%d,%s, cdev 0x%p.\n", @@ -524,7 +531,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) csk = cxgbi_sock_create(cdev); if (!csk) { err = -ENOMEM; - goto rel_rt; + goto rel_neigh; } csk->cdev = cdev; csk->port_id = port; @@ -534,9 +541,13 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) csk->daddr.sin_port = daddr->sin_port; csk->daddr.sin_family = daddr->sin_family; csk->saddr.sin_addr.s_addr = fl4.saddr; + neigh_release(n); return csk; +rel_neigh: + neigh_release(n); + rel_rt: ip_rt_put(rt); if (csk) @@ -1861,8 +1872,9 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) tdata->skb = alloc_skb(cdev->skb_tx_rsvd + headroom, GFP_ATOMIC); if (!tdata->skb) { - pr_warn("alloc skb %u+%u, opcode 0x%x failed.\n", - cdev->skb_tx_rsvd, headroom, opcode); + struct cxgbi_sock *csk = cconn->cep->csk; + struct net_device *ndev = cdev->ports[csk->port_id]; + ndev->stats.tx_dropped++; return -ENOMEM; } @@ -1948,12 +1960,11 @@ int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset, /* data fits in the skb's headroom */ for (i = 0; i < tdata->nr_frags; i++, frag++) { - char *src = kmap_atomic(frag->page, - KM_SOFTIRQ0); + char *src = kmap_atomic(frag->page); memcpy(dst, src+frag->offset, frag->size); dst += frag->size; - kunmap_atomic(src, KM_SOFTIRQ0); + kunmap_atomic(src); } if (padlen) { memset(dst, 0, padlen); @@ -2140,11 +2151,10 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf, int buflen) { struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct cxgbi_conn *cconn = tcp_conn->dd_data; struct cxgbi_sock *csk = cconn->cep->csk; - int value, err = 0; + int err; log_debug(1 << CXGBI_DBG_ISCSI, "cls_conn 0x%p, param %d, buf(%d) %s.\n", @@ -2166,15 +2176,7 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, conn->datadgst_en, 0); break; case ISCSI_PARAM_MAX_R2T: - sscanf(buf, "%d", &value); - if (value <= 0 || !is_power_of_2(value)) - return -EINVAL; - if (session->max_r2t == value) - break; - iscsi_tcp_r2tpool_free(session); - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err && iscsi_tcp_r2tpool_alloc(session)) - return -ENOMEM; + return iscsi_tcp_set_max_r2t(conn, buf); case ISCSI_PARAM_MAX_RECV_DLENGTH: err = iscsi_set_param(cls_conn, param, buf, buflen); if (!err) @@ -2568,7 +2570,7 @@ void cxgbi_iscsi_cleanup(struct iscsi_transport *itp, } EXPORT_SYMBOL_GPL(cxgbi_iscsi_cleanup); -mode_t cxgbi_attr_is_visible(int param_type, int param) +umode_t cxgbi_attr_is_visible(int param_type, int param) { switch (param_type) { case ISCSI_HOST_PARAM: diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 20c88279c7a..8135f04671a 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -658,11 +658,11 @@ static inline u32 cxgbi_tag_nonrsvd_bits(struct cxgbi_tag_format *tformat, static inline void *cxgbi_alloc_big_mem(unsigned int size, gfp_t gfp) { - void *p = kmalloc(size, gfp); + void *p = kzalloc(size, gfp | __GFP_NOWARN); + if (!p) - p = vmalloc(size); - if (p) - memset(p, 0, size); + p = vzalloc(size); + return p; } @@ -709,7 +709,7 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *); void cxgbi_cleanup_task(struct iscsi_task *task); -mode_t cxgbi_attr_is_visible(int param_type, int param); +umode_t cxgbi_attr_is_visible(int param_type, int param); void cxgbi_get_conn_stats(struct iscsi_cls_conn *, struct iscsi_stats *); int cxgbi_set_conn_param(struct iscsi_cls_conn *, enum iscsi_param, char *, int); |
