void cxgb3i_conn_tx_open(struct s3_conn *c3cn) { struct iscsi_conn *conn = c3cn->user_data; cxgb3i_tx_debug("cn 0x%p.\n", c3cn); if (conn) { cxgb3i_tx_debug("cn 0x%p, cid %d.\n", c3cn, conn->id); scsi_queue_work(conn->session->host, &conn->xmitwork); } }
int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) { struct iscsi_conn *conn = task->conn; struct iscsi_tcp_task *tcp_task = task->dd_data; struct cxgb3i_task_data *tdata = task->dd_data + sizeof(*tcp_task); struct scsi_cmnd *sc = task->sc; int headroom = SKB_TX_PDU_HEADER_LEN; tcp_task->dd_data = tdata; task->hdr = NULL; /* write command, need to send data pdus */ if (skb_extra_headroom && (opcode == ISCSI_OP_SCSI_DATA_OUT || (opcode == ISCSI_OP_SCSI_CMD && (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_TO_DEVICE)))) headroom += min(skb_extra_headroom, conn->max_xmit_dlength); tdata->skb = alloc_skb(TX_HEADER_LEN + headroom, GFP_ATOMIC); if (!tdata->skb) return -ENOMEM; skb_reserve(tdata->skb, TX_HEADER_LEN); cxgb3i_tx_debug("task 0x%p, opcode 0x%x, skb 0x%p.\n", task, opcode, tdata->skb); task->hdr = (struct iscsi_hdr *)tdata->skb->data; task->hdr_max = SKB_TX_PDU_HEADER_LEN; /* data_out uses scsi_cmd's itt */ if (opcode != ISCSI_OP_SCSI_DATA_OUT) cxgb3i_reserve_itt(task, &task->hdr->itt); return 0; }
int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) { struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; struct cxgb3i_conn *cconn = tcp_conn->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct cxgb3i_task_data *tdata = tcp_task->dd_data; struct sk_buff *skb = tdata->skb; unsigned int datalen; int err; if (!skb) return 0; datalen = skb->data_len; tdata->skb = NULL; err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb); if (err > 0) { int pdulen = err; cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n", task, skb, skb->len, skb->data_len, err); if (task->conn->hdrdgst_en) pdulen += ISCSI_DIGEST_SIZE; if (datalen && task->conn->datadgst_en) pdulen += ISCSI_DIGEST_SIZE; task->conn->txdata_octets += pdulen; return 0; } if (err == -EAGAIN || err == -ENOBUFS) { /* reset skb to send when we are called again */ tdata->skb = skb; return err; } kfree_skb(skb); cxgb3i_tx_debug("itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n", task->itt, skb, skb->len, skb->data_len, err); iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err); iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED); return err; }
int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset, unsigned int count) { struct iscsi_conn *conn = task->conn; struct iscsi_tcp_task *tcp_task = task->dd_data; struct cxgb3i_task_data *tdata = tcp_task->dd_data; struct sk_buff *skb = tdata->skb; unsigned int datalen = count; int i, padlen = iscsi_padding(count); struct page *pg; cxgb3i_tx_debug("task 0x%p,0x%p, offset %u, count %u, skb 0x%p.\n", task, task->sc, offset, count, skb); skb_put(skb, task->hdr_len); tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0); if (!count) return 0; if (task->sc) { struct scsi_data_buffer *sdb = scsi_out(task->sc); struct scatterlist *sg = NULL; int err; tdata->offset = offset; tdata->count = count; err = sgl_seek_offset(sdb->table.sgl, sdb->table.nents, tdata->offset, &tdata->sgoffset, &sg); if (err < 0) { cxgb3i_log_warn("tpdu, sgl %u, bad offset %u/%u.\n", sdb->table.nents, tdata->offset, sdb->length); return err; } err = sgl_read_to_frags(sg, tdata->sgoffset, tdata->count, tdata->frags, MAX_PDU_FRAGS); if (err < 0) { cxgb3i_log_warn("tpdu, sgl %u, bad offset %u + %u.\n", sdb->table.nents, tdata->offset, tdata->count); return err; } tdata->nr_frags = err; if (tdata->nr_frags > MAX_SKB_FRAGS || (padlen && tdata->nr_frags == MAX_SKB_FRAGS)) { char *dst = skb->data + task->hdr_len; skb_frag_t *frag = tdata->frags; /* data fits in the skb's headroom */ for (i = 0; i < tdata->nr_frags; i++, frag++) { char *src = kmap_atomic(frag->page, KM_SOFTIRQ0); memcpy(dst, src+frag->page_offset, frag->size); dst += frag->size; kunmap_atomic(src, KM_SOFTIRQ0); } if (padlen) { memset(dst, 0, padlen); padlen = 0; } skb_put(skb, count + padlen); } else { /* data fit into frag_list */ for (i = 0; i < tdata->nr_frags; i++) get_page(tdata->frags[i].page); memcpy(skb_shinfo(skb)->frags, tdata->frags, sizeof(skb_frag_t) * tdata->nr_frags); skb_shinfo(skb)->nr_frags = tdata->nr_frags; skb->len += count; skb->data_len += count; skb->truesize += count; } } else { pg = virt_to_page(task->data); get_page(pg); skb_fill_page_desc(skb, 0, pg, offset_in_page(task->data), count); skb->len += count; skb->data_len += count; skb->truesize += count; } if (padlen) { i = skb_shinfo(skb)->nr_frags; get_page(pad_page); skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, pad_page, 0, padlen); skb->data_len += padlen; skb->truesize += padlen; skb->len += padlen; } return 0; }