mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-19 11:41:26 +00:00
- Support for SCSI AENs added
- Now sense data are sent without additional memory allocation and copy - Sending and receiving padding bytes reimplemented - Cleanups git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@699 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -490,7 +490,7 @@ static void iscsi_dump_char(int ch)
|
||||
|
||||
if (ch < 0) {
|
||||
while ((i % 16) != 0) {
|
||||
printk(LOG_FLAG " ");
|
||||
printk(" ");
|
||||
text[i] = ' ';
|
||||
i++;
|
||||
if ((i % 16) == 0)
|
||||
@@ -503,7 +503,7 @@ static void iscsi_dump_char(int ch)
|
||||
}
|
||||
|
||||
text[i] = (ch < 0x20 || (ch >= 0x80 && ch <= 0xa0)) ? ' ' : ch;
|
||||
printk(LOG_FLAG " %02x", ch);
|
||||
printk(" %02x", ch);
|
||||
i++;
|
||||
if ((i % 16) == 0) {
|
||||
printk(" | %.16s |\n", text);
|
||||
@@ -519,18 +519,18 @@ void iscsi_dump_pdu(struct iscsi_pdu *pdu)
|
||||
int i;
|
||||
|
||||
buf = (void *)&pdu->bhs;
|
||||
printk(LOG_FLAG "BHS: (%p,%zd)\n", buf, sizeof(pdu->bhs));
|
||||
printk("BHS: (%p,%zd)\n", buf, sizeof(pdu->bhs));
|
||||
for (i = 0; i < sizeof(pdu->bhs); i++)
|
||||
iscsi_dump_char(*buf++);
|
||||
iscsi_dump_char(-1);
|
||||
|
||||
buf = (void *)pdu->ahs;
|
||||
printk(LOG_FLAG "AHS: (%p,%d)\n", buf, pdu->ahssize);
|
||||
printk("AHS: (%p,%d)\n", buf, pdu->ahssize);
|
||||
for (i = 0; i < pdu->ahssize; i++)
|
||||
iscsi_dump_char(*buf++);
|
||||
iscsi_dump_char(-1);
|
||||
|
||||
printk(LOG_FLAG "Data: (%d)\n", pdu->datasize);
|
||||
printk("Data: (%d)\n", pdu->datasize);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SCST_DEBUG */
|
||||
|
||||
@@ -57,10 +57,11 @@ int digest_init(struct iscsi_conn *conn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 evaluate_crc32_from_sg(struct scatterlist *sg, int total,
|
||||
int pad_bytes)
|
||||
static u32 evaluate_crc32_from_sg(struct scatterlist *sg, int nbytes,
|
||||
uint32_t padding)
|
||||
{
|
||||
u32 crc = ~0;
|
||||
int pad_bytes = ((nbytes + 3) & -4) - nbytes;
|
||||
|
||||
#ifdef CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES
|
||||
if (((scst_random() % 100000) == 752)) {
|
||||
@@ -70,24 +71,15 @@ static u32 evaluate_crc32_from_sg(struct scatterlist *sg, int total,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_LIBCRC32C_MODULE) || defined(CONFIG_LIBCRC32C)
|
||||
while (total > 0) {
|
||||
int d = min(min(total, (int)(sg->length)),
|
||||
(int)(PAGE_SIZE - sg->offset));
|
||||
|
||||
while (nbytes > 0) {
|
||||
int d = min(nbytes, (int)(sg->length));
|
||||
crc = crc32c(crc, sg_virt(sg), d);
|
||||
total -= d;
|
||||
nbytes -= d;
|
||||
sg++;
|
||||
}
|
||||
|
||||
if (pad_bytes) {
|
||||
u32 padding = 0;
|
||||
/*
|
||||
* Digest includes also padding for aligned pdu length,
|
||||
* hopefully it is always filled with 0s in pdu (according to
|
||||
* crypto/crc32c.c
|
||||
*/
|
||||
if (pad_bytes)
|
||||
crc = crc32c(crc, (u8 *)&padding, pad_bytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ~cpu_to_le32(crc);
|
||||
@@ -97,23 +89,25 @@ static u32 digest_header(struct iscsi_pdu *pdu)
|
||||
{
|
||||
struct scatterlist sg[2];
|
||||
unsigned int nbytes = sizeof(struct iscsi_hdr);
|
||||
int asize = (pdu->ahssize + 3) & -4;
|
||||
|
||||
sg_init_table(sg, 2);
|
||||
|
||||
sg_set_buf(&sg[0], &pdu->bhs, nbytes);
|
||||
if (pdu->ahssize) {
|
||||
sg_set_buf(&sg[1], pdu->ahs, pdu->ahssize);
|
||||
nbytes += pdu->ahssize;
|
||||
sg_set_buf(&sg[1], pdu->ahs, asize);
|
||||
nbytes += asize;
|
||||
}
|
||||
EXTRACHECKS_BUG_ON((nbytes & 3) != 0);
|
||||
return evaluate_crc32_from_sg(sg, nbytes, 0);
|
||||
}
|
||||
|
||||
static u32 digest_data(struct iscsi_cmnd *cmd, u32 osize, u32 offset)
|
||||
static u32 digest_data(struct iscsi_cmnd *cmd, u32 size, u32 offset,
|
||||
uint32_t padding)
|
||||
{
|
||||
struct scatterlist *sg = cmd->sg;
|
||||
int idx, count;
|
||||
struct scatterlist saved_sg;
|
||||
u32 size = (osize + 3) & ~3;
|
||||
u32 crc;
|
||||
|
||||
offset += sg[0].offset;
|
||||
@@ -130,7 +124,7 @@ static u32 digest_data(struct iscsi_cmnd *cmd, u32 osize, u32 offset)
|
||||
sg[idx].offset = offset;
|
||||
sg[idx].length -= offset - saved_sg.offset;
|
||||
|
||||
crc = evaluate_crc32_from_sg(sg + idx, osize, size - osize);
|
||||
crc = evaluate_crc32_from_sg(sg + idx, size, padding);
|
||||
|
||||
sg[idx] = saved_sg;
|
||||
return crc;
|
||||
@@ -178,7 +172,8 @@ int digest_rx_data(struct iscsi_cmnd *cmnd)
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
crc = digest_data(req, cmnd->pdu.datasize, offset);
|
||||
crc = digest_data(req, cmnd->pdu.datasize, offset,
|
||||
cmnd->conn->rpadding);
|
||||
|
||||
if (unlikely(crc != cmnd->ddigest)) {
|
||||
PRINT_ERROR("%s", "RX data digest failed");
|
||||
@@ -213,11 +208,7 @@ void digest_tx_data(struct iscsi_cmnd *cmnd)
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cmnd is used here regardless of its sg comes from parent or was
|
||||
* allocated for this cmnd only, see cmnd_send_pdu()
|
||||
*/
|
||||
cmnd->ddigest = digest_data(cmnd, cmnd->pdu.datasize, offset);
|
||||
cmnd->ddigest = digest_data(cmnd, cmnd->pdu.datasize, offset, 0);
|
||||
TRACE_DBG("TX data digest for cmd %p: %x (offset %d, opcode %x)", cmnd,
|
||||
cmnd->ddigest, offset, cmnd_opcode(cmnd));
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ DECLARE_WAIT_QUEUE_HEAD(iscsi_wr_waitQ);
|
||||
static struct page *dummy_page;
|
||||
static struct scatterlist dummy_sg;
|
||||
|
||||
static uint8_t sense_unexpected_unsolicited_data[SCST_STANDARD_SENSE_LEN];
|
||||
|
||||
struct iscsi_thread_t {
|
||||
struct task_struct *thr;
|
||||
struct list_head threads_list_entry;
|
||||
@@ -242,13 +244,14 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
|
||||
/* Order between above and below code is important! */
|
||||
|
||||
if (cmnd->scst_cmd) {
|
||||
if ((cmnd->scst_cmd != NULL) || (cmnd->scst_aen != NULL)) {
|
||||
switch (cmnd->scst_state) {
|
||||
case ISCSI_CMD_STATE_PROCESSED:
|
||||
TRACE_DBG("cmd %p PROCESSED", cmnd);
|
||||
scst_tgt_cmd_done(cmnd->scst_cmd,
|
||||
SCST_CONTEXT_DIRECT);
|
||||
break;
|
||||
|
||||
case ISCSI_CMD_STATE_AFTER_PREPROC:
|
||||
{
|
||||
struct scst_cmd *scst_cmd = cmnd->scst_cmd;
|
||||
@@ -260,6 +263,12 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
SCST_CONTEXT_THREAD);
|
||||
break;
|
||||
}
|
||||
|
||||
case ISCSI_CMD_STATE_AEN:
|
||||
TRACE_DBG("cmd %p AEN PROCESSED", cmnd);
|
||||
scst_aen_done(cmnd->scst_aen);
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINT_CRIT_ERROR("Unexpected cmnd scst state "
|
||||
"%d", cmnd->scst_state);
|
||||
@@ -283,7 +292,7 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
|
||||
if (cmnd->own_sg) {
|
||||
TRACE_DBG("%s", "own_sg");
|
||||
if (cmnd->sg != &dummy_sg)
|
||||
if ((cmnd->sg != &dummy_sg) && (cmnd->sg != cmnd->rsp_sg))
|
||||
scst_free(cmnd->sg, cmnd->sg_cnt);
|
||||
#ifdef CONFIG_SCST_DEBUG
|
||||
cmnd->own_sg = 0;
|
||||
@@ -577,22 +586,6 @@ static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags)
|
||||
return;
|
||||
}
|
||||
|
||||
static void iscsi_set_datasize(struct iscsi_cmnd *cmnd, u32 offset, u32 size)
|
||||
{
|
||||
cmnd->pdu.datasize = size;
|
||||
|
||||
if (size & 3) {
|
||||
u32 last_off = offset + size;
|
||||
int idx = last_off >> PAGE_SHIFT;
|
||||
u8 *p = (u8 *)page_address(sg_page(&cmnd->sg[idx])) +
|
||||
(last_off & ~PAGE_MASK);
|
||||
int i = 4 - (size & 3);
|
||||
while (i--)
|
||||
*p++ = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
|
||||
{
|
||||
struct iscsi_cmnd *rsp;
|
||||
@@ -625,7 +618,7 @@ static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
|
||||
|
||||
if (size <= pdusize) {
|
||||
TRACE_DBG("offset %d, size %d", offset, size);
|
||||
iscsi_set_datasize(rsp, offset, size);
|
||||
rsp->pdu.datasize = size;
|
||||
if (send_status) {
|
||||
TRACE_DBG("status %x", status);
|
||||
rsp_hdr->flags =
|
||||
@@ -649,7 +642,7 @@ static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
|
||||
TRACE_DBG("pdusize %d, offset %d, size %d", pdusize, offset,
|
||||
size);
|
||||
|
||||
iscsi_set_datasize(rsp, offset, pdusize);
|
||||
rsp->pdu.datasize = pdusize;
|
||||
|
||||
size -= pdusize;
|
||||
offset += pdusize;
|
||||
@@ -666,7 +659,6 @@ static struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req, int status,
|
||||
{
|
||||
struct iscsi_cmnd *rsp;
|
||||
struct iscsi_scsi_rsp_hdr *rsp_hdr;
|
||||
struct iscsi_sense_data *sense;
|
||||
struct scatterlist *sg;
|
||||
|
||||
rsp = iscsi_cmnd_create_rsp_cmnd(req);
|
||||
@@ -681,27 +673,19 @@ static struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req, int status,
|
||||
|
||||
if (SCST_SENSE_VALID(sense_buf)) {
|
||||
TRACE_DBG("%s", "SENSE VALID");
|
||||
/* ToDo: __GFP_NOFAIL ?? */
|
||||
sg = rsp->sg = scst_alloc(PAGE_SIZE, GFP_KERNEL|__GFP_NOFAIL,
|
||||
&rsp->sg_cnt);
|
||||
if (sg == NULL) {
|
||||
;/* ToDo */;
|
||||
}
|
||||
rsp->own_sg = 1;
|
||||
sense = (struct iscsi_sense_data *)page_address(sg_page(&sg[0]));
|
||||
sense->length = cpu_to_be16(sense_len);
|
||||
memcpy(sense->data, sense_buf, sense_len);
|
||||
rsp->pdu.datasize = sizeof(struct iscsi_sense_data) + sense_len;
|
||||
rsp->bufflen = (rsp->pdu.datasize + 3) & -4;
|
||||
if (rsp->bufflen - rsp->pdu.datasize) {
|
||||
unsigned int i = rsp->pdu.datasize;
|
||||
u8 *p = (u8 *)sense + i;
|
||||
|
||||
while (i < rsp->bufflen) {
|
||||
*p++ = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
sg = rsp->sg = rsp->rsp_sg;
|
||||
rsp->sg_cnt = 2;
|
||||
rsp->own_sg = 1;
|
||||
|
||||
sg_init_table(sg, 2);
|
||||
sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr));
|
||||
sg_set_buf(&sg[1], sense_buf, sense_len);
|
||||
|
||||
rsp->sense_hdr.length = cpu_to_be16(sense_len);
|
||||
|
||||
rsp->pdu.datasize = sizeof(rsp->sense_hdr) + sense_len;
|
||||
rsp->bufflen = rsp->pdu.datasize;
|
||||
} else {
|
||||
rsp->pdu.datasize = 0;
|
||||
rsp->bufflen = 0;
|
||||
@@ -710,26 +694,11 @@ static struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req, int status,
|
||||
return rsp;
|
||||
}
|
||||
|
||||
static struct iscsi_cmnd *create_sense_rsp(struct iscsi_cmnd *req,
|
||||
u8 sense_key, u8 asc, u8 ascq)
|
||||
{
|
||||
u8 sense[14];
|
||||
memset(sense, 0, sizeof(sense));
|
||||
sense[0] = 0xf0;
|
||||
sense[2] = sense_key;
|
||||
sense[7] = 6; /* Additional sense length */
|
||||
sense[12] = asc;
|
||||
sense[13] = ascq;
|
||||
return create_status_rsp(req, SAM_STAT_CHECK_CONDITION, sense,
|
||||
sizeof(sense));
|
||||
}
|
||||
|
||||
static void iscsi_cmnd_reject(struct iscsi_cmnd *req, int reason)
|
||||
{
|
||||
struct iscsi_cmnd *rsp;
|
||||
struct iscsi_reject_hdr *rsp_hdr;
|
||||
struct scatterlist *sg;
|
||||
char *addr;
|
||||
|
||||
TRACE_MGMT_DBG("Reject: req %p, reason %x", req, reason);
|
||||
|
||||
@@ -744,16 +713,10 @@ static void iscsi_cmnd_reject(struct iscsi_cmnd *req, int reason)
|
||||
rsp_hdr->ffffffff = ISCSI_RESERVED_TAG;
|
||||
rsp_hdr->reason = reason;
|
||||
|
||||
/* ToDo: __GFP_NOFAIL ?? */
|
||||
sg = rsp->sg = scst_alloc(PAGE_SIZE, GFP_KERNEL|__GFP_NOFAIL,
|
||||
&rsp->sg_cnt);
|
||||
if (sg == NULL) {
|
||||
;/* ToDo */;
|
||||
}
|
||||
sg = rsp->sg = rsp->rsp_sg;
|
||||
rsp->sg_cnt = 1;
|
||||
rsp->own_sg = 1;
|
||||
addr = page_address(sg_page(&sg[0]));
|
||||
clear_page(addr);
|
||||
memcpy(addr, &req->pdu.bhs, sizeof(struct iscsi_hdr));
|
||||
sg_init_one(sg, &req->pdu.bhs, sizeof(struct iscsi_hdr));
|
||||
rsp->bufflen = rsp->pdu.datasize = sizeof(struct iscsi_hdr);
|
||||
|
||||
iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_REMOVE_HASH |
|
||||
@@ -971,7 +934,6 @@ static void cmnd_prepare_get_rejected_cmd_data(struct iscsi_cmnd *cmnd)
|
||||
|
||||
addr = (char __force __user *)(page_address(sg_page(&sg[0])));
|
||||
sBUG_ON(addr == NULL);
|
||||
size = (size + 3) & -4;
|
||||
conn->read_size = size;
|
||||
for (i = 0; size > PAGE_SIZE; i++, size -= cmnd->bufflen) {
|
||||
/* We already checked pdu.datasize in check_segment_length() */
|
||||
@@ -1059,7 +1021,7 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn,
|
||||
offset &= ~PAGE_MASK;
|
||||
|
||||
conn->read_msg.msg_iov = conn->read_iov;
|
||||
conn->read_size = size = (size + 3) & -4;
|
||||
conn->read_size = size;
|
||||
|
||||
i = 0;
|
||||
while (1) {
|
||||
@@ -1077,7 +1039,6 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn,
|
||||
TRACE_DBG("idx=%d, offset=%u, size=%d, iov_len=%zd, addr=%p",
|
||||
idx, offset, size, conn->read_iov[i].iov_len, addr);
|
||||
size -= conn->read_iov[i].iov_len;
|
||||
offset = 0;
|
||||
if (unlikely(++i >= ISCSI_CONN_IOV_MAX)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters by sending too much data (size "
|
||||
@@ -1088,6 +1049,7 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn,
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
offset = sg[idx].offset;
|
||||
}
|
||||
TRACE_DBG("msg_iov=%p, msg_iovlen=%zd",
|
||||
conn->read_msg.msg_iov, conn->read_msg.msg_iovlen);
|
||||
@@ -1241,7 +1203,6 @@ static int noop_out_start(struct iscsi_cmnd *cmnd)
|
||||
size = cmnd->pdu.datasize;
|
||||
|
||||
if (size) {
|
||||
size = (size + 3) & -4;
|
||||
conn->read_msg.msg_iov = conn->read_iov;
|
||||
if (cmnd->pdu.bhs.itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
|
||||
struct scatterlist *sg;
|
||||
@@ -1410,7 +1371,9 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
req->pdu.datasize)) {
|
||||
PRINT_ERROR("Unexpected unsolicited data (ITT %x "
|
||||
"CDB %x", cmnd_itt(req), req_hdr->scb[0]);
|
||||
create_sense_rsp(req, ABORTED_COMMAND, 0xc, 0xc);
|
||||
create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
|
||||
sense_unexpected_unsolicited_data,
|
||||
sizeof(sense_unexpected_unsolicited_data));
|
||||
cmnd_reject_scsi_cmd(req);
|
||||
goto out;
|
||||
}
|
||||
@@ -1461,7 +1424,9 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
if (unlikely(dir != SCST_DATA_WRITE)) {
|
||||
PRINT_ERROR("pdu.datasize(%d) >0, but dir(%x) isn't "
|
||||
"WRITE", req->pdu.datasize, dir);
|
||||
create_sense_rsp(req, ABORTED_COMMAND, 0xc, 0xc);
|
||||
create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
|
||||
sense_unexpected_unsolicited_data,
|
||||
sizeof(sense_unexpected_unsolicited_data));
|
||||
cmnd_reject_scsi_cmd(req);
|
||||
} else
|
||||
res = cmnd_prepare_recv_pdu(conn, req, 0,
|
||||
@@ -2092,35 +2057,6 @@ out_rejected:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void __cmnd_send_pdu(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd,
|
||||
u32 offset, u32 size)
|
||||
{
|
||||
TRACE_DBG("%p %u,%u,%u", cmnd, offset, size, cmnd->bufflen);
|
||||
|
||||
iscsi_extracheck_is_wr_thread(conn);
|
||||
|
||||
sBUG_ON(offset > cmnd->bufflen);
|
||||
sBUG_ON(offset + size > cmnd->bufflen);
|
||||
|
||||
conn->write_offset = offset;
|
||||
conn->write_size += size;
|
||||
return;
|
||||
}
|
||||
|
||||
static void cmnd_send_pdu(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
u32 size;
|
||||
|
||||
if (!cmnd->pdu.datasize)
|
||||
return;
|
||||
|
||||
size = (cmnd->pdu.datasize + 3) & -4;
|
||||
sBUG_ON(cmnd->sg == NULL);
|
||||
sBUG_ON(cmnd->bufflen != size);
|
||||
__cmnd_send_pdu(conn, cmnd, 0, size);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: the code belows passes a kernel space pointer (&opt) to setsockopt()
|
||||
* while the declaration of setsockopt specifies that it expects a user space
|
||||
@@ -2144,7 +2080,7 @@ void cmnd_tx_start(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
struct iscsi_conn *conn = cmnd->conn;
|
||||
|
||||
TRACE_DBG("%p:%p:%x", conn, cmnd, cmnd_opcode(cmnd));
|
||||
TRACE_DBG("conn %p, cmnd %p, opcode %x", conn, cmnd, cmnd_opcode(cmnd));
|
||||
iscsi_cmnd_set_length(&cmnd->pdu);
|
||||
|
||||
iscsi_extracheck_is_wr_thread(conn);
|
||||
@@ -2155,16 +2091,15 @@ void cmnd_tx_start(struct iscsi_cmnd *cmnd)
|
||||
conn->write_iop->iov_base = (void __force __user *)(&cmnd->pdu.bhs);
|
||||
conn->write_iop->iov_len = sizeof(cmnd->pdu.bhs);
|
||||
conn->write_iop_used = 1;
|
||||
conn->write_size = sizeof(cmnd->pdu.bhs);
|
||||
conn->write_size = sizeof(cmnd->pdu.bhs) + cmnd->pdu.datasize;
|
||||
conn->write_offset = 0;
|
||||
|
||||
switch (cmnd_opcode(cmnd)) {
|
||||
case ISCSI_OP_NOOP_IN:
|
||||
cmnd_set_sn(cmnd, 1);
|
||||
cmnd_send_pdu(conn, cmnd);
|
||||
break;
|
||||
case ISCSI_OP_SCSI_RSP:
|
||||
cmnd_set_sn(cmnd, 1);
|
||||
cmnd_send_pdu(conn, cmnd);
|
||||
break;
|
||||
case ISCSI_OP_SCSI_TASK_MGT_RSP:
|
||||
cmnd_set_sn(cmnd, 1);
|
||||
@@ -2178,8 +2113,15 @@ void cmnd_tx_start(struct iscsi_cmnd *cmnd)
|
||||
(struct iscsi_data_in_hdr *)&cmnd->pdu.bhs;
|
||||
u32 offset = cpu_to_be32(rsp->buffer_offset);
|
||||
|
||||
TRACE_DBG("cmnd %p, offset %u, datasize %u, bufflen %u", cmnd,
|
||||
offset, cmnd->pdu.datasize, cmnd->bufflen);
|
||||
|
||||
sBUG_ON(offset > cmnd->bufflen);
|
||||
sBUG_ON(offset + cmnd->pdu.datasize > cmnd->bufflen);
|
||||
|
||||
conn->write_offset = offset;
|
||||
|
||||
cmnd_set_sn(cmnd, (rsp->flags & ISCSI_FLG_FINAL) ? 1 : 0);
|
||||
__cmnd_send_pdu(conn, cmnd, offset, cmnd->pdu.datasize);
|
||||
break;
|
||||
}
|
||||
case ISCSI_OP_LOGOUT_RSP:
|
||||
@@ -2193,15 +2135,12 @@ void cmnd_tx_start(struct iscsi_cmnd *cmnd)
|
||||
break;
|
||||
case ISCSI_OP_REJECT:
|
||||
cmnd_set_sn(cmnd, 1);
|
||||
cmnd_send_pdu(conn, cmnd);
|
||||
break;
|
||||
default:
|
||||
PRINT_ERROR("unexpected cmnd op %x", cmnd_opcode(cmnd));
|
||||
PRINT_ERROR("Unexpected cmnd op %x", cmnd_opcode(cmnd));
|
||||
break;
|
||||
}
|
||||
|
||||
/* move this? */
|
||||
conn->write_size = (conn->write_size + 3) & -4;
|
||||
iscsi_dump_pdu(&cmnd->pdu);
|
||||
return;
|
||||
}
|
||||
@@ -2912,6 +2851,116 @@ static void iscsi_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd)
|
||||
return;
|
||||
}
|
||||
|
||||
static int iscsi_scsi_aen(struct scst_aen *aen)
|
||||
{
|
||||
int res = SCST_AEN_RES_SUCCESS;
|
||||
uint64_t lun = scst_aen_get_lun(aen);
|
||||
const uint8_t *sense = scst_aen_get_sense(aen);
|
||||
int sense_len = scst_aen_get_sense_len(aen);
|
||||
struct iscsi_session *sess = scst_sess_get_tgt_priv(
|
||||
scst_aen_get_sess(aen));
|
||||
struct iscsi_conn *conn;
|
||||
bool found;
|
||||
struct iscsi_cmnd *fake_req, *rsp;
|
||||
struct iscsi_async_msg_hdr *rsp_hdr;
|
||||
struct scatterlist *sg;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_MGMT_DBG("SCSI AEN to sess %p (initiator %s)", sess,
|
||||
sess->initiator_name);
|
||||
|
||||
mutex_lock(&sess->target->target_mutex);
|
||||
|
||||
found = false;
|
||||
list_for_each_entry_reverse(conn, &sess->conn_list, conn_list_entry) {
|
||||
if (!conn->conn_shutting_down &&
|
||||
(conn->conn_reinst_successor == NULL)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
TRACE_MGMT_DBG("Unable to find alive conn for sess %p", sess);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Create a fake request */
|
||||
fake_req = cmnd_alloc(conn, NULL);
|
||||
if (fake_req == NULL) {
|
||||
PRINT_ERROR("%s", "Unable to alloc fake AEN request");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
mutex_unlock(&sess->target->target_mutex);
|
||||
|
||||
rsp = iscsi_cmnd_create_rsp_cmnd(fake_req);
|
||||
if (rsp == NULL) {
|
||||
PRINT_ERROR("%s", "Unable to alloc AEN rsp");
|
||||
goto out_err_free_req;
|
||||
}
|
||||
|
||||
fake_req->scst_state = ISCSI_CMD_STATE_AEN;
|
||||
fake_req->scst_aen = aen;
|
||||
|
||||
rsp_hdr = (struct iscsi_async_msg_hdr *)&rsp->pdu.bhs;
|
||||
|
||||
rsp_hdr->opcode = ISCSI_OP_ASYNC_MSG;
|
||||
rsp_hdr->flags = ISCSI_FLG_FINAL;
|
||||
rsp_hdr->lun = lun; /* it's already in SCSI form */
|
||||
rsp_hdr->ffffffff = 0xffffffff;
|
||||
rsp_hdr->async_event = ISCSI_ASYNC_SCSI;
|
||||
|
||||
sg = rsp->sg = rsp->rsp_sg;
|
||||
rsp->sg_cnt = 2;
|
||||
rsp->own_sg = 1;
|
||||
|
||||
sg_init_table(sg, 2);
|
||||
sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr));
|
||||
sg_set_buf(&sg[1], sense, sense_len);
|
||||
|
||||
rsp->sense_hdr.length = cpu_to_be16(sense_len);
|
||||
rsp->pdu.datasize = sizeof(rsp->sense_hdr) + sense_len;
|
||||
rsp->bufflen = rsp->pdu.datasize;
|
||||
|
||||
iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_WAKE);
|
||||
|
||||
req_cmnd_release(fake_req);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_err_free_req:
|
||||
req_cmnd_release(fake_req);
|
||||
|
||||
out_err:
|
||||
mutex_unlock(&sess->target->target_mutex);
|
||||
res = SCST_AEN_RES_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int iscsi_report_aen(struct scst_aen *aen)
|
||||
{
|
||||
int res;
|
||||
int event_fn = scst_aen_get_event_fn(aen);
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
switch (event_fn) {
|
||||
case SCST_AEN_SCSI:
|
||||
res = iscsi_scsi_aen(aen);
|
||||
break;
|
||||
default:
|
||||
TRACE_MGMT_DBG("Unsupported AEN %d", event_fn);
|
||||
res = SCST_AEN_RES_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int iscsi_target_detect(struct scst_tgt_template *templ)
|
||||
{
|
||||
/* Nothing to do */
|
||||
@@ -2940,6 +2989,7 @@ struct scst_tgt_template iscsi_template = {
|
||||
.pre_exec = iscsi_pre_exec,
|
||||
.task_mgmt_affected_cmds_done = iscsi_task_mgmt_affected_cmds_done,
|
||||
.task_mgmt_fn_done = iscsi_task_mgmt_fn_done,
|
||||
.report_aen = iscsi_report_aen,
|
||||
};
|
||||
|
||||
static __init int iscsi_run_threads(int count, char *name, int (*fn)(void *))
|
||||
@@ -2991,6 +3041,12 @@ static int __init iscsi_init(void)
|
||||
|
||||
PRINT_INFO("iSCSI SCST Target - version %s", ISCSI_VERSION_STRING);
|
||||
|
||||
sense_unexpected_unsolicited_data[0] = 0x70;
|
||||
sense_unexpected_unsolicited_data[2] = ABORTED_COMMAND;
|
||||
sense_unexpected_unsolicited_data[7] = 6;
|
||||
sense_unexpected_unsolicited_data[12] = 0xc;
|
||||
sense_unexpected_unsolicited_data[13] = 0xc;
|
||||
|
||||
dummy_page = alloc_pages(GFP_KERNEL, 0);
|
||||
if (dummy_page == NULL) {
|
||||
PRINT_ERROR("%s", "Dummy page allocation failed");
|
||||
|
||||
@@ -73,8 +73,12 @@ struct iscsi_target {
|
||||
struct list_head session_list; /* protected by target_mutex */
|
||||
|
||||
/* Both protected by target_mutex */
|
||||
struct iscsi_sess_param trgt_sess_param;
|
||||
struct iscsi_trgt_param trgt_param;
|
||||
/*
|
||||
* Put here to have uniform parameters checking and assigning
|
||||
* from various places, including iscsi-scst-adm.
|
||||
*/
|
||||
struct iscsi_sess_param trgt_sess_param;
|
||||
|
||||
struct list_head target_list_entry;
|
||||
u32 tid;
|
||||
@@ -214,6 +218,7 @@ struct iscsi_conn {
|
||||
u32 read_size;
|
||||
int read_state;
|
||||
struct iovec *read_iov;
|
||||
uint32_t rpadding;
|
||||
|
||||
struct iscsi_target *target;
|
||||
|
||||
@@ -240,20 +245,27 @@ struct iscsi_pdu {
|
||||
typedef void (iscsi_show_info_t)(struct seq_file *seq,
|
||||
struct iscsi_target *target);
|
||||
|
||||
/* Command's states */
|
||||
/** Command's states **/
|
||||
|
||||
/* New command and SCST processes it */
|
||||
#define ISCSI_CMD_STATE_NEW 0
|
||||
|
||||
/* SCST processes cmd after scst_rx_cmd() */
|
||||
#define ISCSI_CMD_STATE_RX_CMD 1
|
||||
|
||||
/* The command returned from preprocessing_done() */
|
||||
#define ISCSI_CMD_STATE_AFTER_PREPROC 2
|
||||
|
||||
/* scst_restart_cmd() called and SCST processing it */
|
||||
#define ISCSI_CMD_STATE_RESTARTED 3
|
||||
|
||||
/* SCST done processing */
|
||||
#define ISCSI_CMD_STATE_PROCESSED 4
|
||||
|
||||
/* Command's reject reasons */
|
||||
/* AEN processing */
|
||||
#define ISCSI_CMD_STATE_AEN 5
|
||||
|
||||
/** Command's reject reasons **/
|
||||
#define ISCSI_REJECT_SCSI_CMD 1
|
||||
#define ISCSI_REJECT_CMD 2
|
||||
#define ISCSI_REJECT_DATA 3
|
||||
@@ -294,7 +306,10 @@ struct iscsi_cmnd {
|
||||
|
||||
spinlock_t rsp_cmd_lock; /* BH lock */
|
||||
|
||||
/* Unions are for readability and grepability */
|
||||
/*
|
||||
* Unions are for readability and grepability and to save some
|
||||
* cache footprint.
|
||||
*/
|
||||
|
||||
union {
|
||||
/* Protected by rsp_cmd_lock */
|
||||
@@ -312,18 +327,37 @@ struct iscsi_cmnd {
|
||||
unsigned long write_timeout;
|
||||
|
||||
/*
|
||||
* Unprotected, since could be accessed from only a single
|
||||
* All unprotected, since could be accessed from only a single
|
||||
* thread at time
|
||||
*/
|
||||
struct list_head rx_ddigest_cmd_list;
|
||||
struct list_head rx_ddigest_cmd_list_entry;
|
||||
|
||||
struct iscsi_cmnd *parent_req;
|
||||
struct iscsi_cmnd *cmd_req;
|
||||
|
||||
wait_queue_head_t scst_waitQ;
|
||||
int scst_state;
|
||||
struct scst_cmd *scst_cmd;
|
||||
/*
|
||||
* All unprotected, since could be accessed from only a single
|
||||
* thread at time
|
||||
*/
|
||||
union {
|
||||
/* Request only fields */
|
||||
struct {
|
||||
struct list_head rx_ddigest_cmd_list;
|
||||
struct list_head rx_ddigest_cmd_list_entry;
|
||||
|
||||
wait_queue_head_t scst_waitQ;
|
||||
int scst_state;
|
||||
union {
|
||||
struct scst_cmd *scst_cmd;
|
||||
struct scst_aen *scst_aen;
|
||||
};
|
||||
};
|
||||
|
||||
/* Response only fields */
|
||||
struct {
|
||||
struct scatterlist rsp_sg[2];
|
||||
struct iscsi_sense_data sense_hdr;
|
||||
};
|
||||
};
|
||||
|
||||
atomic_t ref_cnt;
|
||||
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
atomic_t net_ref_cnt;
|
||||
|
||||
@@ -39,6 +39,9 @@ enum rx_state {
|
||||
RX_INIT_DATA,
|
||||
RX_DATA,
|
||||
|
||||
RX_INIT_PADDING,
|
||||
RX_PADDING,
|
||||
|
||||
RX_INIT_DDIGEST,
|
||||
RX_DDIGEST,
|
||||
RX_CHECK_DDIGEST,
|
||||
@@ -49,6 +52,8 @@ enum rx_state {
|
||||
enum tx_state {
|
||||
TX_INIT, /* Must be zero. */
|
||||
TX_BHS_DATA,
|
||||
TX_INIT_PADDING,
|
||||
TX_PADDING,
|
||||
TX_INIT_DDIGEST,
|
||||
TX_DDIGEST,
|
||||
TX_END,
|
||||
@@ -594,26 +599,25 @@ static void start_close_conn(struct iscsi_conn *conn)
|
||||
}
|
||||
|
||||
static inline void iscsi_conn_init_read(struct iscsi_conn *conn,
|
||||
void __user *data,
|
||||
size_t len)
|
||||
void __user *data, size_t len)
|
||||
{
|
||||
len = (len + 3) & -4; /* XXX ??? */
|
||||
conn->read_iov[0].iov_base = data;
|
||||
conn->read_iov[0].iov_len = len;
|
||||
conn->read_msg.msg_iov = conn->read_iov;
|
||||
conn->read_msg.msg_iovlen = 1;
|
||||
conn->read_size = (len + 3) & -4;
|
||||
conn->read_size = len;
|
||||
return;
|
||||
}
|
||||
|
||||
static void iscsi_conn_read_ahs(struct iscsi_conn *conn,
|
||||
struct iscsi_cmnd *cmnd)
|
||||
struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
int asize = (cmnd->pdu.ahssize + 3) & -4;
|
||||
|
||||
/* ToDo: __GFP_NOFAIL ?? */
|
||||
cmnd->pdu.ahs = kmalloc(cmnd->pdu.ahssize, __GFP_NOFAIL|GFP_KERNEL);
|
||||
cmnd->pdu.ahs = kmalloc(asize, __GFP_NOFAIL|GFP_KERNEL);
|
||||
sBUG_ON(cmnd->pdu.ahs == NULL);
|
||||
iscsi_conn_init_read(conn, (void __force __user *)cmnd->pdu.ahs,
|
||||
cmnd->pdu.ahssize);
|
||||
iscsi_conn_init_read(conn, (void __force __user *)cmnd->pdu.ahs, asize);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -783,10 +787,31 @@ static int recv(struct iscsi_conn *conn)
|
||||
if (conn->read_state != RX_DATA)
|
||||
break;
|
||||
case RX_DATA:
|
||||
res = do_recv(conn, RX_INIT_PADDING);
|
||||
if (res <= 0 || conn->read_state != RX_INIT_PADDING)
|
||||
break;
|
||||
case RX_INIT_PADDING:
|
||||
{
|
||||
int psz = ((cmnd->pdu.datasize + 3) & -4) - cmnd->pdu.datasize;
|
||||
if (psz != 0) {
|
||||
TRACE_DBG("padding %d bytes", psz);
|
||||
iscsi_conn_init_read(conn,
|
||||
(void __force __user *)&conn->rpadding, psz);
|
||||
conn->read_state = RX_PADDING;
|
||||
} else if (ddigest) {
|
||||
conn->read_state = RX_INIT_DDIGEST;
|
||||
goto init_ddigest;
|
||||
} else {
|
||||
conn->read_state = RX_END;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case RX_PADDING:
|
||||
res = do_recv(conn, ddigest ? RX_INIT_DDIGEST : RX_END);
|
||||
if (res <= 0 || conn->read_state != RX_INIT_DDIGEST)
|
||||
break;
|
||||
case RX_INIT_DDIGEST:
|
||||
init_ddigest:
|
||||
iscsi_conn_init_read(conn,
|
||||
(void __force __user *)&cmnd->ddigest, sizeof(u32));
|
||||
conn->read_state = RX_DDIGEST;
|
||||
@@ -1046,17 +1071,18 @@ static int write_data(struct iscsi_conn *conn)
|
||||
{
|
||||
mm_segment_t oldfs;
|
||||
struct file *file;
|
||||
struct iovec *iop;
|
||||
struct socket *sock;
|
||||
ssize_t (*sock_sendpage)(struct socket *, struct page *, int, size_t,
|
||||
int);
|
||||
ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
|
||||
struct iscsi_cmnd *write_cmnd = conn->write_cmnd;
|
||||
struct iscsi_cmnd *ref_cmd;
|
||||
struct page *page;
|
||||
struct scatterlist *sg;
|
||||
struct iovec *iop;
|
||||
int saved_size, size, sendsize;
|
||||
int offset, idx, sg_offset;
|
||||
int flags, res, count;
|
||||
int length, offset, idx;
|
||||
int flags, res, count, sg_size;
|
||||
bool do_put = false;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -1091,7 +1117,8 @@ static int write_data(struct iscsi_conn *conn)
|
||||
}
|
||||
|
||||
file = conn->file;
|
||||
saved_size = size = conn->write_size;
|
||||
size = conn->write_size;
|
||||
saved_size = size;
|
||||
iop = conn->write_iop;
|
||||
count = conn->write_iop_used;
|
||||
|
||||
@@ -1102,17 +1129,16 @@ static int write_data(struct iscsi_conn *conn)
|
||||
|
||||
sBUG_ON(count > (signed)(sizeof(conn->write_iov) /
|
||||
sizeof(conn->write_iov[0])));
|
||||
retry:
|
||||
retry:
|
||||
oldfs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
res = vfs_writev(file,
|
||||
(struct iovec __force __user *)iop,
|
||||
count, &off);
|
||||
set_fs(oldfs);
|
||||
TRACE_WRITE("%#Lx:%u: %d(%ld)",
|
||||
TRACE_WRITE("sid %#Lx, cid %u, res %d, iov_len %ld",
|
||||
(long long unsigned int)conn->session->sid,
|
||||
conn->cid,
|
||||
res, (long)iop->iov_len);
|
||||
conn->cid, res, (long)iop->iov_len);
|
||||
if (unlikely(res <= 0)) {
|
||||
if (res == -EAGAIN) {
|
||||
conn->write_iop = iop;
|
||||
@@ -1155,11 +1181,6 @@ static int write_data(struct iscsi_conn *conn)
|
||||
__iscsi_get_page_callback(ref_cmd);
|
||||
do_put = true;
|
||||
|
||||
sg_offset = sg[0].offset;
|
||||
offset = conn->write_offset + sg_offset;
|
||||
idx = offset >> PAGE_SHIFT;
|
||||
offset &= ~PAGE_MASK;
|
||||
|
||||
sock = conn->sock;
|
||||
|
||||
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
@@ -1173,6 +1194,31 @@ static int write_data(struct iscsi_conn *conn)
|
||||
#endif
|
||||
|
||||
flags = MSG_DONTWAIT;
|
||||
sg_size = size;
|
||||
|
||||
if (sg != write_cmnd->rsp_sg) {
|
||||
offset = conn->write_offset + sg[0].offset;
|
||||
idx = offset >> PAGE_SHIFT;
|
||||
offset &= ~PAGE_MASK;
|
||||
length = min(size, (int)PAGE_SIZE - offset);
|
||||
TRACE_WRITE("write_offset %d, sg_size %d, idx %d, offset %d, "
|
||||
"length %d", conn->write_offset, sg_size, idx, offset,
|
||||
length);
|
||||
} else {
|
||||
idx = 0;
|
||||
offset = conn->write_offset;
|
||||
while (offset >= sg[idx].length) {
|
||||
offset -= sg[idx].length;
|
||||
idx++;
|
||||
}
|
||||
length = sg[idx].length - offset;
|
||||
offset += sg[idx].offset;
|
||||
sock_sendpage = sock_no_sendpage;
|
||||
TRACE_WRITE("rsp_sg: write_offset %d, sg_size %d, idx %d, "
|
||||
"offset %d, length %d", conn->write_offset, sg_size,
|
||||
idx, offset, length);
|
||||
}
|
||||
page = sg_page(&sg[idx]);
|
||||
|
||||
while (1) {
|
||||
sendpage = sock_sendpage;
|
||||
@@ -1181,8 +1227,8 @@ static int write_data(struct iscsi_conn *conn)
|
||||
{
|
||||
static DEFINE_SPINLOCK(net_priv_lock);
|
||||
spin_lock(&net_priv_lock);
|
||||
if (sg_page(&sg[idx])->net_priv != NULL) {
|
||||
if (sg_page(&sg[idx])->net_priv != ref_cmd) {
|
||||
if (unlikely(page->net_priv != NULL)) {
|
||||
if (page->net_priv != ref_cmd) {
|
||||
/*
|
||||
* This might happen if user space
|
||||
* supplies to scst_user the same
|
||||
@@ -1196,26 +1242,25 @@ static int write_data(struct iscsi_conn *conn)
|
||||
"%p, sg %p, idx %d, page %p, "
|
||||
"net_priv %p)",
|
||||
write_cmnd, ref_cmd, sg, idx,
|
||||
sg_page(&sg[idx]),
|
||||
sg_page(&sg[idx])->net_priv);
|
||||
page, page->net_priv);
|
||||
sendpage = sock_no_sendpage;
|
||||
}
|
||||
} else
|
||||
sg_page(&sg[idx])->net_priv = ref_cmd;
|
||||
page->net_priv = ref_cmd;
|
||||
spin_unlock(&net_priv_lock);
|
||||
}
|
||||
#endif
|
||||
sendsize = PAGE_SIZE - offset;
|
||||
sendsize = min(size, length);
|
||||
if (size <= sendsize) {
|
||||
retry2:
|
||||
res = sendpage(sock, sg_page(&sg[idx]), offset, size,
|
||||
flags);
|
||||
TRACE_WRITE("Final %s %#Lx:%u: %d(%lu,%u,%u, cmd %p, "
|
||||
res = sendpage(sock, page, offset, size, flags);
|
||||
TRACE_WRITE("Final %s sid %#Lx, cid %u, res %d (page "
|
||||
"index %lu, offset %u, size %u, cmd %p, "
|
||||
"page %p)", (sendpage != sock_no_sendpage) ?
|
||||
"sendpage" : "sock_no_sendpage",
|
||||
(long long unsigned int)conn->session->sid,
|
||||
conn->cid, res, sg_page(&sg[idx])->index,
|
||||
offset, size, write_cmnd, sg_page(&sg[idx]));
|
||||
conn->cid, res, page->index,
|
||||
offset, size, write_cmnd, page);
|
||||
if (unlikely(res <= 0)) {
|
||||
if (res == -EINTR)
|
||||
goto retry2;
|
||||
@@ -1223,7 +1268,7 @@ retry2:
|
||||
goto out_res;
|
||||
}
|
||||
|
||||
check_net_priv(ref_cmd, sg_page(&sg[idx]));
|
||||
check_net_priv(ref_cmd, page);
|
||||
if (res == size) {
|
||||
conn->write_size = 0;
|
||||
res = saved_size;
|
||||
@@ -1232,18 +1277,18 @@ retry2:
|
||||
|
||||
offset += res;
|
||||
size -= res;
|
||||
continue;
|
||||
goto retry2;
|
||||
}
|
||||
|
||||
retry1:
|
||||
res = sendpage(sock, sg_page(&sg[idx]), offset, sendsize,
|
||||
flags | MSG_MORE);
|
||||
TRACE_WRITE("%s %#Lx:%u: %d(%lu,%u,%u, cmd %p, page %p)",
|
||||
res = sendpage(sock, page, offset, sendsize, flags | MSG_MORE);
|
||||
TRACE_WRITE("%s sid %#Lx, cid %u, res %d (page index %lu, "
|
||||
"offset %u, sendsize %u, size %u, cmd %p, page %p)",
|
||||
(sendpage != sock_no_sendpage) ? "sendpage" :
|
||||
"sock_no_sendpage",
|
||||
(unsigned long long)conn->session->sid, conn->cid,
|
||||
res, sg_page(&sg[idx])->index, offset, sendsize,
|
||||
write_cmnd, sg_page(&sg[idx]));
|
||||
res, page->index, offset, sendsize, size,
|
||||
write_cmnd, page);
|
||||
if (unlikely(res <= 0)) {
|
||||
if (res == -EINTR)
|
||||
goto retry1;
|
||||
@@ -1251,19 +1296,25 @@ retry1:
|
||||
goto out_res;
|
||||
}
|
||||
|
||||
check_net_priv(ref_cmd, sg_page(&sg[idx]));
|
||||
if (res == sendsize) {
|
||||
idx++;
|
||||
offset = 0;
|
||||
EXTRACHECKS_BUG_ON(idx >= ref_cmd->sg_cnt);
|
||||
} else
|
||||
offset += res;
|
||||
check_net_priv(ref_cmd, page);
|
||||
|
||||
size -= res;
|
||||
|
||||
if (res == sendsize) {
|
||||
idx++;
|
||||
EXTRACHECKS_BUG_ON(idx >= ref_cmd->sg_cnt);
|
||||
page = sg_page(&sg[idx]);
|
||||
length = sg[idx].length;
|
||||
offset = sg[idx].offset;
|
||||
} else {
|
||||
offset += res;
|
||||
sendsize -= res;
|
||||
goto retry1;
|
||||
}
|
||||
}
|
||||
|
||||
out_off:
|
||||
conn->write_offset = (idx << PAGE_SHIFT) + offset - sg_offset;
|
||||
conn->write_offset += sg_size - size;
|
||||
|
||||
out_iov:
|
||||
conn->write_size = size;
|
||||
@@ -1281,7 +1332,7 @@ out:
|
||||
return res;
|
||||
|
||||
out_res:
|
||||
check_net_priv(ref_cmd, sg_page(&sg[idx]));
|
||||
check_net_priv(ref_cmd, page);
|
||||
if (res == -EAGAIN)
|
||||
goto out_off;
|
||||
/* else go through */
|
||||
@@ -1295,9 +1346,14 @@ out_err:
|
||||
(long long unsigned int)conn->session->sid,
|
||||
conn->cid, conn->write_cmnd);
|
||||
}
|
||||
if (ref_cmd->scst_cmd != NULL)
|
||||
scst_set_delivery_status(ref_cmd->scst_cmd,
|
||||
SCST_CMD_DELIVERY_FAILED);
|
||||
if ((ref_cmd->scst_cmd != NULL) || (ref_cmd->scst_aen != NULL)) {
|
||||
if (ref_cmd->scst_state == ISCSI_CMD_STATE_AEN)
|
||||
scst_set_aen_delivery_status(ref_cmd->scst_aen,
|
||||
SCST_AEN_RES_FAILED);
|
||||
else
|
||||
scst_set_delivery_status(ref_cmd->scst_cmd,
|
||||
SCST_CMD_DELIVERY_FAILED);
|
||||
}
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
@@ -1374,6 +1430,31 @@ static void init_tx_hdigest(struct iscsi_cmnd *cmnd)
|
||||
return;
|
||||
}
|
||||
|
||||
static int tx_padding(struct iscsi_cmnd *cmnd, int state)
|
||||
{
|
||||
int res, rest = cmnd->conn->write_size;
|
||||
struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
|
||||
struct kvec iov;
|
||||
static const uint32_t padding;
|
||||
|
||||
iscsi_extracheck_is_wr_thread(cmnd->conn);
|
||||
|
||||
TRACE_DBG("Sending %d padding bytes (cmd %p)", rest, cmnd);
|
||||
|
||||
iov.iov_base = (char *)(&padding) + (sizeof(uint32_t) - rest);
|
||||
iov.iov_len = rest;
|
||||
|
||||
res = kernel_sendmsg(cmnd->conn->sock, &msg, &iov, 1, rest);
|
||||
if (res > 0) {
|
||||
cmnd->conn->write_size -= res;
|
||||
if (!cmnd->conn->write_size)
|
||||
cmnd->conn->write_state = state;
|
||||
} else
|
||||
res = exit_tx(cmnd->conn, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int iscsi_do_send(struct iscsi_conn *conn, int state)
|
||||
{
|
||||
int res;
|
||||
@@ -1421,11 +1502,28 @@ int iscsi_send(struct iscsi_conn *conn)
|
||||
init_tx_hdigest(cmnd);
|
||||
conn->write_state = TX_BHS_DATA;
|
||||
case TX_BHS_DATA:
|
||||
res = iscsi_do_send(conn, ddigest && cmnd->pdu.datasize ?
|
||||
TX_INIT_DDIGEST : TX_END);
|
||||
res = iscsi_do_send(conn, cmnd->pdu.datasize ?
|
||||
TX_INIT_PADDING : TX_END);
|
||||
if (res <= 0 || conn->write_state != TX_INIT_PADDING)
|
||||
break;
|
||||
case TX_INIT_PADDING:
|
||||
cmnd->conn->write_size = ((cmnd->pdu.datasize + 3) & -4) -
|
||||
cmnd->pdu.datasize;
|
||||
if (cmnd->conn->write_size != 0)
|
||||
conn->write_state = TX_PADDING;
|
||||
else if (ddigest) {
|
||||
conn->write_state = TX_INIT_DDIGEST;
|
||||
goto init_ddigest;
|
||||
} else {
|
||||
conn->write_state = TX_END;
|
||||
break;
|
||||
}
|
||||
case TX_PADDING:
|
||||
res = tx_padding(cmnd, ddigest ? TX_INIT_DDIGEST : TX_END);
|
||||
if (res <= 0 || conn->write_state != TX_INIT_DDIGEST)
|
||||
break;
|
||||
case TX_INIT_DDIGEST:
|
||||
init_ddigest:
|
||||
cmnd->conn->write_size = sizeof(u32);
|
||||
conn->write_state = TX_DDIGEST;
|
||||
case TX_DDIGEST:
|
||||
|
||||
@@ -44,10 +44,7 @@ static int iscsi_session_alloc(struct iscsi_target *target,
|
||||
|
||||
session->target = target;
|
||||
session->sid = info->sid;
|
||||
BUILD_BUG_ON(sizeof(session->sess_param) !=
|
||||
sizeof(target->trgt_sess_param));
|
||||
memcpy(&session->sess_param, &target->trgt_sess_param,
|
||||
sizeof(session->sess_param));
|
||||
session->sess_param = target->trgt_sess_param;
|
||||
session->max_queued_cmnds = target->trgt_param.queued_cmnds;
|
||||
atomic_set(&session->active_cmds, 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user