ctask->state = ISCSI_TASK_COMPLETED;
ctask->sc = NULL;
+ /* SCSI eh reuses commands to verify us */
+ sc->SCp.ptr = NULL;
list_del_init(&ctask->running);
__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
sc->scsi_done(sc);
static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
{
- struct iscsi_conn *conn = ctask->conn;
-
- if (atomic_dec_and_test(&ctask->refcount)) {
- conn->session->tt->cleanup_cmd_task(conn, ctask);
+ if (atomic_dec_and_test(&ctask->refcount))
iscsi_complete_command(ctask);
- }
}
static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
wake_up(&conn->ehwait);
}
+static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ char *data, int datalen)
+{
+ struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
+ struct iscsi_hdr rejected_pdu;
+ uint32_t itt;
+
+ conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
+
+ if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) {
+ if (ntoh24(reject->dlength) > datalen)
+ return ISCSI_ERR_PROTO;
+
+ if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
+ memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
+ itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+ printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
+ "due to DataDigest error.\n", itt,
+ rejected_pdu.opcode);
+ }
+ }
+ return 0;
+}
+
/**
* __iscsi_complete_pdu - complete pdu
* @conn: iscsi conn
break;
}
} else if (itt == ISCSI_RESERVED_TAG) {
+ rc = iscsi_check_assign_cmdsn(session,
+ (struct iscsi_nopin*)hdr);
+ if (rc)
+ goto done;
+
switch(opcode) {
case ISCSI_OP_NOOP_IN:
if (datalen) {
break;
}
- rc = iscsi_check_assign_cmdsn(session,
- (struct iscsi_nopin*)hdr);
- if (rc)
- break;
-
if (hdr->ttt == ISCSI_RESERVED_TAG)
break;
rc = ISCSI_ERR_CONN_FAILED;
break;
case ISCSI_OP_REJECT:
- /* we need sth like iscsi_reject_rsp()*/
+ rc = iscsi_handle_reject(conn, hdr, data, datalen);
+ break;
case ISCSI_OP_ASYNC_EVENT:
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
/* we need sth like iscsi_async_event_rsp() */
sc->scsi_done = done;
sc->result = 0;
+ sc->SCp.ptr = NULL;
host = sc->device->host;
session = iscsi_hostdata(host->hostdata);
list_add_tail(&ctask->running, &conn->xmitqueue);
debug_scsi(
- "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n",
+ "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d "
+ "win %d]\n",
sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
- conn->id, (long)sc, ctask->itt, sc->request_bufflen,
+ conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
spin_unlock(&session->lock);
sc = ctask->sc;
if (!sc)
return;
+
+ conn->session->tt->cleanup_cmd_task(conn, ctask);
iscsi_ctask_mtask_cleanup(ctask);
sc->result = err;
sc->resid = sc->request_bufflen;
+ /* release ref from queuecommand */
__iscsi_put_ctask(ctask);
}
int iscsi_eh_abort(struct scsi_cmnd *sc)
{
- struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
- struct iscsi_conn *conn = ctask->conn;
- struct iscsi_session *session = conn->session;
+ struct iscsi_cmd_task *ctask;
+ struct iscsi_conn *conn;
+ struct iscsi_session *session;
int rc;
+ /*
+ * if session was ISCSI_STATE_IN_RECOVERY then we may not have
+ * got the command.
+ */
+ if (!sc->SCp.ptr) {
+ debug_scsi("sc never reached iscsi layer or it completed.\n");
+ return SUCCESS;
+ }
+
+ ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+ conn = ctask->conn;
+ session = conn->session;
+
conn->eh_abort_cnt++;
debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
return -EPERM;
}
- if (session->first_burst > session->max_burst) {
+ if ((session->imm_data_en || !session->initial_r2t_en) &&
+ session->first_burst > session->max_burst) {
printk("iscsi: invalid burst lengths: "
"first_burst %d max_burst %d\n",
session->first_burst, session->max_burst);