#include <scsi/scsi_transport_iscsi.h>
#include <scsi/libiscsi.h>
+static int iscsi_dbg_lib;
+module_param_named(debug_libiscsi, iscsi_dbg_lib, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug_libiscsi, "Turn on debugging for libiscsi module. "
+ "Set to 1 to turn on, and zero to turn off. Default "
+ "is off.");
+
+#define ISCSI_DBG_CONN(_conn, dbg_fmt, arg...) \
+ do { \
+ if (iscsi_dbg_lib) \
+ iscsi_conn_printk(KERN_INFO, _conn, \
+ "%s " dbg_fmt, \
+ __func__, ##arg); \
+ } while (0);
+
+#define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...) \
+ do { \
+ if (iscsi_dbg_lib) \
+ iscsi_session_printk(KERN_INFO, _session, \
+ "%s " dbg_fmt, \
+ __func__, ##arg); \
+ } while (0);
+
/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
#define SNA32_CHECK 2147483648UL
(n1 > n2 && (n2 - n1 < SNA32_CHECK)));
}
+inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
+{
+ struct Scsi_Host *shost = conn->session->host;
+ struct iscsi_host *ihost = shost_priv(shost);
+
+ queue_work(ihost->workq, &conn->xmitwork);
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
+
void
iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
{
if (!list_empty(&session->leadconn->xmitqueue) ||
!list_empty(&session->leadconn->mgmtqueue)) {
if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
- scsi_queue_work(session->host,
- &session->leadconn->xmitwork);
+ iscsi_conn_queue_work(session->leadconn);
}
}
}
EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
-void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *task,
- struct iscsi_data *hdr)
+/**
+ * iscsi_prep_data_out_pdu - initialize Data-Out
+ * @task: scsi command task
+ * @r2t: R2T info
+ * @hdr: iscsi data in pdu
+ *
+ * Notes:
+ * Initialize Data-Out within this R2T sequence and finds
+ * proper data_offset within this SCSI command.
+ *
+ * This function is called with connection lock taken.
+ **/
+void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t,
+ struct iscsi_data *hdr)
{
struct iscsi_conn *conn = task->conn;
+ unsigned int left = r2t->data_length - r2t->sent;
+
+ task->hdr_len = sizeof(struct iscsi_data);
memset(hdr, 0, sizeof(struct iscsi_data));
- hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
- hdr->datasn = cpu_to_be32(task->unsol_datasn);
- task->unsol_datasn++;
+ hdr->ttt = r2t->ttt;
+ hdr->datasn = cpu_to_be32(r2t->datasn);
+ r2t->datasn++;
hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
- memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun));
-
- hdr->itt = task->hdr->itt;
- hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
- hdr->offset = cpu_to_be32(task->unsol_offset);
-
- if (task->unsol_count > conn->max_xmit_dlength) {
+ memcpy(hdr->lun, task->lun, sizeof(hdr->lun));
+ hdr->itt = task->hdr_itt;
+ hdr->exp_statsn = r2t->exp_statsn;
+ hdr->offset = cpu_to_be32(r2t->data_offset + r2t->sent);
+ if (left > conn->max_xmit_dlength) {
hton24(hdr->dlength, conn->max_xmit_dlength);
- task->data_count = conn->max_xmit_dlength;
- task->unsol_offset += task->data_count;
+ r2t->data_count = conn->max_xmit_dlength;
hdr->flags = 0;
} else {
- hton24(hdr->dlength, task->unsol_count);
- task->data_count = task->unsol_count;
+ hton24(hdr->dlength, left);
+ r2t->data_count = left;
hdr->flags = ISCSI_FLAG_CMD_FINAL;
}
+ conn->dataout_pdus_cnt++;
}
-EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
+EXPORT_SYMBOL_GPL(iscsi_prep_data_out_pdu);
static int iscsi_add_hdr(struct iscsi_task *task, unsigned len)
{
ecdb_ahdr->reserved = 0;
memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
- debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
- "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
- cmd->cmd_len, rlen, pad_len, ahslength, task->hdr_len);
-
+ ISCSI_DBG_SESSION(task->conn->session,
+ "iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
+ "rlen %d pad_len %d ahs_length %d iscsi_headers_size "
+ "%u\n", cmd->cmd_len, rlen, pad_len, ahslength,
+ task->hdr_len);
return 0;
}
rlen_ahdr->reserved = 0;
rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
- debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
- "rlen_ahdr->ahslength(%d)\n",
- be32_to_cpu(rlen_ahdr->read_length),
- be16_to_cpu(rlen_ahdr->ahslength));
+ ISCSI_DBG_SESSION(task->conn->session,
+ "bidi-in rlen_ahdr->read_length(%d) "
+ "rlen_ahdr->ahslength(%d)\n",
+ be32_to_cpu(rlen_ahdr->read_length),
+ be16_to_cpu(rlen_ahdr->ahslength));
return 0;
}
{
struct iscsi_conn *conn = task->conn;
struct iscsi_session *session = conn->session;
- struct iscsi_cmd *hdr = task->hdr;
struct scsi_cmnd *sc = task->sc;
+ struct iscsi_cmd *hdr;
unsigned hdrlength, cmd_len;
+ itt_t itt;
int rc;
+ rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
+ if (rc)
+ return rc;
+ hdr = (struct iscsi_cmd *) task->hdr;
+ itt = hdr->itt;
+ memset(hdr, 0, sizeof(*hdr));
+
+ if (session->tt->parse_pdu_itt)
+ hdr->itt = task->hdr_itt = itt;
+ else
+ hdr->itt = task->hdr_itt = build_itt(task->itt,
+ task->conn->session->age);
task->hdr_len = 0;
rc = iscsi_add_hdr(task, sizeof(*hdr));
if (rc)
hdr->opcode = ISCSI_OP_SCSI_CMD;
hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
- hdr->itt = build_itt(task->itt, session->age);
- hdr->cmdsn = cpu_to_be32(session->cmdsn);
+ memcpy(task->lun, hdr->lun, sizeof(task->lun));
+ hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
cmd_len = sc->cmd_len;
}
if (sc->sc_data_direction == DMA_TO_DEVICE) {
unsigned out_len = scsi_out(sc)->length;
+ struct iscsi_r2t_info *r2t = &task->unsol_r2t;
+
hdr->data_length = cpu_to_be32(out_len);
hdr->flags |= ISCSI_FLAG_CMD_WRITE;
/*
* without R2T ack right after
* immediate data
*
- * r2t_data_count bytes to be sent via R2T ack's
+ * r2t data_length bytes to be sent via R2T ack's
*
* pad_count bytes to be sent as zero-padding
*/
- task->unsol_count = 0;
- task->unsol_offset = 0;
- task->unsol_datasn = 0;
+ memset(r2t, 0, sizeof(*r2t));
if (session->imm_data_en) {
if (out_len >= session->first_burst)
zero_data(hdr->dlength);
if (!session->initial_r2t_en) {
- task->unsol_count = min(session->first_burst, out_len)
- - task->imm_count;
- task->unsol_offset = task->imm_count;
+ r2t->data_length = min(session->first_burst, out_len) -
+ task->imm_count;
+ r2t->data_offset = task->imm_count;
+ r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
+ r2t->exp_statsn = cpu_to_be32(conn->exp_statsn);
}
- if (!task->unsol_count)
+ if (!task->unsol_r2t.data_length)
/* No unsolicit Data-Out's */
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
} else {
WARN_ON(hdrlength >= 256);
hdr->hlength = hdrlength & 0xFF;
- if (conn->session->tt->init_task &&
- conn->session->tt->init_task(task))
+ if (session->tt->init_task && session->tt->init_task(task))
return -EIO;
task->state = ISCSI_TASK_RUNNING;
list_move_tail(&task->running, &conn->run_list);
conn->scsicmd_pdus_cnt++;
- debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
- "bidi_len %d cmdsn %d win %d]\n", scsi_bidi_cmnd(sc) ?
- "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
- "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
- scsi_bufflen(sc),
- scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
- session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x "
+ "itt 0x%x len %d bidi_len %d cmdsn %d win %d]\n",
+ scsi_bidi_cmnd(sc) ? "bidirectional" :
+ sc->sc_data_direction == DMA_TO_DEVICE ?
+ "write" : "read", conn->id, sc, sc->cmnd[0],
+ task->itt, scsi_bufflen(sc),
+ scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
+ session->cmdsn,
+ session->max_cmdsn - session->exp_cmdsn + 1);
return 0;
}
struct iscsi_session *session = conn->session;
struct scsi_cmnd *sc = task->sc;
+ session->tt->cleanup_task(task);
list_del_init(&task->running);
task->state = ISCSI_TASK_COMPLETED;
task->sc = NULL;
* the cmd in the sequencing
*/
conn->session->queued_cmdsn--;
- else
- conn->session->tt->cleanup_task(conn, task);
sc->result = err;
if (!scsi_bidi_cmnd(sc))
struct iscsi_task *task)
{
struct iscsi_session *session = conn->session;
- struct iscsi_hdr *hdr = (struct iscsi_hdr *)task->hdr;
+ struct iscsi_hdr *hdr = task->hdr;
struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
*/
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (hdr->itt != RESERVED_ITT) {
- hdr->itt = build_itt(task->itt, session->age);
/*
* TODO: We always use immediate, so we never hit this.
* If we start to send tmfs or nops as non-immediate then
}
}
- if (session->tt->init_task)
- session->tt->init_task(task);
+ if (session->tt->init_task && session->tt->init_task(task))
+ return -EIO;
if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
session->state = ISCSI_STATE_LOGGING_OUT;
+ task->state = ISCSI_TASK_RUNNING;
list_move_tail(&task->running, &conn->mgmt_run_list);
- debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
- hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
- task->data_count);
+ ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x "
+ "datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK,
+ hdr->itt, task->data_count);
return 0;
}
{
struct iscsi_session *session = conn->session;
struct iscsi_task *task;
+ itt_t itt;
if (session->state == ISCSI_STATE_TERMINATE)
return NULL;
if (!__kfifo_get(session->cmdpool.queue,
(void*)&task, sizeof(void*)))
return NULL;
-
- if ((hdr->opcode == (ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE)) &&
- hdr->ttt == RESERVED_ITT) {
- conn->ping_task = task;
- conn->last_ping = jiffies;
- }
}
/*
* released in complete pdu for task we expect a response for, and
} else
task->data_count = 0;
+ if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
+ iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
+ "pdu for mgmt task.\n");
+ goto requeue_task;
+ }
+ itt = task->hdr->itt;
+ task->hdr_len = sizeof(struct iscsi_hdr);
memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr));
+
+ if (hdr->itt != RESERVED_ITT) {
+ if (session->tt->parse_pdu_itt)
+ task->hdr->itt = itt;
+ else
+ task->hdr->itt = build_itt(task->itt,
+ task->conn->session->age);
+ }
+
INIT_LIST_HEAD(&task->running);
list_add_tail(&task->running, &conn->mgmtqueue);
if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
- if (iscsi_prep_mgmt_task(conn, task)) {
- __iscsi_put_task(task);
- return NULL;
- }
+ if (iscsi_prep_mgmt_task(conn, task))
+ goto free_task;
if (session->tt->xmit_task(task))
- task = NULL;
+ goto free_task;
} else
- scsi_queue_work(conn->session->host, &conn->xmitwork);
+ iscsi_conn_queue_work(conn);
return task;
+
+free_task:
+ __iscsi_put_task(task);
+ return NULL;
+
+requeue_task:
+ if (task != conn->login_task)
+ __kfifo_put(session->cmdpool.queue, (void*)&task,
+ sizeof(void*));
+ return NULL;
}
int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
memcpy(sc->sense_buffer, data + 2,
min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
- debug_scsi("copied %d bytes of sense\n",
- min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
+ ISCSI_DBG_SESSION(session, "copied %d bytes of sense\n",
+ min_t(uint16_t, senselen,
+ SCSI_SENSE_BUFFERSIZE));
}
if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
}
out:
- debug_scsi("done [sc %lx res %d itt 0x%x]\n",
- (long)sc, sc->result, task->itt);
+ ISCSI_DBG_SESSION(session, "done [sc %p res %d itt 0x%x]\n",
+ sc, sc->result, task->itt);
conn->scsirsp_pdus_cnt++;
__iscsi_put_task(task);
task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
if (!task)
iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
+ else if (!rhdr) {
+ /* only track our nops */
+ conn->ping_task = task;
+ conn->last_ping = jiffies;
+ }
}
static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
{
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 (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
- itt = get_itt(rejected_pdu.itt);
iscsi_conn_printk(KERN_ERR, conn,
- "itt 0x%x had pdu (op 0x%x) rejected "
- "due to DataDigest error.\n", itt,
+ "pdu (op 0x%x) rejected "
+ "due to DataDigest error.\n",
rejected_pdu.opcode);
}
}
static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
{
struct iscsi_session *session = conn->session;
- uint32_t i;
+ int i;
if (itt == RESERVED_ITT)
return NULL;
- i = get_itt(itt);
+ if (session->tt->parse_pdu_itt)
+ session->tt->parse_pdu_itt(conn, itt, &i, NULL);
+ else
+ i = get_itt(itt);
if (i >= session->cmds_max)
return NULL;
else
itt = ~0U;
- debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n",
- opcode, conn->id, itt, datalen);
+ ISCSI_DBG_SESSION(session, "[op 0x%x cid %d itt 0x%x len %d]\n",
+ opcode, conn->id, itt, datalen);
if (itt == ~0U) {
iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
{
struct iscsi_session *session = conn->session;
- uint32_t i;
+ int age = 0, i = 0;
if (itt == RESERVED_ITT)
return 0;
- if (((__force u32)itt & ISCSI_AGE_MASK) !=
- (session->age << ISCSI_AGE_SHIFT)) {
+ if (session->tt->parse_pdu_itt)
+ session->tt->parse_pdu_itt(conn, itt, &i, &age);
+ else {
+ i = get_itt(itt);
+ age = ((__force u32)itt >> ISCSI_AGE_SHIFT) & ISCSI_AGE_MASK;
+ }
+
+ if (age != session->age) {
iscsi_conn_printk(KERN_ERR, conn,
"received itt %x expected session age (%x)\n",
(__force u32)itt, session->age);
return ISCSI_ERR_BAD_ITT;
}
- i = get_itt(itt);
if (i >= session->cmds_max) {
iscsi_conn_printk(KERN_ERR, conn,
"received invalid itt index %u (max cmds "
}
EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask);
-void iscsi_session_failure(struct iscsi_cls_session *cls_session,
+void iscsi_session_failure(struct iscsi_session *session,
enum iscsi_err err)
{
- struct iscsi_session *session = cls_session->dd_data;
struct iscsi_conn *conn;
struct device *dev;
unsigned long flags;
* Check for iSCSI window and take care of CmdSN wrap-around
*/
if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) {
- debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u "
- "CmdSN %u/%u\n", session->exp_cmdsn,
- session->max_cmdsn, session->cmdsn,
- session->queued_cmdsn);
+ ISCSI_DBG_SESSION(session, "iSCSI CmdSN closed. ExpCmdSn "
+ "%u MaxCmdSN %u CmdSN %u/%u\n",
+ session->exp_cmdsn, session->max_cmdsn,
+ session->cmdsn, session->queued_cmdsn);
return -ENOSPC;
}
return 0;
struct iscsi_conn *conn = task->conn;
list_move_tail(&task->running, &conn->requeue);
- scsi_queue_work(conn->session->host, &conn->xmitwork);
+ iscsi_conn_queue_work(conn);
}
EXPORT_SYMBOL_GPL(iscsi_requeue_task);
spin_lock_bh(&conn->session->lock);
if (unlikely(conn->suspend_tx)) {
- debug_scsi("conn %d Tx suspended!\n", conn->id);
+ ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
spin_unlock_bh(&conn->session->lock);
return -ENODATA;
}
fail_command(conn, conn->task, DID_IMM_RETRY << 16);
continue;
}
- if (iscsi_prep_scsi_cmd_pdu(conn->task)) {
- fail_command(conn, conn->task, DID_ABORT << 16);
+ rc = iscsi_prep_scsi_cmd_pdu(conn->task);
+ if (rc) {
+ if (rc == -ENOMEM) {
+ conn->task = NULL;
+ goto again;
+ } else
+ fail_command(conn, conn->task, DID_ABORT << 16);
continue;
}
rc = iscsi_xmit_task(conn);
} while (rc >= 0 || rc == -EAGAIN);
}
+static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
+ struct scsi_cmnd *sc)
+{
+ struct iscsi_task *task;
+
+ if (!__kfifo_get(conn->session->cmdpool.queue,
+ (void *) &task, sizeof(void *)))
+ return NULL;
+
+ sc->SCp.phase = conn->session->age;
+ sc->SCp.ptr = (char *) task;
+
+ atomic_set(&task->refcount, 1);
+ task->state = ISCSI_TASK_PENDING;
+ task->conn = conn;
+ task->sc = sc;
+ INIT_LIST_HEAD(&task->running);
+ return task;
+}
+
enum {
FAILURE_BAD_HOST = 1,
FAILURE_SESSION_FAILED,
goto reject;
}
- if (!__kfifo_get(session->cmdpool.queue, (void*)&task,
- sizeof(void*))) {
+ task = iscsi_alloc_task(conn, sc);
+ if (!task) {
reason = FAILURE_OOM;
goto reject;
}
- sc->SCp.phase = session->age;
- sc->SCp.ptr = (char *)task;
-
- atomic_set(&task->refcount, 1);
- task->state = ISCSI_TASK_PENDING;
- task->conn = conn;
- task->sc = sc;
- INIT_LIST_HEAD(&task->running);
list_add_tail(&task->running, &conn->xmitqueue);
if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
- if (iscsi_prep_scsi_cmd_pdu(task)) {
- sc->result = DID_ABORT << 16;
- sc->scsi_done = NULL;
- iscsi_complete_command(task);
- goto fault;
+ reason = iscsi_prep_scsi_cmd_pdu(task);
+ if (reason) {
+ if (reason == -ENOMEM) {
+ reason = FAILURE_OOM;
+ goto prepd_reject;
+ } else {
+ sc->result = DID_ABORT << 16;
+ goto prepd_fault;
+ }
}
if (session->tt->xmit_task(task)) {
- sc->scsi_done = NULL;
- iscsi_complete_command(task);
reason = FAILURE_SESSION_NOT_READY;
- goto reject;
+ goto prepd_reject;
}
} else
- scsi_queue_work(session->host, &conn->xmitwork);
+ iscsi_conn_queue_work(conn);
session->queued_cmdsn++;
spin_unlock(&session->lock);
spin_lock(host->host_lock);
return 0;
+prepd_reject:
+ sc->scsi_done = NULL;
+ iscsi_complete_command(task);
reject:
spin_unlock(&session->lock);
- debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
+ ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
+ sc->cmnd[0], reason);
spin_lock(host->host_lock);
return SCSI_MLQUEUE_TARGET_BUSY;
+prepd_fault:
+ sc->scsi_done = NULL;
+ iscsi_complete_command(task);
fault:
spin_unlock(&session->lock);
- debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
+ ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
+ sc->cmnd[0], reason);
if (!scsi_bidi_cmnd(sc))
scsi_set_resid(sc, scsi_bufflen(sc));
else {
int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
{
- if (depth > ISCSI_MAX_CMD_PER_LUN)
- depth = ISCSI_MAX_CMD_PER_LUN;
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
return sdev->queue_depth;
}
EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
+int iscsi_target_alloc(struct scsi_target *starget)
+{
+ struct iscsi_cls_session *cls_session = starget_to_session(starget);
+ struct iscsi_session *session = cls_session->dd_data;
+
+ starget->can_queue = session->scsi_cmds_max;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_target_alloc);
+
void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
{
struct iscsi_session *session = cls_session->dd_data;
spin_lock_bh(&session->lock);
if (session->state == ISCSI_STATE_TERMINATE) {
failed:
- debug_scsi("failing target reset: session terminated "
- "[CID %d age %d]\n", conn->id, session->age);
+ iscsi_session_printk(KERN_INFO, session,
+ "failing target reset: Could not log "
+ "back into target [age %d]\n",
+ session->age);
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
return FAILED;
*/
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- debug_scsi("iscsi_eh_target_reset wait for relogin\n");
+ ISCSI_DBG_SESSION(session, "wait for relogin\n");
wait_event_interruptible(conn->ehwait,
session->state == ISCSI_STATE_TERMINATE ||
session->state == ISCSI_STATE_LOGGED_IN ||
spin_lock(&session->lock);
if (conn->tmf_state == TMF_QUEUED) {
conn->tmf_state = TMF_TIMEDOUT;
- debug_scsi("tmf timedout\n");
+ ISCSI_DBG_SESSION(session, "tmf timedout\n");
/* unblock eh_abort() */
wake_up(&conn->ehwait);
}
spin_unlock_bh(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
spin_lock_bh(&session->lock);
- debug_scsi("tmf exec failure\n");
+ ISCSI_DBG_SESSION(session, "tmf exec failure\n");
return -EPERM;
}
conn->tmfcmd_pdus_cnt++;
conn->tmf_timer.function = iscsi_tmf_timedout;
conn->tmf_timer.data = (unsigned long)conn;
add_timer(&conn->tmf_timer);
- debug_scsi("tmf set timeout\n");
+ ISCSI_DBG_SESSION(session, "tmf set timeout\n");
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
{
struct iscsi_task *task, *tmp;
- if (conn->task && (conn->task->sc->device->lun == lun || lun == -1))
- conn->task = NULL;
+ if (conn->task) {
+ if (lun == -1 ||
+ (conn->task->sc && conn->task->sc->device->lun == lun))
+ conn->task = NULL;
+ }
/* flush pending */
list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) {
if (lun == task->sc->device->lun || lun == -1) {
- debug_scsi("failing pending sc %p itt 0x%x\n",
- task->sc, task->itt);
+ ISCSI_DBG_SESSION(conn->session,
+ "failing pending sc %p itt 0x%x\n",
+ task->sc, task->itt);
fail_command(conn, task, error << 16);
}
}
list_for_each_entry_safe(task, tmp, &conn->requeue, running) {
if (lun == task->sc->device->lun || lun == -1) {
- debug_scsi("failing requeued sc %p itt 0x%x\n",
- task->sc, task->itt);
+ ISCSI_DBG_SESSION(conn->session,
+ "failing requeued sc %p itt 0x%x\n",
+ task->sc, task->itt);
fail_command(conn, task, error << 16);
}
}
/* fail all other running */
list_for_each_entry_safe(task, tmp, &conn->run_list, running) {
if (lun == task->sc->device->lun || lun == -1) {
- debug_scsi("failing in progress sc %p itt 0x%x\n",
- task->sc, task->itt);
+ ISCSI_DBG_SESSION(conn->session,
+ "failing in progress sc %p itt 0x%x\n",
+ task->sc, task->itt);
fail_command(conn, task, error << 16);
}
}
void iscsi_suspend_tx(struct iscsi_conn *conn)
{
+ struct Scsi_Host *shost = conn->session->host;
+ struct iscsi_host *ihost = shost_priv(shost);
+
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
- scsi_flush_work(conn->session->host);
+ flush_workqueue(ihost->workq);
}
EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
{
clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
- scsi_queue_work(conn->session->host, &conn->xmitwork);
+ iscsi_conn_queue_work(conn);
}
static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
cls_session = starget_to_session(scsi_target(scmd->device));
session = cls_session->dd_data;
- debug_scsi("scsi cmd %p timedout\n", scmd);
+ ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", scmd);
spin_lock(&session->lock);
if (session->state != ISCSI_STATE_LOGGED_IN) {
rc = BLK_EH_RESET_TIMER;
done:
spin_unlock(&session->lock);
- debug_scsi("return %s\n", rc == BLK_EH_RESET_TIMER ?
- "timer reset" : "nh");
+ ISCSI_DBG_SESSION(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
+ "timer reset" : "nh");
return rc;
}
if (time_before_eq(last_recv + recv_timeout, jiffies)) {
/* send a ping to try to provoke some traffic */
- debug_scsi("Sending nopout as ping on conn %p\n", conn);
+ ISCSI_DBG_CONN(conn, "Sending nopout as ping\n");
iscsi_send_nopout(conn, NULL);
next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
} else
next_timeout = last_recv + recv_timeout;
- debug_scsi("Setting next tmo %lu\n", next_timeout);
+ ISCSI_DBG_CONN(conn, "Setting next tmo %lu\n", next_timeout);
mod_timer(&conn->transport_timer, next_timeout);
done:
spin_unlock(&session->lock);
hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun));
- hdr->rtt = task->hdr->itt;
- hdr->refcmdsn = task->hdr->cmdsn;
+ memcpy(hdr->lun, task->lun, sizeof(hdr->lun));
+ hdr->rtt = task->hdr_itt;
+ hdr->refcmdsn = task->cmdsn;
}
int iscsi_eh_abort(struct scsi_cmnd *sc)
* got the command.
*/
if (!sc->SCp.ptr) {
- debug_scsi("sc never reached iscsi layer or it completed.\n");
+ ISCSI_DBG_SESSION(session, "sc never reached iscsi layer or "
+ "it completed.\n");
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
return SUCCESS;
age = session->age;
task = (struct iscsi_task *)sc->SCp.ptr;
- debug_scsi("aborting [sc %p itt 0x%x]\n", sc, task->itt);
+ ISCSI_DBG_SESSION(session, "aborting [sc %p itt 0x%x]\n",
+ sc, task->itt);
/* task completed before time out */
if (!task->sc) {
- debug_scsi("sc completed while abort in progress\n");
+ ISCSI_DBG_SESSION(session, "sc completed while abort in "
+ "progress\n");
goto success;
}
if (!sc->SCp.ptr) {
conn->tmf_state = TMF_INITIAL;
/* task completed before tmf abort response */
- debug_scsi("sc completed while abort in progress\n");
+ ISCSI_DBG_SESSION(session, "sc completed while abort "
+ "in progress\n");
goto success;
}
/* fall through */
success:
spin_unlock_bh(&session->lock);
success_unlocked:
- debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, task->itt);
+ ISCSI_DBG_SESSION(session, "abort success [sc %p itt 0x%x]\n",
+ sc, task->itt);
mutex_unlock(&session->eh_mutex);
return SUCCESS;
failed:
spin_unlock_bh(&session->lock);
failed_unlocked:
- debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
- task ? task->itt : 0);
+ ISCSI_DBG_SESSION(session, "abort failed [sc %p itt 0x%x]\n", sc,
+ task ? task->itt : 0);
mutex_unlock(&session->eh_mutex);
return FAILED;
}
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
+ ISCSI_DBG_SESSION(session, "LU Reset [sc %p lun %u]\n",
+ sc, sc->device->lun);
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
unlock:
spin_unlock_bh(&session->lock);
done:
- debug_scsi("iscsi_eh_device_reset %s\n",
- rc == SUCCESS ? "SUCCESS" : "FAILED");
+ ISCSI_DBG_SESSION(session, "dev reset result = %s\n",
+ rc == SUCCESS ? "SUCCESS" : "FAILED");
mutex_unlock(&session->eh_mutex);
return rc;
}
num_arrays++;
q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
if (q->pool == NULL)
- goto enomem;
+ return -ENOMEM;
q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
GFP_KERNEL, NULL);
- if (q->queue == ERR_PTR(-ENOMEM))
+ if (IS_ERR(q->queue)) {
+ q->queue = NULL;
goto enomem;
+ }
for (i = 0; i < max; i++) {
q->pool[i] = kzalloc(item_size, GFP_KERNEL);
for (i = 0; i < q->max; i++)
kfree(q->pool[i]);
- if (q->pool)
- kfree(q->pool);
+ kfree(q->pool);
+ kfree(q->queue);
}
EXPORT_SYMBOL_GPL(iscsi_pool_free);
if (!shost->can_queue)
shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
+ if (!shost->cmd_per_lun)
+ shost->cmd_per_lun = ISCSI_DEF_CMD_PER_LUN;
+
+ if (!shost->transportt->eh_timed_out)
+ shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
return scsi_add_host(shost, pdev);
}
EXPORT_SYMBOL_GPL(iscsi_host_add);
* iscsi_host_alloc - allocate a host and driver data
* @sht: scsi host template
* @dd_data_size: driver host data size
- * @qdepth: default device queue depth
+ * @xmit_can_sleep: bool indicating if LLD will queue IO from a work queue
*
* This should be called by partial offload and software iscsi drivers.
* To access the driver specific memory use the iscsi_host_priv() macro.
*/
struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
- int dd_data_size, uint16_t qdepth)
+ int dd_data_size, bool xmit_can_sleep)
{
struct Scsi_Host *shost;
struct iscsi_host *ihost;
shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
if (!shost)
return NULL;
- shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
+ ihost = shost_priv(shost);
- if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
- if (qdepth != 0)
- printk(KERN_ERR "iscsi: invalid queue depth of %d. "
- "Queue depth must be between 1 and %d.\n",
- qdepth, ISCSI_MAX_CMD_PER_LUN);
- qdepth = ISCSI_DEF_CMD_PER_LUN;
+ if (xmit_can_sleep) {
+ snprintf(ihost->workq_name, sizeof(ihost->workq_name),
+ "iscsi_q_%d", shost->host_no);
+ ihost->workq = create_singlethread_workqueue(ihost->workq_name);
+ if (!ihost->workq)
+ goto free_host;
}
- shost->cmd_per_lun = qdepth;
- ihost = shost_priv(shost);
spin_lock_init(&ihost->lock);
ihost->state = ISCSI_HOST_SETUP;
ihost->num_sessions = 0;
init_waitqueue_head(&ihost->session_removal_wq);
return shost;
+
+free_host:
+ scsi_host_put(shost);
+ return NULL;
}
EXPORT_SYMBOL_GPL(iscsi_host_alloc);
static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session)
{
- iscsi_session_failure(cls_session, ISCSI_ERR_INVALID_HOST);
+ iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_INVALID_HOST);
}
/**
flush_signals(current);
scsi_remove_host(shost);
+ if (ihost->workq)
+ destroy_workqueue(ihost->workq);
}
EXPORT_SYMBOL_GPL(iscsi_host_remove);
}
spin_unlock_bh(&session->lock);
- data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL);
+ data = (char *) __get_free_pages(GFP_KERNEL,
+ get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
if (!data)
goto login_task_data_alloc_fail;
conn->login_task->data = conn->data = data;
iscsi_suspend_tx(conn);
spin_lock_bh(&session->lock);
- kfree(conn->data);
+ free_pages((unsigned long) conn->data,
+ get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
kfree(conn->persistent_address);
__kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
sizeof(void*));
/* handle pending */
list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) {
- debug_scsi("flushing pending mgmt task itt 0x%x\n", task->itt);
+ ISCSI_DBG_SESSION(session, "flushing pending mgmt task "
+ "itt 0x%x\n", task->itt);
/* release ref from prep task */
__iscsi_put_task(task);
}
/* handle running */
list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) {
- debug_scsi("flushing running mgmt task itt 0x%x\n", task->itt);
+ ISCSI_DBG_SESSION(session, "flushing running mgmt task "
+ "itt 0x%x\n", task->itt);
/* release ref from prep task */
__iscsi_put_task(task);
}
conn->datadgst_en = 0;
if (session->state == ISCSI_STATE_IN_RECOVERY &&
old_stop_stage != STOP_CONN_RECOVER) {
- debug_scsi("blocking session\n");
+ ISCSI_DBG_SESSION(session, "blocking session\n");
iscsi_block_session(session->cls_session);
}
}