diff options
| -rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_ddp.c | 19 | ||||
| -rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_ddp.h | 3 | ||||
| -rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_iscsi.c | 17 | ||||
| -rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_offload.h | 1 | ||||
| -rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_pdu.c | 275 | ||||
| -rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_pdu.h | 2 |
6 files changed, 205 insertions, 112 deletions
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c index 08f3a09d9233..a83d36e4926f 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c | |||
| @@ -639,10 +639,11 @@ static int ddp_init(struct t3cdev *tdev) | |||
| 639 | write_unlock(&cxgb3i_ddp_rwlock); | 639 | write_unlock(&cxgb3i_ddp_rwlock); |
| 640 | 640 | ||
| 641 | ddp_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x " | 641 | ddp_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x " |
| 642 | "pkt %u,%u.\n", | 642 | "pkt %u/%u, %u/%u.\n", |
| 643 | ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits, | 643 | ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits, |
| 644 | ddp->idx_mask, ddp->rsvd_tag_mask, | 644 | ddp->idx_mask, ddp->rsvd_tag_mask, |
| 645 | ddp->max_txsz, ddp->max_rxsz); | 645 | ddp->max_txsz, uinfo.max_txsz, |
| 646 | ddp->max_rxsz, uinfo.max_rxsz); | ||
| 646 | return 0; | 647 | return 0; |
| 647 | 648 | ||
| 648 | free_ddp_map: | 649 | free_ddp_map: |
| @@ -654,8 +655,8 @@ free_ddp_map: | |||
| 654 | * cxgb3i_adapter_ddp_init - initialize the adapter's ddp resource | 655 | * cxgb3i_adapter_ddp_init - initialize the adapter's ddp resource |
| 655 | * @tdev: t3cdev adapter | 656 | * @tdev: t3cdev adapter |
| 656 | * @tformat: tag format | 657 | * @tformat: tag format |
| 657 | * @txsz: max tx pkt size, filled in by this func. | 658 | * @txsz: max tx pdu payload size, filled in by this func. |
| 658 | * @rxsz: max rx pkt size, filled in by this func. | 659 | * @rxsz: max rx pdu payload size, filled in by this func. |
| 659 | * initialize the ddp pagepod manager for a given adapter if needed and | 660 | * initialize the ddp pagepod manager for a given adapter if needed and |
| 660 | * setup the tag format for a given iscsi entity | 661 | * setup the tag format for a given iscsi entity |
| 661 | */ | 662 | */ |
| @@ -685,10 +686,12 @@ int cxgb3i_adapter_ddp_init(struct t3cdev *tdev, | |||
| 685 | tformat->sw_bits, tformat->rsvd_bits, | 686 | tformat->sw_bits, tformat->rsvd_bits, |
| 686 | tformat->rsvd_shift, tformat->rsvd_mask); | 687 | tformat->rsvd_shift, tformat->rsvd_mask); |
| 687 | 688 | ||
| 688 | *txsz = ddp->max_txsz; | 689 | *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, |
| 689 | *rxsz = ddp->max_rxsz; | 690 | ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN); |
| 690 | ddp_log_info("ddp max pkt size: %u, %u.\n", | 691 | *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, |
| 691 | ddp->max_txsz, ddp->max_rxsz); | 692 | ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN); |
| 693 | ddp_log_info("max payload size: %u/%u, %u/%u.\n", | ||
| 694 | *txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz); | ||
| 692 | return 0; | 695 | return 0; |
| 693 | } | 696 | } |
| 694 | EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_init); | 697 | EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_init); |
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.h b/drivers/scsi/cxgb3i/cxgb3i_ddp.h index 5c7c4d95c493..99d7014d614d 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.h +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.h | |||
| @@ -85,8 +85,9 @@ struct cxgb3i_ddp_info { | |||
| 85 | struct sk_buff **gl_skb; | 85 | struct sk_buff **gl_skb; |
| 86 | }; | 86 | }; |
| 87 | 87 | ||
| 88 | #define ISCSI_PDU_NONPAYLOAD_LEN 312 /* bhs(48) + ahs(256) + digest(8) */ | ||
| 88 | #define ULP2_MAX_PKT_SIZE 16224 | 89 | #define ULP2_MAX_PKT_SIZE 16224 |
| 89 | #define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_MAX) | 90 | #define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN) |
| 90 | #define PPOD_PAGES_MAX 4 | 91 | #define PPOD_PAGES_MAX 4 |
| 91 | #define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */ | 92 | #define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */ |
| 92 | 93 | ||
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c index f0434b74554c..fa2a44f37b36 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c | |||
| @@ -403,17 +403,15 @@ static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn) | |||
| 403 | { | 403 | { |
| 404 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 404 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
| 405 | struct cxgb3i_conn *cconn = tcp_conn->dd_data; | 405 | struct cxgb3i_conn *cconn = tcp_conn->dd_data; |
| 406 | unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, | 406 | unsigned int max = max(512 * MAX_SKB_FRAGS, SKB_TX_HEADROOM); |
| 407 | cconn->hba->snic->tx_max_size - | ||
| 408 | ISCSI_PDU_NONPAYLOAD_MAX); | ||
| 409 | 407 | ||
| 408 | max = min(cconn->hba->snic->tx_max_size, max); | ||
| 410 | if (conn->max_xmit_dlength) | 409 | if (conn->max_xmit_dlength) |
| 411 | conn->max_xmit_dlength = min_t(unsigned int, | 410 | conn->max_xmit_dlength = min(conn->max_xmit_dlength, max); |
| 412 | conn->max_xmit_dlength, max); | ||
| 413 | else | 411 | else |
| 414 | conn->max_xmit_dlength = max; | 412 | conn->max_xmit_dlength = max; |
| 415 | align_pdu_size(conn->max_xmit_dlength); | 413 | align_pdu_size(conn->max_xmit_dlength); |
| 416 | cxgb3i_log_info("conn 0x%p, max xmit %u.\n", | 414 | cxgb3i_api_debug("conn 0x%p, max xmit %u.\n", |
| 417 | conn, conn->max_xmit_dlength); | 415 | conn, conn->max_xmit_dlength); |
| 418 | return 0; | 416 | return 0; |
| 419 | } | 417 | } |
| @@ -428,9 +426,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) | |||
| 428 | { | 426 | { |
| 429 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 427 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
| 430 | struct cxgb3i_conn *cconn = tcp_conn->dd_data; | 428 | struct cxgb3i_conn *cconn = tcp_conn->dd_data; |
| 431 | unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, | 429 | unsigned int max = cconn->hba->snic->rx_max_size; |
| 432 | cconn->hba->snic->rx_max_size - | ||
| 433 | ISCSI_PDU_NONPAYLOAD_MAX); | ||
| 434 | 430 | ||
| 435 | align_pdu_size(max); | 431 | align_pdu_size(max); |
| 436 | if (conn->max_recv_dlength) { | 432 | if (conn->max_recv_dlength) { |
| @@ -440,8 +436,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) | |||
| 440 | conn->max_recv_dlength, max); | 436 | conn->max_recv_dlength, max); |
| 441 | return -EINVAL; | 437 | return -EINVAL; |
| 442 | } | 438 | } |
| 443 | conn->max_recv_dlength = min_t(unsigned int, | 439 | conn->max_recv_dlength = min(conn->max_recv_dlength, max); |
| 444 | conn->max_recv_dlength, max); | ||
| 445 | align_pdu_size(conn->max_recv_dlength); | 440 | align_pdu_size(conn->max_recv_dlength); |
| 446 | } else | 441 | } else |
| 447 | conn->max_recv_dlength = max; | 442 | conn->max_recv_dlength = max; |
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h index df1eae0ee4be..6344b9eb2589 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.h +++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h | |||
| @@ -225,6 +225,7 @@ struct sge_opaque_hdr { | |||
| 225 | /* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ | 225 | /* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ |
| 226 | #define TX_HEADER_LEN \ | 226 | #define TX_HEADER_LEN \ |
| 227 | (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr)) | 227 | (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr)) |
| 228 | #define SKB_TX_HEADROOM SKB_MAX_HEAD(TX_HEADER_LEN) | ||
| 228 | 229 | ||
| 229 | /* | 230 | /* |
| 230 | * get and set private ip for iscsi traffic | 231 | * get and set private ip for iscsi traffic |
diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.c b/drivers/scsi/cxgb3i/cxgb3i_pdu.c index ce7ce8c6094c..17115c230d65 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_pdu.c +++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.c | |||
| @@ -32,6 +32,10 @@ | |||
| 32 | #define cxgb3i_tx_debug(fmt...) | 32 | #define cxgb3i_tx_debug(fmt...) |
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | /* always allocate rooms for AHS */ | ||
| 36 | #define SKB_TX_PDU_HEADER_LEN \ | ||
| 37 | (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE) | ||
| 38 | static unsigned int skb_extra_headroom; | ||
| 35 | static struct page *pad_page; | 39 | static struct page *pad_page; |
| 36 | 40 | ||
| 37 | /* | 41 | /* |
| @@ -146,12 +150,13 @@ static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc) | |||
| 146 | 150 | ||
| 147 | void cxgb3i_conn_cleanup_task(struct iscsi_task *task) | 151 | void cxgb3i_conn_cleanup_task(struct iscsi_task *task) |
| 148 | { | 152 | { |
| 149 | struct iscsi_tcp_task *tcp_task = task->dd_data; | 153 | struct cxgb3i_task_data *tdata = task->dd_data + |
| 154 | sizeof(struct iscsi_tcp_task); | ||
| 150 | 155 | ||
| 151 | /* never reached the xmit task callout */ | 156 | /* never reached the xmit task callout */ |
| 152 | if (tcp_task->dd_data) | 157 | if (tdata->skb) |
| 153 | kfree_skb(tcp_task->dd_data); | 158 | __kfree_skb(tdata->skb); |
| 154 | tcp_task->dd_data = NULL; | 159 | memset(tdata, 0, sizeof(struct cxgb3i_task_data)); |
| 155 | 160 | ||
| 156 | /* MNC - Do we need a check in case this is called but | 161 | /* MNC - Do we need a check in case this is called but |
| 157 | * cxgb3i_conn_alloc_pdu has never been called on the task */ | 162 | * cxgb3i_conn_alloc_pdu has never been called on the task */ |
| @@ -159,28 +164,102 @@ void cxgb3i_conn_cleanup_task(struct iscsi_task *task) | |||
| 159 | iscsi_tcp_cleanup_task(task); | 164 | iscsi_tcp_cleanup_task(task); |
| 160 | } | 165 | } |
| 161 | 166 | ||
| 162 | /* | 167 | static int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt, |
| 163 | * We do not support ahs yet | 168 | unsigned int offset, unsigned int *off, |
| 164 | */ | 169 | struct scatterlist **sgp) |
| 170 | { | ||
| 171 | int i; | ||
| 172 | struct scatterlist *sg; | ||
| 173 | |||
| 174 | for_each_sg(sgl, sg, sgcnt, i) { | ||
| 175 | if (offset < sg->length) { | ||
| 176 | *off = offset; | ||
| 177 | *sgp = sg; | ||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | offset -= sg->length; | ||
| 181 | } | ||
| 182 | return -EFAULT; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset, | ||
| 186 | unsigned int dlen, skb_frag_t *frags, | ||
| 187 | int frag_max) | ||
| 188 | { | ||
| 189 | unsigned int datalen = dlen; | ||
| 190 | unsigned int sglen = sg->length - sgoffset; | ||
| 191 | struct page *page = sg_page(sg); | ||
| 192 | int i; | ||
| 193 | |||
| 194 | i = 0; | ||
| 195 | do { | ||
| 196 | unsigned int copy; | ||
| 197 | |||
| 198 | if (!sglen) { | ||
| 199 | sg = sg_next(sg); | ||
| 200 | if (!sg) { | ||
| 201 | cxgb3i_log_error("%s, sg NULL, len %u/%u.\n", | ||
| 202 | __func__, datalen, dlen); | ||
| 203 | return -EINVAL; | ||
| 204 | } | ||
| 205 | sgoffset = 0; | ||
| 206 | sglen = sg->length; | ||
| 207 | page = sg_page(sg); | ||
| 208 | |||
| 209 | } | ||
| 210 | copy = min(datalen, sglen); | ||
| 211 | if (i && page == frags[i - 1].page && | ||
| 212 | sgoffset + sg->offset == | ||
| 213 | frags[i - 1].page_offset + frags[i - 1].size) { | ||
| 214 | frags[i - 1].size += copy; | ||
| 215 | } else { | ||
| 216 | if (i >= frag_max) { | ||
| 217 | cxgb3i_log_error("%s, too many pages %u, " | ||
| 218 | "dlen %u.\n", __func__, | ||
| 219 | frag_max, dlen); | ||
| 220 | return -EINVAL; | ||
| 221 | } | ||
| 222 | |||
| 223 | frags[i].page = page; | ||
| 224 | frags[i].page_offset = sg->offset + sgoffset; | ||
| 225 | frags[i].size = copy; | ||
| 226 | i++; | ||
| 227 | } | ||
| 228 | datalen -= copy; | ||
| 229 | sgoffset += copy; | ||
| 230 | sglen -= copy; | ||
| 231 | } while (datalen); | ||
| 232 | |||
| 233 | return i; | ||
| 234 | } | ||
| 235 | |||
| 165 | int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) | 236 | int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) |
| 166 | { | 237 | { |
| 238 | struct iscsi_conn *conn = task->conn; | ||
| 167 | struct iscsi_tcp_task *tcp_task = task->dd_data; | 239 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
| 168 | struct sk_buff *skb; | 240 | struct cxgb3i_task_data *tdata = task->dd_data + sizeof(*tcp_task); |
| 241 | struct scsi_cmnd *sc = task->sc; | ||
| 242 | int headroom = SKB_TX_PDU_HEADER_LEN; | ||
| 169 | 243 | ||
| 244 | tcp_task->dd_data = tdata; | ||
| 170 | task->hdr = NULL; | 245 | task->hdr = NULL; |
| 171 | /* always allocate rooms for AHS */ | 246 | |
| 172 | skb = alloc_skb(sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE + | 247 | /* write command, need to send data pdus */ |
| 173 | TX_HEADER_LEN, GFP_ATOMIC); | 248 | if (skb_extra_headroom && (opcode == ISCSI_OP_SCSI_DATA_OUT || |
| 174 | if (!skb) | 249 | (opcode == ISCSI_OP_SCSI_CMD && |
| 250 | (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_TO_DEVICE)))) | ||
| 251 | headroom += min(skb_extra_headroom, conn->max_xmit_dlength); | ||
| 252 | |||
| 253 | tdata->skb = alloc_skb(TX_HEADER_LEN + headroom, GFP_ATOMIC); | ||
| 254 | if (!tdata->skb) | ||
| 175 | return -ENOMEM; | 255 | return -ENOMEM; |
| 256 | skb_reserve(tdata->skb, TX_HEADER_LEN); | ||
| 176 | 257 | ||
| 177 | cxgb3i_tx_debug("task 0x%p, opcode 0x%x, skb 0x%p.\n", | 258 | cxgb3i_tx_debug("task 0x%p, opcode 0x%x, skb 0x%p.\n", |
| 178 | task, opcode, skb); | 259 | task, opcode, tdata->skb); |
| 179 | 260 | ||
| 180 | tcp_task->dd_data = skb; | 261 | task->hdr = (struct iscsi_hdr *)tdata->skb->data; |
| 181 | skb_reserve(skb, TX_HEADER_LEN); | 262 | task->hdr_max = SKB_TX_PDU_HEADER_LEN; |
| 182 | task->hdr = (struct iscsi_hdr *)skb->data; | ||
| 183 | task->hdr_max = sizeof(struct iscsi_hdr); | ||
| 184 | 263 | ||
| 185 | /* data_out uses scsi_cmd's itt */ | 264 | /* data_out uses scsi_cmd's itt */ |
| 186 | if (opcode != ISCSI_OP_SCSI_DATA_OUT) | 265 | if (opcode != ISCSI_OP_SCSI_DATA_OUT) |
| @@ -192,13 +271,13 @@ int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) | |||
| 192 | int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset, | 271 | int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset, |
| 193 | unsigned int count) | 272 | unsigned int count) |
| 194 | { | 273 | { |
| 195 | struct iscsi_tcp_task *tcp_task = task->dd_data; | ||
| 196 | struct sk_buff *skb = tcp_task->dd_data; | ||
| 197 | struct iscsi_conn *conn = task->conn; | 274 | struct iscsi_conn *conn = task->conn; |
| 198 | struct page *pg; | 275 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
| 276 | struct cxgb3i_task_data *tdata = tcp_task->dd_data; | ||
| 277 | struct sk_buff *skb = tdata->skb; | ||
| 199 | unsigned int datalen = count; | 278 | unsigned int datalen = count; |
| 200 | int i, padlen = iscsi_padding(count); | 279 | int i, padlen = iscsi_padding(count); |
| 201 | skb_frag_t *frag; | 280 | struct page *pg; |
| 202 | 281 | ||
| 203 | cxgb3i_tx_debug("task 0x%p,0x%p, offset %u, count %u, skb 0x%p.\n", | 282 | cxgb3i_tx_debug("task 0x%p,0x%p, offset %u, count %u, skb 0x%p.\n", |
| 204 | task, task->sc, offset, count, skb); | 283 | task, task->sc, offset, count, skb); |
| @@ -209,90 +288,94 @@ int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset, | |||
| 209 | return 0; | 288 | return 0; |
| 210 | 289 | ||
| 211 | if (task->sc) { | 290 | if (task->sc) { |
| 212 | struct scatterlist *sg; | 291 | struct scsi_data_buffer *sdb = scsi_out(task->sc); |
| 213 | struct scsi_data_buffer *sdb; | 292 | struct scatterlist *sg = NULL; |
| 214 | unsigned int sgoffset = offset; | 293 | int err; |
| 215 | struct page *sgpg; | 294 | |
| 216 | unsigned int sglen; | 295 | tdata->offset = offset; |
| 217 | 296 | tdata->count = count; | |
| 218 | sdb = scsi_out(task->sc); | 297 | err = sgl_seek_offset(sdb->table.sgl, sdb->table.nents, |
| 219 | sg = sdb->table.sgl; | 298 | tdata->offset, &tdata->sgoffset, &sg); |
| 220 | 299 | if (err < 0) { | |
| 221 | for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { | 300 | cxgb3i_log_warn("tpdu, sgl %u, bad offset %u/%u.\n", |
| 222 | cxgb3i_tx_debug("sg %d, page 0x%p, len %u offset %u\n", | 301 | sdb->table.nents, tdata->offset, |
| 223 | i, sg_page(sg), sg->length, sg->offset); | 302 | sdb->length); |
| 224 | 303 | return err; | |
| 225 | if (sgoffset < sg->length) | ||
| 226 | break; | ||
| 227 | sgoffset -= sg->length; | ||
| 228 | } | 304 | } |
| 229 | sgpg = sg_page(sg); | 305 | err = sgl_read_to_frags(sg, tdata->sgoffset, tdata->count, |
| 230 | sglen = sg->length - sgoffset; | 306 | tdata->frags, MAX_PDU_FRAGS); |
| 231 | 307 | if (err < 0) { | |
| 232 | do { | 308 | cxgb3i_log_warn("tpdu, sgl %u, bad offset %u + %u.\n", |
| 233 | int j = skb_shinfo(skb)->nr_frags; | 309 | sdb->table.nents, tdata->offset, |
| 234 | unsigned int copy; | 310 | tdata->count); |
| 235 | 311 | return err; | |
| 236 | if (!sglen) { | 312 | } |
| 237 | sg = sg_next(sg); | 313 | tdata->nr_frags = err; |
| 238 | sgpg = sg_page(sg); | 314 | |
| 239 | sgoffset = 0; | 315 | if (tdata->nr_frags > MAX_SKB_FRAGS || |
| 240 | sglen = sg->length; | 316 | (padlen && tdata->nr_frags == MAX_SKB_FRAGS)) { |
| 241 | ++i; | 317 | char *dst = skb->data + task->hdr_len; |
| 318 | skb_frag_t *frag = tdata->frags; | ||
| 319 | |||
| 320 | /* data fits in the skb's headroom */ | ||
| 321 | for (i = 0; i < tdata->nr_frags; i++, frag++) { | ||
| 322 | char *src = kmap_atomic(frag->page, | ||
| 323 | KM_SOFTIRQ0); | ||
| 324 | |||
| 325 | memcpy(dst, src+frag->page_offset, frag->size); | ||
| 326 | dst += frag->size; | ||
| 327 | kunmap_atomic(src, KM_SOFTIRQ0); | ||
| 242 | } | 328 | } |
| 243 | copy = min(sglen, datalen); | 329 | if (padlen) { |
| 244 | if (j && skb_can_coalesce(skb, j, sgpg, | 330 | memset(dst, 0, padlen); |
| 245 | sg->offset + sgoffset)) { | 331 | padlen = 0; |
| 246 | skb_shinfo(skb)->frags[j - 1].size += copy; | ||
| 247 | } else { | ||
| 248 | get_page(sgpg); | ||
| 249 | skb_fill_page_desc(skb, j, sgpg, | ||
| 250 | sg->offset + sgoffset, copy); | ||
| 251 | } | 332 | } |
| 252 | sgoffset += copy; | 333 | skb_put(skb, count + padlen); |
| 253 | sglen -= copy; | 334 | } else { |
| 254 | datalen -= copy; | 335 | /* data fit into frag_list */ |
| 255 | } while (datalen); | 336 | for (i = 0; i < tdata->nr_frags; i++) |
| 337 | get_page(tdata->frags[i].page); | ||
| 338 | |||
| 339 | memcpy(skb_shinfo(skb)->frags, tdata->frags, | ||
| 340 | sizeof(skb_frag_t) * tdata->nr_frags); | ||
| 341 | skb_shinfo(skb)->nr_frags = tdata->nr_frags; | ||
| 342 | skb->len += count; | ||
| 343 | skb->data_len += count; | ||
| 344 | skb->truesize += count; | ||
| 345 | } | ||
| 346 | |||
| 256 | } else { | 347 | } else { |
| 257 | pg = virt_to_page(task->data); | 348 | pg = virt_to_page(task->data); |
| 258 | 349 | ||
| 259 | while (datalen) { | 350 | get_page(pg); |
| 260 | i = skb_shinfo(skb)->nr_frags; | 351 | skb_fill_page_desc(skb, 0, pg, offset_in_page(task->data), |
| 261 | frag = &skb_shinfo(skb)->frags[i]; | 352 | count); |
| 262 | 353 | skb->len += count; | |
| 263 | get_page(pg); | 354 | skb->data_len += count; |
| 264 | frag->page = pg; | 355 | skb->truesize += count; |
| 265 | frag->page_offset = 0; | ||
| 266 | frag->size = min((unsigned int)PAGE_SIZE, datalen); | ||
| 267 | |||
| 268 | skb_shinfo(skb)->nr_frags++; | ||
| 269 | datalen -= frag->size; | ||
| 270 | pg++; | ||
| 271 | } | ||
| 272 | } | 356 | } |
| 273 | 357 | ||
| 274 | if (padlen) { | 358 | if (padlen) { |
| 275 | i = skb_shinfo(skb)->nr_frags; | 359 | i = skb_shinfo(skb)->nr_frags; |
| 276 | frag = &skb_shinfo(skb)->frags[i]; | 360 | get_page(pad_page); |
| 277 | frag->page = pad_page; | 361 | skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, pad_page, 0, |
| 278 | frag->page_offset = 0; | 362 | padlen); |
| 279 | frag->size = padlen; | 363 | |
| 280 | skb_shinfo(skb)->nr_frags++; | 364 | skb->data_len += padlen; |
| 365 | skb->truesize += padlen; | ||
| 366 | skb->len += padlen; | ||
| 281 | } | 367 | } |
| 282 | 368 | ||
| 283 | datalen = count + padlen; | ||
| 284 | skb->data_len += datalen; | ||
| 285 | skb->truesize += datalen; | ||
| 286 | skb->len += datalen; | ||
| 287 | return 0; | 369 | return 0; |
| 288 | } | 370 | } |
| 289 | 371 | ||
| 290 | int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) | 372 | int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) |
| 291 | { | 373 | { |
| 292 | struct iscsi_tcp_task *tcp_task = task->dd_data; | ||
| 293 | struct sk_buff *skb = tcp_task->dd_data; | ||
| 294 | struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; | 374 | struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; |
| 295 | struct cxgb3i_conn *cconn = tcp_conn->dd_data; | 375 | struct cxgb3i_conn *cconn = tcp_conn->dd_data; |
| 376 | struct iscsi_tcp_task *tcp_task = task->dd_data; | ||
| 377 | struct cxgb3i_task_data *tdata = tcp_task->dd_data; | ||
| 378 | struct sk_buff *skb = tdata->skb; | ||
| 296 | unsigned int datalen; | 379 | unsigned int datalen; |
| 297 | int err; | 380 | int err; |
| 298 | 381 | ||
| @@ -300,13 +383,14 @@ int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) | |||
| 300 | return 0; | 383 | return 0; |
| 301 | 384 | ||
| 302 | datalen = skb->data_len; | 385 | datalen = skb->data_len; |
| 303 | tcp_task->dd_data = NULL; | 386 | tdata->skb = NULL; |
| 304 | err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb); | 387 | err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb); |
| 305 | cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n", | ||
| 306 | task, skb, skb->len, skb->data_len, err); | ||
| 307 | if (err > 0) { | 388 | if (err > 0) { |
| 308 | int pdulen = err; | 389 | int pdulen = err; |
| 309 | 390 | ||
| 391 | cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n", | ||
| 392 | task, skb, skb->len, skb->data_len, err); | ||
| 393 | |||
| 310 | if (task->conn->hdrdgst_en) | 394 | if (task->conn->hdrdgst_en) |
| 311 | pdulen += ISCSI_DIGEST_SIZE; | 395 | pdulen += ISCSI_DIGEST_SIZE; |
| 312 | if (datalen && task->conn->datadgst_en) | 396 | if (datalen && task->conn->datadgst_en) |
| @@ -325,12 +409,14 @@ int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) | |||
| 325 | return err; | 409 | return err; |
| 326 | } | 410 | } |
| 327 | /* reset skb to send when we are called again */ | 411 | /* reset skb to send when we are called again */ |
| 328 | tcp_task->dd_data = skb; | 412 | tdata->skb = skb; |
| 329 | return -EAGAIN; | 413 | return -EAGAIN; |
| 330 | } | 414 | } |
| 331 | 415 | ||
| 332 | int cxgb3i_pdu_init(void) | 416 | int cxgb3i_pdu_init(void) |
| 333 | { | 417 | { |
| 418 | if (SKB_TX_HEADROOM > (512 * MAX_SKB_FRAGS)) | ||
| 419 | skb_extra_headroom = SKB_TX_HEADROOM; | ||
| 334 | pad_page = alloc_page(GFP_KERNEL); | 420 | pad_page = alloc_page(GFP_KERNEL); |
| 335 | if (!pad_page) | 421 | if (!pad_page) |
| 336 | return -ENOMEM; | 422 | return -ENOMEM; |
| @@ -366,7 +452,9 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) | |||
| 366 | skb = skb_peek(&c3cn->receive_queue); | 452 | skb = skb_peek(&c3cn->receive_queue); |
| 367 | while (!err && skb) { | 453 | while (!err && skb) { |
| 368 | __skb_unlink(skb, &c3cn->receive_queue); | 454 | __skb_unlink(skb, &c3cn->receive_queue); |
| 369 | read += skb_ulp_pdulen(skb); | 455 | read += skb_rx_pdulen(skb); |
| 456 | cxgb3i_rx_debug("conn 0x%p, cn 0x%p, rx skb 0x%p, pdulen %u.\n", | ||
| 457 | conn, c3cn, skb, skb_rx_pdulen(skb)); | ||
| 370 | err = cxgb3i_conn_read_pdu_skb(conn, skb); | 458 | err = cxgb3i_conn_read_pdu_skb(conn, skb); |
| 371 | __kfree_skb(skb); | 459 | __kfree_skb(skb); |
| 372 | skb = skb_peek(&c3cn->receive_queue); | 460 | skb = skb_peek(&c3cn->receive_queue); |
| @@ -377,6 +465,11 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) | |||
| 377 | cxgb3i_c3cn_rx_credits(c3cn, read); | 465 | cxgb3i_c3cn_rx_credits(c3cn, read); |
| 378 | } | 466 | } |
| 379 | conn->rxdata_octets += read; | 467 | conn->rxdata_octets += read; |
| 468 | |||
| 469 | if (err) { | ||
| 470 | cxgb3i_log_info("conn 0x%p rx failed err %d.\n", conn, err); | ||
| 471 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
| 472 | } | ||
| 380 | } | 473 | } |
| 381 | 474 | ||
| 382 | void cxgb3i_conn_tx_open(struct s3_conn *c3cn) | 475 | void cxgb3i_conn_tx_open(struct s3_conn *c3cn) |
diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.h b/drivers/scsi/cxgb3i/cxgb3i_pdu.h index a3f685cc2362..0770b23d90da 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_pdu.h +++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.h | |||
| @@ -53,7 +53,7 @@ struct cpl_rx_data_ddp_norss { | |||
| 53 | #define ULP2_FLAG_DCRC_ERROR 0x20 | 53 | #define ULP2_FLAG_DCRC_ERROR 0x20 |
| 54 | #define ULP2_FLAG_PAD_ERROR 0x40 | 54 | #define ULP2_FLAG_PAD_ERROR 0x40 |
| 55 | 55 | ||
| 56 | void cxgb3i_conn_closing(struct s3_conn *); | 56 | void cxgb3i_conn_closing(struct s3_conn *c3cn); |
| 57 | void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn); | 57 | void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn); |
| 58 | void cxgb3i_conn_tx_open(struct s3_conn *c3cn); | 58 | void cxgb3i_conn_tx_open(struct s3_conn *c3cn); |
| 59 | #endif | 59 | #endif |
