static int iscsi_iser_task_xmit_unsol_data(struct iscsi_conn *conn, struct iscsi_task *task) { struct iscsi_r2t_info *r2t = &task->unsol_r2t; struct iscsi_data hdr; int error = 0; /* Send data-out PDUs while there's still unsolicited data to send */ while (iscsi_task_has_unsol_data(task)) { iscsi_prep_data_out_pdu(task, r2t, &hdr); debug_scsi("Sending data-out: itt 0x%x, data count %d\n", hdr.itt, r2t->data_count); /* the buffer description has been passed with the command */ /* Send the command */ error = iser_send_data_out(conn, task, &hdr); if (error) { r2t->datasn--; goto iscsi_iser_task_xmit_unsol_data_exit; } r2t->sent += r2t->data_count; debug_scsi("Need to send %d more as data-out PDUs\n", r2t->data_length - r2t->sent); } iscsi_iser_task_xmit_unsol_data_exit: return error; }
int iscsi_tcp_hdr_recv(struct iscsi_conn *conn) { int ahslen; struct iscsi_hdr *hdr; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; uint32_t cdgst, rdgst = 0; hdr = tcp_conn->in.hdr; /* verify PDU length */ tcp_conn->in.datalen = ntoh24(hdr->dlength); if (tcp_conn->in.datalen > conn->max_recv_dlength) { printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n", tcp_conn->in.datalen, conn->max_recv_dlength); return ISCSI_ERR_DATALEN; } tcp_conn->data_copied = 0; /* read AHS */ ahslen = hdr->hlength << 2; tcp_conn->in.offset += ahslen; tcp_conn->in.copy -= ahslen; if (tcp_conn->in.copy < 0) { printk(KERN_ERR "iscsi_tcp: can't handle AHS with length " "%d bytes\n", ahslen); return ISCSI_ERR_AHSLEN; } /* calculate read padding */ tcp_conn->in.padding = tcp_conn->in.datalen & (ISCSI_PAD_LEN-1); if (tcp_conn->in.padding) { tcp_conn->in.padding = ISCSI_PAD_LEN - tcp_conn->in.padding; debug_scsi("read padding %d bytes\n", tcp_conn->in.padding); } if (conn->hdrdgst_en) { struct scatterlist sg; sg_init_one(&sg, (u8 *)hdr, sizeof(struct iscsi_hdr) + ahslen); crypto_digest_digest(tcp_conn->rx_tfm, &sg, 1, (u8 *)&cdgst); rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) + ahslen); if (cdgst != rdgst) { printk(KERN_ERR "iscsi_tcp: hdrdgst error " "recv 0x%x calc 0x%x\n", rdgst, cdgst); return ISCSI_ERR_HDR_DGST; } } return 0; }
static int iscsi_iser_task_xmit(struct iscsi_task *task) { struct iscsi_conn *conn = task->conn; struct iscsi_iser_task *iser_task = task->dd_data; int error = 0; if (!task->sc) return iscsi_iser_mtask_xmit(conn, task); if (task->sc->sc_data_direction == DMA_TO_DEVICE) { BUG_ON(scsi_bufflen(task->sc) == 0); debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", task->itt, scsi_bufflen(task->sc), task->imm_count, task->unsol_r2t.data_length); } debug_scsi("task deq [cid %d itt 0x%x]\n", conn->id, task->itt); /* Send the cmd PDU */ if (!iser_task->command_sent) { error = iser_send_command(conn, task); if (error) goto iscsi_iser_task_xmit_exit; iser_task->command_sent = 1; } /* Send unsolicited data-out PDU(s) if necessary */ if (iscsi_task_has_unsol_data(task)) error = iscsi_iser_task_xmit_unsol_data(conn, task); iscsi_iser_task_xmit_exit: if (error && error != -ENOBUFS) iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return error; }
/** * iscsi_iser_mtask_xmit - xmit management(immediate) task * @conn: iscsi connection * @task: task management task * * Notes: * The function can return -EAGAIN in which case caller must * call it again later, or recover. '0' return code means successful * xmit. * **/ static int iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) { int error = 0; debug_scsi("task deq [cid %d itt 0x%x]\n", conn->id, task->itt); error = iser_send_control(conn, task); /* since iser xmits control with zero copy, tasks can not be recycled * right after sending them. * The recycling scheme is based on whether a response is expected * - if yes, the task is recycled at iscsi_complete_pdu * - if no, the task is recycled at iser_snd_completion */ if (error && error != -ENOBUFS) iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return error; }