-/**
- * iscsi_data_xmit - xmit any command into the scheduled connection
- * @conn: iscsi connection
- *
- * Notes:
- * The function can return -EAGAIN in which case the caller must
- * re-schedule it again later or recover. '0' return code means
- * successful xmit.
- **/
-static int
-iscsi_data_xmit(struct iscsi_conn *conn)
-{
- if (unlikely(conn->suspend_tx)) {
- debug_tcp("conn %d Tx suspended!\n", conn->id);
- return 0;
- }
-
- /*
- * Transmit in the following order:
- *
- * 1) un-finished xmit (ctask or mtask)
- * 2) immediate control PDUs
- * 3) write data
- * 4) SCSI commands
- * 5) non-immediate control PDUs
- *
- * No need to lock around __kfifo_get as long as
- * there's one producer and one consumer.
- */
-
- BUG_ON(conn->ctask && conn->mtask);
-
- if (conn->ctask) {
- if (iscsi_ctask_xmit(conn, conn->ctask))
- goto again;
- /* done with this in-progress ctask */
- conn->ctask = NULL;
- }
- if (conn->mtask) {
- if (iscsi_mtask_xmit(conn, conn->mtask))
- goto again;
- /* done with this in-progress mtask */
- conn->mtask = NULL;
- }
-
- /* process immediate first */
- if (unlikely(__kfifo_len(conn->immqueue))) {
- struct iscsi_session *session = conn->session;
- while (__kfifo_get(conn->immqueue, (void*)&conn->mtask,
- sizeof(void*))) {
- if (iscsi_mtask_xmit(conn, conn->mtask))
- goto again;
-
- if (conn->mtask->hdr.itt ==
- cpu_to_be32(ISCSI_RESERVED_TAG)) {
- spin_lock_bh(&session->lock);
- __kfifo_put(session->mgmtpool.queue,
- (void*)&conn->mtask, sizeof(void*));
- spin_unlock_bh(&session->lock);
- }
- }
- /* done with this mtask */
- conn->mtask = NULL;
- }
-
- /* process write queue */
- while (__kfifo_get(conn->writequeue, (void*)&conn->ctask,
- sizeof(void*))) {
- if (iscsi_ctask_xmit(conn, conn->ctask))
- goto again;
- }
-
- /* process command queue */
- while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask,
- sizeof(void*))) {
- if (iscsi_ctask_xmit(conn, conn->ctask))
- goto again;
- }
- /* done with this ctask */
- conn->ctask = NULL;
-
- /* process the rest control plane PDUs, if any */
- if (unlikely(__kfifo_len(conn->mgmtqueue))) {
- struct iscsi_session *session = conn->session;
-
- while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
- sizeof(void*))) {
- if (iscsi_mtask_xmit(conn, conn->mtask))
- goto again;
-
- if (conn->mtask->hdr.itt ==
- cpu_to_be32(ISCSI_RESERVED_TAG)) {
- spin_lock_bh(&session->lock);
- __kfifo_put(session->mgmtpool.queue,
- (void*)&conn->mtask,
- sizeof(void*));
- spin_unlock_bh(&session->lock);
- }
- }
- /* done with this mtask */
- conn->mtask = NULL;
- }
-
- return 0;
-
-again:
- if (unlikely(conn->suspend_tx))
- return 0;
-
- return -EAGAIN;
-}
-
-static void
-iscsi_xmitworker(void *data)
-{
- struct iscsi_conn *conn = data;
-
- /*
- * serialize Xmit worker on a per-connection basis.
- */
- mutex_lock(&conn->xmitmutex);
- if (iscsi_data_xmit(conn))
- scsi_queue_work(conn->session->host, &conn->xmitwork);
- mutex_unlock(&conn->xmitmutex);
-}
-
-#define FAILURE_BAD_HOST 1
-#define FAILURE_SESSION_FAILED 2
-#define FAILURE_SESSION_FREED 3
-#define FAILURE_WINDOW_CLOSED 4
-#define FAILURE_SESSION_TERMINATE 5
-
-static int
-iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
-{
- struct Scsi_Host *host;
- int reason = 0;
- struct iscsi_session *session;
- struct iscsi_conn *conn = NULL;
- struct iscsi_cmd_task *ctask = NULL;
-
- sc->scsi_done = done;
- sc->result = 0;
-
- host = sc->device->host;
- session = iscsi_hostdata(host->hostdata);
- BUG_ON(host != session->host);
-
- spin_lock(&session->lock);
-
- if (session->state != ISCSI_STATE_LOGGED_IN) {
- if (session->state == ISCSI_STATE_FAILED) {
- reason = FAILURE_SESSION_FAILED;
- goto reject;
- } else if (session->state == ISCSI_STATE_TERMINATE) {
- reason = FAILURE_SESSION_TERMINATE;
- goto fault;
- }
- reason = FAILURE_SESSION_FREED;
- goto fault;
- }
-
- /*
- * Check for iSCSI window and take care of CmdSN wrap-around
- */
- if ((int)(session->max_cmdsn - session->cmdsn) < 0) {
- reason = FAILURE_WINDOW_CLOSED;
- goto reject;
- }
-
- conn = session->leadconn;
-
- __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
- BUG_ON(ctask->sc);
-
- sc->SCp.phase = session->age;
- sc->SCp.ptr = (char*)ctask;
- iscsi_cmd_init(conn, ctask, sc);
-
- __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*));
- debug_scsi(
- "ctask enq [%s cid %d sc %lx 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,
- session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
- spin_unlock(&session->lock);
-
- scsi_queue_work(host, &conn->xmitwork);
- return 0;
-
-reject:
- spin_unlock(&session->lock);
- debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
- return SCSI_MLQUEUE_HOST_BUSY;
-
-fault:
- spin_unlock(&session->lock);
- printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n",
- sc->cmnd[0], reason);
- sc->sense_buffer[0] = 0x70;
- sc->sense_buffer[2] = NOT_READY;
- sc->sense_buffer[7] = 0x6;
- sc->sense_buffer[12] = 0x08;
- sc->sense_buffer[13] = 0x00;
- sc->result = (DID_NO_CONNECT << 16);
- sc->resid = sc->request_bufflen;
- sc->scsi_done(sc);
- return 0;
-}
-
-static 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;
-}
-
-static int
-iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size)
-{
- int i;
-
- *items = kmalloc(max * sizeof(void*), GFP_KERNEL);
- if (*items == NULL)
- return -ENOMEM;
-
- q->max = max;
- q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL);
- if (q->pool == NULL) {
- kfree(*items);
- return -ENOMEM;
- }
-
- q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
- GFP_KERNEL, NULL);
- if (q->queue == ERR_PTR(-ENOMEM)) {
- kfree(q->pool);
- kfree(*items);
- return -ENOMEM;
- }
-
- for (i = 0; i < max; i++) {
- q->pool[i] = kmalloc(item_size, GFP_KERNEL);
- if (q->pool[i] == NULL) {
- int j;
-
- for (j = 0; j < i; j++)
- kfree(q->pool[j]);
-
- kfifo_free(q->queue);
- kfree(q->pool);
- kfree(*items);
- return -ENOMEM;
- }
- memset(q->pool[i], 0, item_size);
- (*items)[i] = q->pool[i];
- __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
- }
- return 0;
-}
-
-static void
-iscsi_pool_free(struct iscsi_queue *q, void **items)
-{
- int i;
-
- for (i = 0; i < q->max; i++)
- kfree(items[i]);
- kfree(q->pool);
- kfree(items);
-}
-