13e641400SJames Smart // SPDX-License-Identifier: GPL-2.0
23e641400SJames Smart /*
33e641400SJames Smart * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
43e641400SJames Smart * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
53e641400SJames Smart */
63e641400SJames Smart
73e641400SJames Smart #include "efct_driver.h"
83e641400SJames Smart #include "efct_hw.h"
93e641400SJames Smart
103e641400SJames Smart #define enable_tsend_auto_resp(efct) 1
113e641400SJames Smart #define enable_treceive_auto_resp(efct) 0
123e641400SJames Smart
133e641400SJames Smart #define SCSI_IOFMT "[%04x][i:%04x t:%04x h:%04x]"
143e641400SJames Smart
153e641400SJames Smart #define scsi_io_printf(io, fmt, ...) \
163e641400SJames Smart efc_log_debug(io->efct, "[%s]" SCSI_IOFMT fmt, \
173e641400SJames Smart io->node->display_name, io->instance_index,\
183e641400SJames Smart io->init_task_tag, io->tgt_task_tag, io->hw_tag, ##__VA_ARGS__)
193e641400SJames Smart
203e641400SJames Smart #define EFCT_LOG_ENABLE_SCSI_TRACE(efct) \
213e641400SJames Smart (((efct) != NULL) ? (((efct)->logmask & (1U << 2)) != 0) : 0)
223e641400SJames Smart
233e641400SJames Smart #define scsi_io_trace(io, fmt, ...) \
243e641400SJames Smart do { \
253e641400SJames Smart if (EFCT_LOG_ENABLE_SCSI_TRACE(io->efct)) \
263e641400SJames Smart scsi_io_printf(io, fmt, ##__VA_ARGS__); \
273e641400SJames Smart } while (0)
283e641400SJames Smart
293e641400SJames Smart struct efct_io *
efct_scsi_io_alloc(struct efct_node * node)303e641400SJames Smart efct_scsi_io_alloc(struct efct_node *node)
313e641400SJames Smart {
323e641400SJames Smart struct efct *efct;
333e641400SJames Smart struct efct_xport *xport;
343e641400SJames Smart struct efct_io *io;
35*a013c71cSDan Carpenter unsigned long flags;
363e641400SJames Smart
373e641400SJames Smart efct = node->efct;
383e641400SJames Smart
393e641400SJames Smart xport = efct->xport;
403e641400SJames Smart
413e641400SJames Smart io = efct_io_pool_io_alloc(efct->xport->io_pool);
423e641400SJames Smart if (!io) {
433e641400SJames Smart efc_log_err(efct, "IO alloc Failed\n");
443e641400SJames Smart atomic_add_return(1, &xport->io_alloc_failed_count);
453e641400SJames Smart return NULL;
463e641400SJames Smart }
473e641400SJames Smart
483e641400SJames Smart /* initialize refcount */
493e641400SJames Smart kref_init(&io->ref);
503e641400SJames Smart io->release = _efct_scsi_io_free;
513e641400SJames Smart
523e641400SJames Smart /* set generic fields */
533e641400SJames Smart io->efct = efct;
543e641400SJames Smart io->node = node;
553e641400SJames Smart kref_get(&node->ref);
563e641400SJames Smart
573e641400SJames Smart /* set type and name */
583e641400SJames Smart io->io_type = EFCT_IO_TYPE_IO;
593e641400SJames Smart io->display_name = "scsi_io";
603e641400SJames Smart
613e641400SJames Smart io->cmd_ini = false;
623e641400SJames Smart io->cmd_tgt = true;
633e641400SJames Smart
643e641400SJames Smart /* Add to node's active_ios list */
653e641400SJames Smart INIT_LIST_HEAD(&io->list_entry);
66e76b7c5eSDmitry Bogdanov spin_lock_irqsave(&node->active_ios_lock, flags);
673e641400SJames Smart list_add(&io->list_entry, &node->active_ios);
683e641400SJames Smart
693e641400SJames Smart spin_unlock_irqrestore(&node->active_ios_lock, flags);
703e641400SJames Smart
713e641400SJames Smart return io;
723e641400SJames Smart }
733e641400SJames Smart
743e641400SJames Smart void
_efct_scsi_io_free(struct kref * arg)753e641400SJames Smart _efct_scsi_io_free(struct kref *arg)
763e641400SJames Smart {
773e641400SJames Smart struct efct_io *io = container_of(arg, struct efct_io, ref);
783e641400SJames Smart struct efct *efct = io->efct;
793e641400SJames Smart struct efct_node *node = io->node;
803e641400SJames Smart unsigned long flags = 0;
813e641400SJames Smart
823e641400SJames Smart scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
833e641400SJames Smart
843e641400SJames Smart if (io->io_free) {
853e641400SJames Smart efc_log_err(efct, "IO already freed.\n");
863e641400SJames Smart return;
873e641400SJames Smart }
883e641400SJames Smart
893e641400SJames Smart spin_lock_irqsave(&node->active_ios_lock, flags);
903e641400SJames Smart list_del_init(&io->list_entry);
913e641400SJames Smart spin_unlock_irqrestore(&node->active_ios_lock, flags);
923e641400SJames Smart
933e641400SJames Smart kref_put(&node->ref, node->release);
943e641400SJames Smart io->node = NULL;
953e641400SJames Smart efct_io_pool_io_free(efct->xport->io_pool, io);
963e641400SJames Smart }
973e641400SJames Smart
983e641400SJames Smart void
efct_scsi_io_free(struct efct_io * io)993e641400SJames Smart efct_scsi_io_free(struct efct_io *io)
1003e641400SJames Smart {
1013e641400SJames Smart scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
1023e641400SJames Smart WARN_ON(!refcount_read(&io->ref.refcount));
1033e641400SJames Smart kref_put(&io->ref, io->release);
1043e641400SJames Smart }
1053e641400SJames Smart
1063e641400SJames Smart static void
efct_target_io_cb(struct efct_hw_io * hio,u32 length,int status,u32 ext_status,void * app)1073e641400SJames Smart efct_target_io_cb(struct efct_hw_io *hio, u32 length, int status,
1083e641400SJames Smart u32 ext_status, void *app)
1093e641400SJames Smart {
1103e641400SJames Smart u32 flags = 0;
1113e641400SJames Smart struct efct_io *io = app;
1123e641400SJames Smart struct efct *efct;
1133e641400SJames Smart enum efct_scsi_io_status scsi_stat = EFCT_SCSI_STATUS_GOOD;
1143e641400SJames Smart efct_scsi_io_cb_t cb;
1153e641400SJames Smart
1163e641400SJames Smart if (!io || !io->efct) {
1173e641400SJames Smart pr_err("%s: IO can not be NULL\n", __func__);
1183e641400SJames Smart return;
1193e641400SJames Smart }
1203e641400SJames Smart
1213e641400SJames Smart scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status);
1223e641400SJames Smart
1233e641400SJames Smart efct = io->efct;
1243e641400SJames Smart
1253e641400SJames Smart io->transferred += length;
1263e641400SJames Smart
1273e641400SJames Smart if (!io->scsi_tgt_cb) {
1283e641400SJames Smart efct_scsi_check_pending(efct);
1293e641400SJames Smart return;
1303e641400SJames Smart }
1313e641400SJames Smart
1323e641400SJames Smart /* Call target server completion */
1333e641400SJames Smart cb = io->scsi_tgt_cb;
1343e641400SJames Smart
1353e641400SJames Smart /* Clear the callback before invoking the callback */
1363e641400SJames Smart io->scsi_tgt_cb = NULL;
1373e641400SJames Smart
1383e641400SJames Smart /* if status was good, and auto-good-response was set,
1393e641400SJames Smart * then callback target-server with IO_CMPL_RSP_SENT,
1403e641400SJames Smart * otherwise send IO_CMPL
1413e641400SJames Smart */
1423e641400SJames Smart if (status == 0 && io->auto_resp)
1433e641400SJames Smart flags |= EFCT_SCSI_IO_CMPL_RSP_SENT;
1443e641400SJames Smart else
1453e641400SJames Smart flags |= EFCT_SCSI_IO_CMPL;
1463e641400SJames Smart
1473e641400SJames Smart switch (status) {
1483e641400SJames Smart case SLI4_FC_WCQE_STATUS_SUCCESS:
1493e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_GOOD;
1503e641400SJames Smart break;
1513e641400SJames Smart case SLI4_FC_WCQE_STATUS_DI_ERROR:
1523e641400SJames Smart if (ext_status & SLI4_FC_DI_ERROR_GE)
1533e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_DIF_GUARD_ERR;
1543e641400SJames Smart else if (ext_status & SLI4_FC_DI_ERROR_AE)
1553e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_DIF_APP_TAG_ERROR;
1563e641400SJames Smart else if (ext_status & SLI4_FC_DI_ERROR_RE)
1573e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_DIF_REF_TAG_ERROR;
1583e641400SJames Smart else
1593e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_DIF_UNKNOWN_ERROR;
1603e641400SJames Smart break;
1613e641400SJames Smart case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
1623e641400SJames Smart switch (ext_status) {
1633e641400SJames Smart case SLI4_FC_LOCAL_REJECT_INVALID_RELOFFSET:
1643e641400SJames Smart case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED:
1653e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_ABORTED;
1663e641400SJames Smart break;
1673e641400SJames Smart case SLI4_FC_LOCAL_REJECT_INVALID_RPI:
1683e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_NEXUS_LOST;
1693e641400SJames Smart break;
1703e641400SJames Smart case SLI4_FC_LOCAL_REJECT_NO_XRI:
1713e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_NO_IO;
1723e641400SJames Smart break;
1733e641400SJames Smart default:
1743e641400SJames Smart /*we have seen 0x0d(TX_DMA_FAILED err)*/
1753e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_ERROR;
1763e641400SJames Smart break;
1773e641400SJames Smart }
1783e641400SJames Smart break;
1793e641400SJames Smart
1803e641400SJames Smart case SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT:
1813e641400SJames Smart /* target IO timed out */
1823e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_TIMEDOUT_AND_ABORTED;
1833e641400SJames Smart break;
1843e641400SJames Smart
1853e641400SJames Smart case SLI4_FC_WCQE_STATUS_SHUTDOWN:
1863e641400SJames Smart /* Target IO cancelled by HW */
1873e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_SHUTDOWN;
1883e641400SJames Smart break;
1893e641400SJames Smart
1903e641400SJames Smart default:
1913e641400SJames Smart scsi_stat = EFCT_SCSI_STATUS_ERROR;
1923e641400SJames Smart break;
1933e641400SJames Smart }
1943e641400SJames Smart
1953e641400SJames Smart cb(io, scsi_stat, flags, io->scsi_tgt_cb_arg);
1963e641400SJames Smart
1973e641400SJames Smart efct_scsi_check_pending(efct);
1983e641400SJames Smart }
1993e641400SJames Smart
2003e641400SJames Smart static int
efct_scsi_build_sgls(struct efct_hw * hw,struct efct_hw_io * hio,struct efct_scsi_sgl * sgl,u32 sgl_count,enum efct_hw_io_type type)2013e641400SJames Smart efct_scsi_build_sgls(struct efct_hw *hw, struct efct_hw_io *hio,
2023e641400SJames Smart struct efct_scsi_sgl *sgl, u32 sgl_count,
2033e641400SJames Smart enum efct_hw_io_type type)
2043e641400SJames Smart {
2053e641400SJames Smart int rc;
2063e641400SJames Smart u32 i;
2073e641400SJames Smart struct efct *efct = hw->os;
2083e641400SJames Smart
2093e641400SJames Smart /* Initialize HW SGL */
2103e641400SJames Smart rc = efct_hw_io_init_sges(hw, hio, type);
2113e641400SJames Smart if (rc) {
2123e641400SJames Smart efc_log_err(efct, "efct_hw_io_init_sges failed: %d\n", rc);
2133e641400SJames Smart return -EIO;
2143e641400SJames Smart }
2153e641400SJames Smart
2163e641400SJames Smart for (i = 0; i < sgl_count; i++) {
2173e641400SJames Smart /* Add data SGE */
2183e641400SJames Smart rc = efct_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len);
2193e641400SJames Smart if (rc) {
2203e641400SJames Smart efc_log_err(efct, "add sge failed cnt=%d rc=%d\n",
2213e641400SJames Smart sgl_count, rc);
2223e641400SJames Smart return rc;
2233e641400SJames Smart }
2243e641400SJames Smart }
2253e641400SJames Smart
2263e641400SJames Smart return 0;
2273e641400SJames Smart }
2283e641400SJames Smart
efc_log_sgl(struct efct_io * io)2293e641400SJames Smart static void efc_log_sgl(struct efct_io *io)
2303e641400SJames Smart {
2313e641400SJames Smart struct efct_hw_io *hio = io->hio;
2323e641400SJames Smart struct sli4_sge *data = NULL;
2333e641400SJames Smart u32 *dword = NULL;
2343e641400SJames Smart u32 i;
2353e641400SJames Smart u32 n_sge;
2363e641400SJames Smart
2373e641400SJames Smart scsi_io_trace(io, "def_sgl at 0x%x 0x%08x\n",
2383e641400SJames Smart upper_32_bits(hio->def_sgl.phys),
2393e641400SJames Smart lower_32_bits(hio->def_sgl.phys));
2403e641400SJames Smart n_sge = (hio->sgl == &hio->def_sgl) ? hio->n_sge : hio->def_sgl_count;
2413e641400SJames Smart for (i = 0, data = hio->def_sgl.virt; i < n_sge; i++, data++) {
2423e641400SJames Smart dword = (u32 *)data;
2433e641400SJames Smart
2443e641400SJames Smart scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
2453e641400SJames Smart i, dword[0], dword[1], dword[2], dword[3]);
2463e641400SJames Smart
2473e641400SJames Smart if (dword[2] & (1U << 31))
2483e641400SJames Smart break;
2493e641400SJames Smart }
2503e641400SJames Smart }
2513e641400SJames Smart
2523e641400SJames Smart static void
efct_scsi_check_pending_async_cb(struct efct_hw * hw,int status,u8 * mqe,void * arg)2533e641400SJames Smart efct_scsi_check_pending_async_cb(struct efct_hw *hw, int status,
2543e641400SJames Smart u8 *mqe, void *arg)
2553e641400SJames Smart {
2563e641400SJames Smart struct efct_io *io = arg;
2573e641400SJames Smart
2583e641400SJames Smart if (io) {
2593e641400SJames Smart efct_hw_done_t cb = io->hw_cb;
2603e641400SJames Smart
2613e641400SJames Smart if (!io->hw_cb)
2623e641400SJames Smart return;
2633e641400SJames Smart
2643e641400SJames Smart io->hw_cb = NULL;
2653e641400SJames Smart (cb)(io->hio, 0, SLI4_FC_WCQE_STATUS_DISPATCH_ERROR, 0, io);
2663e641400SJames Smart }
2673e641400SJames Smart }
2683e641400SJames Smart
2693e641400SJames Smart static int
efct_scsi_io_dispatch_hw_io(struct efct_io * io,struct efct_hw_io * hio)2703e641400SJames Smart efct_scsi_io_dispatch_hw_io(struct efct_io *io, struct efct_hw_io *hio)
2713e641400SJames Smart {
2723e641400SJames Smart int rc = 0;
2733e641400SJames Smart struct efct *efct = io->efct;
2743e641400SJames Smart
2753e641400SJames Smart /* Got a HW IO;
2763e641400SJames Smart * update ini/tgt_task_tag with HW IO info and dispatch
2773e641400SJames Smart */
2783e641400SJames Smart io->hio = hio;
2793e641400SJames Smart if (io->cmd_tgt)
2803e641400SJames Smart io->tgt_task_tag = hio->indicator;
2813e641400SJames Smart else if (io->cmd_ini)
2823e641400SJames Smart io->init_task_tag = hio->indicator;
2833e641400SJames Smart io->hw_tag = hio->reqtag;
2843e641400SJames Smart
2853e641400SJames Smart hio->eq = io->hw_priv;
2863e641400SJames Smart
2873e641400SJames Smart /* Copy WQ steering */
2883e641400SJames Smart switch (io->wq_steering) {
2893e641400SJames Smart case EFCT_SCSI_WQ_STEERING_CLASS >> EFCT_SCSI_WQ_STEERING_SHIFT:
2903e641400SJames Smart hio->wq_steering = EFCT_HW_WQ_STEERING_CLASS;
2913e641400SJames Smart break;
2923e641400SJames Smart case EFCT_SCSI_WQ_STEERING_REQUEST >> EFCT_SCSI_WQ_STEERING_SHIFT:
2933e641400SJames Smart hio->wq_steering = EFCT_HW_WQ_STEERING_REQUEST;
2943e641400SJames Smart break;
2953e641400SJames Smart case EFCT_SCSI_WQ_STEERING_CPU >> EFCT_SCSI_WQ_STEERING_SHIFT:
2963e641400SJames Smart hio->wq_steering = EFCT_HW_WQ_STEERING_CPU;
2973e641400SJames Smart break;
2983e641400SJames Smart }
2993e641400SJames Smart
3003e641400SJames Smart switch (io->io_type) {
3013e641400SJames Smart case EFCT_IO_TYPE_IO:
3023e641400SJames Smart rc = efct_scsi_build_sgls(&efct->hw, io->hio,
3033e641400SJames Smart io->sgl, io->sgl_count, io->hio_type);
3043e641400SJames Smart if (rc)
3053e641400SJames Smart break;
3063e641400SJames Smart
3073e641400SJames Smart if (EFCT_LOG_ENABLE_SCSI_TRACE(efct))
3083e641400SJames Smart efc_log_sgl(io);
3093e641400SJames Smart
3103e641400SJames Smart if (io->app_id)
3113e641400SJames Smart io->iparam.fcp_tgt.app_id = io->app_id;
3123e641400SJames Smart
3133e641400SJames Smart io->iparam.fcp_tgt.vpi = io->node->vpi;
3143e641400SJames Smart io->iparam.fcp_tgt.rpi = io->node->rpi;
3153e641400SJames Smart io->iparam.fcp_tgt.s_id = io->node->port_fc_id;
3163e641400SJames Smart io->iparam.fcp_tgt.d_id = io->node->node_fc_id;
3173e641400SJames Smart io->iparam.fcp_tgt.xmit_len = io->wire_len;
3183e641400SJames Smart
3193e641400SJames Smart rc = efct_hw_io_send(&io->efct->hw, io->hio_type, io->hio,
3203e641400SJames Smart &io->iparam, io->hw_cb, io);
3213e641400SJames Smart break;
3223e641400SJames Smart default:
3233e641400SJames Smart scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
3243e641400SJames Smart rc = -EIO;
3253e641400SJames Smart break;
3263e641400SJames Smart }
3273e641400SJames Smart return rc;
3283e641400SJames Smart }
3293e641400SJames Smart
3303e641400SJames Smart static int
efct_scsi_io_dispatch_no_hw_io(struct efct_io * io)3313e641400SJames Smart efct_scsi_io_dispatch_no_hw_io(struct efct_io *io)
3323e641400SJames Smart {
3333e641400SJames Smart int rc;
3343e641400SJames Smart
3353e641400SJames Smart switch (io->io_type) {
3363e641400SJames Smart case EFCT_IO_TYPE_ABORT: {
3373e641400SJames Smart struct efct_hw_io *hio_to_abort = NULL;
3383e641400SJames Smart
3393e641400SJames Smart hio_to_abort = io->io_to_abort->hio;
3403e641400SJames Smart
3413e641400SJames Smart if (!hio_to_abort) {
3423e641400SJames Smart /*
3433e641400SJames Smart * If "IO to abort" does not have an
3443e641400SJames Smart * associated HW IO, immediately make callback with
3453e641400SJames Smart * success. The command must have been sent to
3463e641400SJames Smart * the backend, but the data phase has not yet
3473e641400SJames Smart * started, so we don't have a HW IO.
3483e641400SJames Smart *
3493e641400SJames Smart * Note: since the backend shims should be
3503e641400SJames Smart * taking a reference on io_to_abort, it should not
3513e641400SJames Smart * be possible to have been completed and freed by
3523e641400SJames Smart * the backend before the abort got here.
3533e641400SJames Smart */
3543e641400SJames Smart scsi_io_printf(io, "IO: not active\n");
3553e641400SJames Smart ((efct_hw_done_t)io->hw_cb)(io->hio, 0,
3563e641400SJames Smart SLI4_FC_WCQE_STATUS_SUCCESS, 0, io);
3573e641400SJames Smart rc = 0;
3583e641400SJames Smart break;
3593e641400SJames Smart }
3603e641400SJames Smart
3613e641400SJames Smart /* HW IO is valid, abort it */
3623e641400SJames Smart scsi_io_printf(io, "aborting\n");
3633e641400SJames Smart rc = efct_hw_io_abort(&io->efct->hw, hio_to_abort,
3643e641400SJames Smart io->send_abts, io->hw_cb, io);
3653e641400SJames Smart if (rc) {
3663e641400SJames Smart int status = SLI4_FC_WCQE_STATUS_SUCCESS;
3673e641400SJames Smart efct_hw_done_t cb = io->hw_cb;
3683e641400SJames Smart
3693e641400SJames Smart if (rc != -ENOENT && rc != -EINPROGRESS) {
3703e641400SJames Smart status = -1;
3713e641400SJames Smart scsi_io_printf(io, "Failed to abort IO rc=%d\n",
3723e641400SJames Smart rc);
3733e641400SJames Smart }
3743e641400SJames Smart cb(io->hio, 0, status, 0, io);
3753e641400SJames Smart rc = 0;
3763e641400SJames Smart }
3773e641400SJames Smart
3783e641400SJames Smart break;
3793e641400SJames Smart }
3803e641400SJames Smart default:
3813e641400SJames Smart scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
3823e641400SJames Smart rc = -EIO;
3833e641400SJames Smart break;
3843e641400SJames Smart }
3853e641400SJames Smart return rc;
3863e641400SJames Smart }
3873e641400SJames Smart
3883e641400SJames Smart static struct efct_io *
efct_scsi_dispatch_pending(struct efct * efct)3893e641400SJames Smart efct_scsi_dispatch_pending(struct efct *efct)
3903e641400SJames Smart {
3913e641400SJames Smart struct efct_xport *xport = efct->xport;
3923e641400SJames Smart struct efct_io *io = NULL;
3933e641400SJames Smart struct efct_hw_io *hio;
3943e641400SJames Smart unsigned long flags = 0;
3953e641400SJames Smart int status;
3963e641400SJames Smart
3973e641400SJames Smart spin_lock_irqsave(&xport->io_pending_lock, flags);
3983e641400SJames Smart
3993e641400SJames Smart if (!list_empty(&xport->io_pending_list)) {
4003e641400SJames Smart io = list_first_entry(&xport->io_pending_list, struct efct_io,
4013e641400SJames Smart io_pending_link);
4023e641400SJames Smart list_del_init(&io->io_pending_link);
4033e641400SJames Smart }
4043e641400SJames Smart
4053e641400SJames Smart if (!io) {
4063e641400SJames Smart spin_unlock_irqrestore(&xport->io_pending_lock, flags);
4073e641400SJames Smart return NULL;
4083e641400SJames Smart }
4093e641400SJames Smart
4103e641400SJames Smart if (io->io_type == EFCT_IO_TYPE_ABORT) {
4113e641400SJames Smart hio = NULL;
4123e641400SJames Smart } else {
4133e641400SJames Smart hio = efct_hw_io_alloc(&efct->hw);
4143e641400SJames Smart if (!hio) {
4153e641400SJames Smart /*
4163e641400SJames Smart * No HW IO available.Put IO back on
4173e641400SJames Smart * the front of pending list
4183e641400SJames Smart */
4193e641400SJames Smart list_add(&xport->io_pending_list, &io->io_pending_link);
4203e641400SJames Smart io = NULL;
4213e641400SJames Smart } else {
4223e641400SJames Smart hio->eq = io->hw_priv;
4233e641400SJames Smart }
4243e641400SJames Smart }
4253e641400SJames Smart
4263e641400SJames Smart /* Must drop the lock before dispatching the IO */
4273e641400SJames Smart spin_unlock_irqrestore(&xport->io_pending_lock, flags);
4283e641400SJames Smart
4293e641400SJames Smart if (!io)
4303e641400SJames Smart return NULL;
4313e641400SJames Smart
4323e641400SJames Smart /*
4333e641400SJames Smart * We pulled an IO off the pending list,
4343e641400SJames Smart * and either got an HW IO or don't need one
4353e641400SJames Smart */
4363e641400SJames Smart atomic_sub_return(1, &xport->io_pending_count);
4373e641400SJames Smart if (!hio)
4383e641400SJames Smart status = efct_scsi_io_dispatch_no_hw_io(io);
4393e641400SJames Smart else
4403e641400SJames Smart status = efct_scsi_io_dispatch_hw_io(io, hio);
4413e641400SJames Smart if (status) {
4423e641400SJames Smart /*
4433e641400SJames Smart * Invoke the HW callback, but do so in the
4443e641400SJames Smart * separate execution context,provided by the
4453e641400SJames Smart * NOP mailbox completion processing context
4463e641400SJames Smart * by using efct_hw_async_call()
4473e641400SJames Smart */
4483e641400SJames Smart if (efct_hw_async_call(&efct->hw,
4493e641400SJames Smart efct_scsi_check_pending_async_cb, io)) {
4503e641400SJames Smart efc_log_debug(efct, "call hw async failed\n");
4513e641400SJames Smart }
4523e641400SJames Smart }
4533e641400SJames Smart
4543e641400SJames Smart return io;
4553e641400SJames Smart }
4563e641400SJames Smart
4573e641400SJames Smart void
efct_scsi_check_pending(struct efct * efct)4583e641400SJames Smart efct_scsi_check_pending(struct efct *efct)
4593e641400SJames Smart {
4603e641400SJames Smart struct efct_xport *xport = efct->xport;
4613e641400SJames Smart struct efct_io *io = NULL;
4623e641400SJames Smart int count = 0;
4633e641400SJames Smart unsigned long flags = 0;
4643e641400SJames Smart int dispatch = 0;
4653e641400SJames Smart
4663e641400SJames Smart /* Guard against recursion */
4673e641400SJames Smart if (atomic_add_return(1, &xport->io_pending_recursing)) {
4683e641400SJames Smart /* This function is already running. Decrement and return. */
4693e641400SJames Smart atomic_sub_return(1, &xport->io_pending_recursing);
4703e641400SJames Smart return;
4713e641400SJames Smart }
4723e641400SJames Smart
4733e641400SJames Smart while (efct_scsi_dispatch_pending(efct))
4743e641400SJames Smart count++;
4753e641400SJames Smart
4763e641400SJames Smart if (count) {
4773e641400SJames Smart atomic_sub_return(1, &xport->io_pending_recursing);
4783e641400SJames Smart return;
4793e641400SJames Smart }
4803e641400SJames Smart
4813e641400SJames Smart /*
4823e641400SJames Smart * If nothing was removed from the list,
4833e641400SJames Smart * we might be in a case where we need to abort an
4843e641400SJames Smart * active IO and the abort is on the pending list.
4853e641400SJames Smart * Look for an abort we can dispatch.
4863e641400SJames Smart */
4873e641400SJames Smart
4883e641400SJames Smart spin_lock_irqsave(&xport->io_pending_lock, flags);
4893e641400SJames Smart
4903e641400SJames Smart list_for_each_entry(io, &xport->io_pending_list, io_pending_link) {
4913e641400SJames Smart if (io->io_type == EFCT_IO_TYPE_ABORT && io->io_to_abort->hio) {
4923e641400SJames Smart /* This IO has a HW IO, so it is
4933e641400SJames Smart * active. Dispatch the abort.
4943e641400SJames Smart */
4953e641400SJames Smart dispatch = 1;
4963e641400SJames Smart list_del_init(&io->io_pending_link);
4973e641400SJames Smart atomic_sub_return(1, &xport->io_pending_count);
4983e641400SJames Smart break;
4993e641400SJames Smart }
5003e641400SJames Smart }
5013e641400SJames Smart
5023e641400SJames Smart spin_unlock_irqrestore(&xport->io_pending_lock, flags);
5033e641400SJames Smart
5043e641400SJames Smart if (dispatch) {
5053e641400SJames Smart if (efct_scsi_io_dispatch_no_hw_io(io)) {
5063e641400SJames Smart if (efct_hw_async_call(&efct->hw,
5073e641400SJames Smart efct_scsi_check_pending_async_cb, io)) {
5083e641400SJames Smart efc_log_debug(efct, "hw async failed\n");
5093e641400SJames Smart }
5103e641400SJames Smart }
5113e641400SJames Smart }
5123e641400SJames Smart
5133e641400SJames Smart atomic_sub_return(1, &xport->io_pending_recursing);
5143e641400SJames Smart }
5153e641400SJames Smart
5163e641400SJames Smart int
efct_scsi_io_dispatch(struct efct_io * io,void * cb)5173e641400SJames Smart efct_scsi_io_dispatch(struct efct_io *io, void *cb)
5183e641400SJames Smart {
5193e641400SJames Smart struct efct_hw_io *hio;
5203e641400SJames Smart struct efct *efct = io->efct;
5213e641400SJames Smart struct efct_xport *xport = efct->xport;
5223e641400SJames Smart unsigned long flags = 0;
5233e641400SJames Smart
5243e641400SJames Smart io->hw_cb = cb;
5253e641400SJames Smart
5263e641400SJames Smart /*
5273e641400SJames Smart * if this IO already has a HW IO, then this is either
5283e641400SJames Smart * not the first phase of the IO. Send it to the HW.
5293e641400SJames Smart */
5303e641400SJames Smart if (io->hio)
5313e641400SJames Smart return efct_scsi_io_dispatch_hw_io(io, io->hio);
5323e641400SJames Smart
5333e641400SJames Smart /*
5343e641400SJames Smart * We don't already have a HW IO associated with the IO. First check
5353e641400SJames Smart * the pending list. If not empty, add IO to the tail and process the
5363e641400SJames Smart * pending list.
5373e641400SJames Smart */
5383e641400SJames Smart spin_lock_irqsave(&xport->io_pending_lock, flags);
5393e641400SJames Smart if (!list_empty(&xport->io_pending_list)) {
5403e641400SJames Smart /*
5413e641400SJames Smart * If this is a low latency request,
5423e641400SJames Smart * the put at the front of the IO pending
5433e641400SJames Smart * queue, otherwise put it at the end of the queue.
5443e641400SJames Smart */
5453e641400SJames Smart if (io->low_latency) {
5463e641400SJames Smart INIT_LIST_HEAD(&io->io_pending_link);
5473e641400SJames Smart list_add(&xport->io_pending_list, &io->io_pending_link);
5483e641400SJames Smart } else {
5493e641400SJames Smart INIT_LIST_HEAD(&io->io_pending_link);
5503e641400SJames Smart list_add_tail(&io->io_pending_link,
5513e641400SJames Smart &xport->io_pending_list);
5523e641400SJames Smart }
5533e641400SJames Smart spin_unlock_irqrestore(&xport->io_pending_lock, flags);
5543e641400SJames Smart atomic_add_return(1, &xport->io_pending_count);
5553e641400SJames Smart atomic_add_return(1, &xport->io_total_pending);
5563e641400SJames Smart
5573e641400SJames Smart /* process pending list */
5583e641400SJames Smart efct_scsi_check_pending(efct);
5593e641400SJames Smart return 0;
5603e641400SJames Smart }
5613e641400SJames Smart spin_unlock_irqrestore(&xport->io_pending_lock, flags);
5623e641400SJames Smart
5633e641400SJames Smart /*
5643e641400SJames Smart * We don't have a HW IO associated with the IO and there's nothing
5653e641400SJames Smart * on the pending list. Attempt to allocate a HW IO and dispatch it.
5663e641400SJames Smart */
5673e641400SJames Smart hio = efct_hw_io_alloc(&io->efct->hw);
5683e641400SJames Smart if (!hio) {
5693e641400SJames Smart /* Couldn't get a HW IO. Save this IO on the pending list */
5703e641400SJames Smart spin_lock_irqsave(&xport->io_pending_lock, flags);
5713e641400SJames Smart INIT_LIST_HEAD(&io->io_pending_link);
5723e641400SJames Smart list_add_tail(&io->io_pending_link, &xport->io_pending_list);
5733e641400SJames Smart spin_unlock_irqrestore(&xport->io_pending_lock, flags);
5743e641400SJames Smart
5753e641400SJames Smart atomic_add_return(1, &xport->io_total_pending);
5763e641400SJames Smart atomic_add_return(1, &xport->io_pending_count);
5773e641400SJames Smart return 0;
5783e641400SJames Smart }
5793e641400SJames Smart
5803e641400SJames Smart /* We successfully allocated a HW IO; dispatch to HW */
5813e641400SJames Smart return efct_scsi_io_dispatch_hw_io(io, hio);
5823e641400SJames Smart }
5833e641400SJames Smart
5843e641400SJames Smart int
efct_scsi_io_dispatch_abort(struct efct_io * io,void * cb)5853e641400SJames Smart efct_scsi_io_dispatch_abort(struct efct_io *io, void *cb)
5863e641400SJames Smart {
5873e641400SJames Smart struct efct *efct = io->efct;
5883e641400SJames Smart struct efct_xport *xport = efct->xport;
5893e641400SJames Smart unsigned long flags = 0;
5903e641400SJames Smart
5913e641400SJames Smart io->hw_cb = cb;
5923e641400SJames Smart
5933e641400SJames Smart /*
5943e641400SJames Smart * For aborts, we don't need a HW IO, but we still want
5953e641400SJames Smart * to pass through the pending list to preserve ordering.
5963e641400SJames Smart * Thus, if the pending list is not empty, add this abort
5973e641400SJames Smart * to the pending list and process the pending list.
5983e641400SJames Smart */
5993e641400SJames Smart spin_lock_irqsave(&xport->io_pending_lock, flags);
6003e641400SJames Smart if (!list_empty(&xport->io_pending_list)) {
6013e641400SJames Smart INIT_LIST_HEAD(&io->io_pending_link);
6023e641400SJames Smart list_add_tail(&io->io_pending_link, &xport->io_pending_list);
6033e641400SJames Smart spin_unlock_irqrestore(&xport->io_pending_lock, flags);
6043e641400SJames Smart atomic_add_return(1, &xport->io_pending_count);
6053e641400SJames Smart atomic_add_return(1, &xport->io_total_pending);
6063e641400SJames Smart
6073e641400SJames Smart /* process pending list */
6083e641400SJames Smart efct_scsi_check_pending(efct);
6093e641400SJames Smart return 0;
6103e641400SJames Smart }
6113e641400SJames Smart spin_unlock_irqrestore(&xport->io_pending_lock, flags);
6123e641400SJames Smart
6133e641400SJames Smart /* nothing on pending list, dispatch abort */
6143e641400SJames Smart return efct_scsi_io_dispatch_no_hw_io(io);
6153e641400SJames Smart }
6163e641400SJames Smart
6173e641400SJames Smart static inline int
efct_scsi_xfer_data(struct efct_io * io,u32 flags,struct efct_scsi_sgl * sgl,u32 sgl_count,u64 xwire_len,enum efct_hw_io_type type,int enable_ar,efct_scsi_io_cb_t cb,void * arg)6183e641400SJames Smart efct_scsi_xfer_data(struct efct_io *io, u32 flags,
6193e641400SJames Smart struct efct_scsi_sgl *sgl, u32 sgl_count, u64 xwire_len,
6203e641400SJames Smart enum efct_hw_io_type type, int enable_ar,
6213e641400SJames Smart efct_scsi_io_cb_t cb, void *arg)
6223e641400SJames Smart {
6233e641400SJames Smart struct efct *efct;
6243e641400SJames Smart size_t residual = 0;
6253e641400SJames Smart
6263e641400SJames Smart io->sgl_count = sgl_count;
6273e641400SJames Smart
6283e641400SJames Smart efct = io->efct;
6293e641400SJames Smart
6303e641400SJames Smart scsi_io_trace(io, "%s wire_len %llu\n",
6313e641400SJames Smart (type == EFCT_HW_IO_TARGET_READ) ? "send" : "recv",
6323e641400SJames Smart xwire_len);
6333e641400SJames Smart
6343e641400SJames Smart io->hio_type = type;
6353e641400SJames Smart
6363e641400SJames Smart io->scsi_tgt_cb = cb;
6373e641400SJames Smart io->scsi_tgt_cb_arg = arg;
6383e641400SJames Smart
6393e641400SJames Smart residual = io->exp_xfer_len - io->transferred;
6403e641400SJames Smart io->wire_len = (xwire_len < residual) ? xwire_len : residual;
6413e641400SJames Smart residual = (xwire_len - io->wire_len);
6423e641400SJames Smart
6433e641400SJames Smart memset(&io->iparam, 0, sizeof(io->iparam));
6443e641400SJames Smart io->iparam.fcp_tgt.ox_id = io->init_task_tag;
6453e641400SJames Smart io->iparam.fcp_tgt.offset = io->transferred;
6463e641400SJames Smart io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
6473e641400SJames Smart io->iparam.fcp_tgt.timeout = io->timeout;
6483e641400SJames Smart
6493e641400SJames Smart /* if this is the last data phase and there is no residual, enable
6503e641400SJames Smart * auto-good-response
6513e641400SJames Smart */
6523e641400SJames Smart if (enable_ar && (flags & EFCT_SCSI_LAST_DATAPHASE) && residual == 0 &&
6533e641400SJames Smart ((io->transferred + io->wire_len) == io->exp_xfer_len) &&
6543e641400SJames Smart (!(flags & EFCT_SCSI_NO_AUTO_RESPONSE))) {
6553e641400SJames Smart io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
6563e641400SJames Smart io->auto_resp = true;
6573e641400SJames Smart } else {
6583e641400SJames Smart io->auto_resp = false;
6593e641400SJames Smart }
6603e641400SJames Smart
6613e641400SJames Smart /* save this transfer length */
6623e641400SJames Smart io->xfer_req = io->wire_len;
6633e641400SJames Smart
6643e641400SJames Smart /* Adjust the transferred count to account for overrun
6653e641400SJames Smart * when the residual is calculated in efct_scsi_send_resp
6663e641400SJames Smart */
6673e641400SJames Smart io->transferred += residual;
6683e641400SJames Smart
6693e641400SJames Smart /* Adjust the SGL size if there is overrun */
6703e641400SJames Smart
6713e641400SJames Smart if (residual) {
6723e641400SJames Smart struct efct_scsi_sgl *sgl_ptr = &io->sgl[sgl_count - 1];
6733e641400SJames Smart
6743e641400SJames Smart while (residual) {
6753e641400SJames Smart size_t len = sgl_ptr->len;
6763e641400SJames Smart
6773e641400SJames Smart if (len > residual) {
6783e641400SJames Smart sgl_ptr->len = len - residual;
6793e641400SJames Smart residual = 0;
6803e641400SJames Smart } else {
6813e641400SJames Smart sgl_ptr->len = 0;
6823e641400SJames Smart residual -= len;
6833e641400SJames Smart io->sgl_count--;
6843e641400SJames Smart }
6853e641400SJames Smart sgl_ptr--;
6863e641400SJames Smart }
6873e641400SJames Smart }
6883e641400SJames Smart
6893e641400SJames Smart /* Set latency and WQ steering */
6903e641400SJames Smart io->low_latency = (flags & EFCT_SCSI_LOW_LATENCY) != 0;
6913e641400SJames Smart io->wq_steering = (flags & EFCT_SCSI_WQ_STEERING_MASK) >>
6923e641400SJames Smart EFCT_SCSI_WQ_STEERING_SHIFT;
6933e641400SJames Smart io->wq_class = (flags & EFCT_SCSI_WQ_CLASS_MASK) >>
6943e641400SJames Smart EFCT_SCSI_WQ_CLASS_SHIFT;
6953e641400SJames Smart
6963e641400SJames Smart if (efct->xport) {
6973e641400SJames Smart struct efct_xport *xport = efct->xport;
6983e641400SJames Smart
6993e641400SJames Smart if (type == EFCT_HW_IO_TARGET_READ) {
7003e641400SJames Smart xport->fcp_stats.input_requests++;
7013e641400SJames Smart xport->fcp_stats.input_bytes += xwire_len;
7023e641400SJames Smart } else if (type == EFCT_HW_IO_TARGET_WRITE) {
7033e641400SJames Smart xport->fcp_stats.output_requests++;
7043e641400SJames Smart xport->fcp_stats.output_bytes += xwire_len;
7053e641400SJames Smart }
7063e641400SJames Smart }
7073e641400SJames Smart return efct_scsi_io_dispatch(io, efct_target_io_cb);
7083e641400SJames Smart }
7093e641400SJames Smart
7103e641400SJames Smart int
efct_scsi_send_rd_data(struct efct_io * io,u32 flags,struct efct_scsi_sgl * sgl,u32 sgl_count,u64 len,efct_scsi_io_cb_t cb,void * arg)7113e641400SJames Smart efct_scsi_send_rd_data(struct efct_io *io, u32 flags,
7123e641400SJames Smart struct efct_scsi_sgl *sgl, u32 sgl_count, u64 len,
7133e641400SJames Smart efct_scsi_io_cb_t cb, void *arg)
7143e641400SJames Smart {
7153e641400SJames Smart return efct_scsi_xfer_data(io, flags, sgl, sgl_count,
7163e641400SJames Smart len, EFCT_HW_IO_TARGET_READ,
7173e641400SJames Smart enable_tsend_auto_resp(io->efct), cb, arg);
7183e641400SJames Smart }
7193e641400SJames Smart
7203e641400SJames Smart int
efct_scsi_recv_wr_data(struct efct_io * io,u32 flags,struct efct_scsi_sgl * sgl,u32 sgl_count,u64 len,efct_scsi_io_cb_t cb,void * arg)7213e641400SJames Smart efct_scsi_recv_wr_data(struct efct_io *io, u32 flags,
7223e641400SJames Smart struct efct_scsi_sgl *sgl, u32 sgl_count, u64 len,
7233e641400SJames Smart efct_scsi_io_cb_t cb, void *arg)
7243e641400SJames Smart {
7253e641400SJames Smart return efct_scsi_xfer_data(io, flags, sgl, sgl_count, len,
7263e641400SJames Smart EFCT_HW_IO_TARGET_WRITE,
7273e641400SJames Smart enable_treceive_auto_resp(io->efct), cb, arg);
7283e641400SJames Smart }
7293e641400SJames Smart
7303e641400SJames Smart int
efct_scsi_send_resp(struct efct_io * io,u32 flags,struct efct_scsi_cmd_resp * rsp,efct_scsi_io_cb_t cb,void * arg)7313e641400SJames Smart efct_scsi_send_resp(struct efct_io *io, u32 flags,
7323e641400SJames Smart struct efct_scsi_cmd_resp *rsp,
7333e641400SJames Smart efct_scsi_io_cb_t cb, void *arg)
7343e641400SJames Smart {
7353e641400SJames Smart struct efct *efct;
7363e641400SJames Smart int residual;
7373e641400SJames Smart /* Always try auto resp */
7383e641400SJames Smart bool auto_resp = true;
7393e641400SJames Smart u8 scsi_status = 0;
7403e641400SJames Smart u16 scsi_status_qualifier = 0;
7413e641400SJames Smart u8 *sense_data = NULL;
7423e641400SJames Smart u32 sense_data_length = 0;
7433e641400SJames Smart
7443e641400SJames Smart efct = io->efct;
7453e641400SJames Smart
7463e641400SJames Smart if (rsp) {
7473e641400SJames Smart scsi_status = rsp->scsi_status;
7483e641400SJames Smart scsi_status_qualifier = rsp->scsi_status_qualifier;
7493e641400SJames Smart sense_data = rsp->sense_data;
7503e641400SJames Smart sense_data_length = rsp->sense_data_length;
7513e641400SJames Smart residual = rsp->residual;
7523e641400SJames Smart } else {
7533e641400SJames Smart residual = io->exp_xfer_len - io->transferred;
7543e641400SJames Smart }
7553e641400SJames Smart
7563e641400SJames Smart io->wire_len = 0;
7573e641400SJames Smart io->hio_type = EFCT_HW_IO_TARGET_RSP;
7583e641400SJames Smart
7593e641400SJames Smart io->scsi_tgt_cb = cb;
7603e641400SJames Smart io->scsi_tgt_cb_arg = arg;
7613e641400SJames Smart
7623e641400SJames Smart memset(&io->iparam, 0, sizeof(io->iparam));
7633e641400SJames Smart io->iparam.fcp_tgt.ox_id = io->init_task_tag;
7643e641400SJames Smart io->iparam.fcp_tgt.offset = 0;
7653e641400SJames Smart io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
7663e641400SJames Smart io->iparam.fcp_tgt.timeout = io->timeout;
7673e641400SJames Smart
7683e641400SJames Smart /* Set low latency queueing request */
7693e641400SJames Smart io->low_latency = (flags & EFCT_SCSI_LOW_LATENCY) != 0;
7703e641400SJames Smart io->wq_steering = (flags & EFCT_SCSI_WQ_STEERING_MASK) >>
7713e641400SJames Smart EFCT_SCSI_WQ_STEERING_SHIFT;
7723e641400SJames Smart io->wq_class = (flags & EFCT_SCSI_WQ_CLASS_MASK) >>
7733e641400SJames Smart EFCT_SCSI_WQ_CLASS_SHIFT;
7743e641400SJames Smart
7753e641400SJames Smart if (scsi_status != 0 || residual || sense_data_length) {
7763e641400SJames Smart struct fcp_resp_with_ext *fcprsp = io->rspbuf.virt;
7773e641400SJames Smart u8 *sns_data;
7783e641400SJames Smart
7793e641400SJames Smart if (!fcprsp) {
7803e641400SJames Smart efc_log_err(efct, "NULL response buffer\n");
7813e641400SJames Smart return -EIO;
7823e641400SJames Smart }
7833e641400SJames Smart
7843e641400SJames Smart sns_data = (u8 *)io->rspbuf.virt + sizeof(*fcprsp);
7853e641400SJames Smart
7863e641400SJames Smart auto_resp = false;
7873e641400SJames Smart
7883e641400SJames Smart memset(fcprsp, 0, sizeof(*fcprsp));
7893e641400SJames Smart
7903e641400SJames Smart io->wire_len += sizeof(*fcprsp);
7913e641400SJames Smart
7923e641400SJames Smart fcprsp->resp.fr_status = scsi_status;
7933e641400SJames Smart fcprsp->resp.fr_retry_delay =
7943e641400SJames Smart cpu_to_be16(scsi_status_qualifier);
7953e641400SJames Smart
7963e641400SJames Smart /* set residual status if necessary */
7973e641400SJames Smart if (residual != 0) {
7983e641400SJames Smart /* FCP: if data transferred is less than the
7993e641400SJames Smart * amount expected, then this is an underflow.
8003e641400SJames Smart * If data transferred would have been greater
8013e641400SJames Smart * than the amount expected this is an overflow
8023e641400SJames Smart */
8033e641400SJames Smart if (residual > 0) {
8043e641400SJames Smart fcprsp->resp.fr_flags |= FCP_RESID_UNDER;
8053e641400SJames Smart fcprsp->ext.fr_resid = cpu_to_be32(residual);
8063e641400SJames Smart } else {
8073e641400SJames Smart fcprsp->resp.fr_flags |= FCP_RESID_OVER;
8083e641400SJames Smart fcprsp->ext.fr_resid = cpu_to_be32(-residual);
8093e641400SJames Smart }
8103e641400SJames Smart }
8113e641400SJames Smart
8123e641400SJames Smart if (EFCT_SCSI_SNS_BUF_VALID(sense_data) && sense_data_length) {
8133e641400SJames Smart if (sense_data_length > SCSI_SENSE_BUFFERSIZE) {
8143e641400SJames Smart efc_log_err(efct, "Sense exceeds max size.\n");
8153e641400SJames Smart return -EIO;
8163e641400SJames Smart }
8173e641400SJames Smart
8183e641400SJames Smart fcprsp->resp.fr_flags |= FCP_SNS_LEN_VAL;
8193e641400SJames Smart memcpy(sns_data, sense_data, sense_data_length);
8203e641400SJames Smart fcprsp->ext.fr_sns_len = cpu_to_be32(sense_data_length);
8213e641400SJames Smart io->wire_len += sense_data_length;
8223e641400SJames Smart }
8233e641400SJames Smart
8243e641400SJames Smart io->sgl[0].addr = io->rspbuf.phys;
8253e641400SJames Smart io->sgl[0].dif_addr = 0;
8263e641400SJames Smart io->sgl[0].len = io->wire_len;
8273e641400SJames Smart io->sgl_count = 1;
8283e641400SJames Smart }
8293e641400SJames Smart
8303e641400SJames Smart if (auto_resp)
8313e641400SJames Smart io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
8323e641400SJames Smart
8333e641400SJames Smart return efct_scsi_io_dispatch(io, efct_target_io_cb);
8343e641400SJames Smart }
8353e641400SJames Smart
8363e641400SJames Smart static int
efct_target_bls_resp_cb(struct efct_hw_io * hio,u32 length,int status,u32 ext_status,void * app)8373e641400SJames Smart efct_target_bls_resp_cb(struct efct_hw_io *hio, u32 length, int status,
8383e641400SJames Smart u32 ext_status, void *app)
8393e641400SJames Smart {
8403e641400SJames Smart struct efct_io *io = app;
8413e641400SJames Smart struct efct *efct;
8423e641400SJames Smart enum efct_scsi_io_status bls_status;
8433e641400SJames Smart
8443e641400SJames Smart efct = io->efct;
8453e641400SJames Smart
8463e641400SJames Smart /* BLS isn't really a "SCSI" concept, but use SCSI status */
8473e641400SJames Smart if (status) {
8483e641400SJames Smart io_error_log(io, "s=%#x x=%#x\n", status, ext_status);
8493e641400SJames Smart bls_status = EFCT_SCSI_STATUS_ERROR;
8503e641400SJames Smart } else {
8513e641400SJames Smart bls_status = EFCT_SCSI_STATUS_GOOD;
8523e641400SJames Smart }
8533e641400SJames Smart
8543e641400SJames Smart if (io->bls_cb) {
8553e641400SJames Smart efct_scsi_io_cb_t bls_cb = io->bls_cb;
8563e641400SJames Smart void *bls_cb_arg = io->bls_cb_arg;
8573e641400SJames Smart
8583e641400SJames Smart io->bls_cb = NULL;
8593e641400SJames Smart io->bls_cb_arg = NULL;
8603e641400SJames Smart
8613e641400SJames Smart /* invoke callback */
8623e641400SJames Smart bls_cb(io, bls_status, 0, bls_cb_arg);
8633e641400SJames Smart }
8643e641400SJames Smart
8653e641400SJames Smart efct_scsi_check_pending(efct);
8663e641400SJames Smart return 0;
8673e641400SJames Smart }
8683e641400SJames Smart
8693e641400SJames Smart static int
efct_target_send_bls_resp(struct efct_io * io,efct_scsi_io_cb_t cb,void * arg)8703e641400SJames Smart efct_target_send_bls_resp(struct efct_io *io,
8713e641400SJames Smart efct_scsi_io_cb_t cb, void *arg)
8723e641400SJames Smart {
8733e641400SJames Smart struct efct_node *node = io->node;
8743e641400SJames Smart struct sli_bls_params *bls = &io->iparam.bls;
8753e641400SJames Smart struct efct *efct = node->efct;
8763e641400SJames Smart struct fc_ba_acc *acc;
8773e641400SJames Smart int rc;
8783e641400SJames Smart
8793e641400SJames Smart /* fill out IO structure with everything needed to send BA_ACC */
8803e641400SJames Smart memset(&io->iparam, 0, sizeof(io->iparam));
8813e641400SJames Smart bls->ox_id = io->init_task_tag;
8823e641400SJames Smart bls->rx_id = io->abort_rx_id;
8833e641400SJames Smart bls->vpi = io->node->vpi;
8843e641400SJames Smart bls->rpi = io->node->rpi;
8853e641400SJames Smart bls->s_id = U32_MAX;
8863e641400SJames Smart bls->d_id = io->node->node_fc_id;
8873e641400SJames Smart bls->rpi_registered = true;
8883e641400SJames Smart
8893e641400SJames Smart acc = (void *)bls->payload;
8903e641400SJames Smart acc->ba_ox_id = cpu_to_be16(bls->ox_id);
8913e641400SJames Smart acc->ba_rx_id = cpu_to_be16(bls->rx_id);
8923e641400SJames Smart acc->ba_high_seq_cnt = cpu_to_be16(U16_MAX);
8933e641400SJames Smart
8943e641400SJames Smart /* generic io fields have already been populated */
8953e641400SJames Smart
8963e641400SJames Smart /* set type and BLS-specific fields */
8973e641400SJames Smart io->io_type = EFCT_IO_TYPE_BLS_RESP;
8983e641400SJames Smart io->display_name = "bls_rsp";
8993e641400SJames Smart io->hio_type = EFCT_HW_BLS_ACC;
9003e641400SJames Smart io->bls_cb = cb;
9013e641400SJames Smart io->bls_cb_arg = arg;
9023e641400SJames Smart
9033e641400SJames Smart /* dispatch IO */
9043e641400SJames Smart rc = efct_hw_bls_send(efct, FC_RCTL_BA_ACC, bls,
9053e641400SJames Smart efct_target_bls_resp_cb, io);
9063e641400SJames Smart return rc;
9073e641400SJames Smart }
9083e641400SJames Smart
efct_bls_send_rjt_cb(struct efct_hw_io * hio,u32 length,int status,u32 ext_status,void * app)9093e641400SJames Smart static int efct_bls_send_rjt_cb(struct efct_hw_io *hio, u32 length, int status,
9103e641400SJames Smart u32 ext_status, void *app)
9113e641400SJames Smart {
9123e641400SJames Smart struct efct_io *io = app;
9133e641400SJames Smart
9143e641400SJames Smart efct_scsi_io_free(io);
9153e641400SJames Smart return 0;
9163e641400SJames Smart }
9173e641400SJames Smart
9183e641400SJames Smart struct efct_io *
efct_bls_send_rjt(struct efct_io * io,struct fc_frame_header * hdr)9193e641400SJames Smart efct_bls_send_rjt(struct efct_io *io, struct fc_frame_header *hdr)
9203e641400SJames Smart {
9213e641400SJames Smart struct efct_node *node = io->node;
9223e641400SJames Smart struct sli_bls_params *bls = &io->iparam.bls;
9233e641400SJames Smart struct efct *efct = node->efct;
9243e641400SJames Smart struct fc_ba_rjt *acc;
9253e641400SJames Smart int rc;
9263e641400SJames Smart
9273e641400SJames Smart /* fill out BLS Response-specific fields */
9283e641400SJames Smart io->io_type = EFCT_IO_TYPE_BLS_RESP;
9293e641400SJames Smart io->display_name = "ba_rjt";
9303e641400SJames Smart io->hio_type = EFCT_HW_BLS_RJT;
9313e641400SJames Smart io->init_task_tag = be16_to_cpu(hdr->fh_ox_id);
9323e641400SJames Smart
9333e641400SJames Smart /* fill out iparam fields */
9343e641400SJames Smart memset(&io->iparam, 0, sizeof(io->iparam));
9353e641400SJames Smart bls->ox_id = be16_to_cpu(hdr->fh_ox_id);
9363e641400SJames Smart bls->rx_id = be16_to_cpu(hdr->fh_rx_id);
9373e641400SJames Smart bls->vpi = io->node->vpi;
9383e641400SJames Smart bls->rpi = io->node->rpi;
9393e641400SJames Smart bls->s_id = U32_MAX;
9403e641400SJames Smart bls->d_id = io->node->node_fc_id;
9413e641400SJames Smart bls->rpi_registered = true;
9423e641400SJames Smart
9433e641400SJames Smart acc = (void *)bls->payload;
9443e641400SJames Smart acc->br_reason = ELS_RJT_UNAB;
9453e641400SJames Smart acc->br_explan = ELS_EXPL_NONE;
9463e641400SJames Smart
9473e641400SJames Smart rc = efct_hw_bls_send(efct, FC_RCTL_BA_RJT, bls, efct_bls_send_rjt_cb,
9483e641400SJames Smart io);
9493e641400SJames Smart if (rc) {
9503e641400SJames Smart efc_log_err(efct, "efct_scsi_io_dispatch() failed: %d\n", rc);
9513e641400SJames Smart efct_scsi_io_free(io);
9523e641400SJames Smart io = NULL;
9533e641400SJames Smart }
9543e641400SJames Smart return io;
9553e641400SJames Smart }
9563e641400SJames Smart
9573e641400SJames Smart int
efct_scsi_send_tmf_resp(struct efct_io * io,enum efct_scsi_tmf_resp rspcode,u8 addl_rsp_info[3],efct_scsi_io_cb_t cb,void * arg)9583e641400SJames Smart efct_scsi_send_tmf_resp(struct efct_io *io,
9593e641400SJames Smart enum efct_scsi_tmf_resp rspcode,
9603e641400SJames Smart u8 addl_rsp_info[3],
9613e641400SJames Smart efct_scsi_io_cb_t cb, void *arg)
9623e641400SJames Smart {
9633e641400SJames Smart int rc;
9643e641400SJames Smart struct {
9653e641400SJames Smart struct fcp_resp_with_ext rsp_ext;
9663e641400SJames Smart struct fcp_resp_rsp_info info;
9673e641400SJames Smart } *fcprsp;
9683e641400SJames Smart u8 fcp_rspcode;
9693e641400SJames Smart
9703e641400SJames Smart io->wire_len = 0;
9713e641400SJames Smart
9723e641400SJames Smart switch (rspcode) {
9733e641400SJames Smart case EFCT_SCSI_TMF_FUNCTION_COMPLETE:
9743e641400SJames Smart fcp_rspcode = FCP_TMF_CMPL;
9753e641400SJames Smart break;
9763e641400SJames Smart case EFCT_SCSI_TMF_FUNCTION_SUCCEEDED:
9773e641400SJames Smart case EFCT_SCSI_TMF_FUNCTION_IO_NOT_FOUND:
9783e641400SJames Smart fcp_rspcode = FCP_TMF_CMPL;
9793e641400SJames Smart break;
9803e641400SJames Smart case EFCT_SCSI_TMF_FUNCTION_REJECTED:
9813e641400SJames Smart fcp_rspcode = FCP_TMF_REJECTED;
9823e641400SJames Smart break;
9833e641400SJames Smart case EFCT_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER:
9843e641400SJames Smart fcp_rspcode = FCP_TMF_INVALID_LUN;
9853e641400SJames Smart break;
9863e641400SJames Smart case EFCT_SCSI_TMF_SERVICE_DELIVERY:
9873e641400SJames Smart fcp_rspcode = FCP_TMF_FAILED;
9883e641400SJames Smart break;
9893e641400SJames Smart default:
9903e641400SJames Smart fcp_rspcode = FCP_TMF_REJECTED;
9913e641400SJames Smart break;
9923e641400SJames Smart }
9933e641400SJames Smart
9943e641400SJames Smart io->hio_type = EFCT_HW_IO_TARGET_RSP;
9953e641400SJames Smart
9963e641400SJames Smart io->scsi_tgt_cb = cb;
9973e641400SJames Smart io->scsi_tgt_cb_arg = arg;
9983e641400SJames Smart
9993e641400SJames Smart if (io->tmf_cmd == EFCT_SCSI_TMF_ABORT_TASK) {
10003e641400SJames Smart rc = efct_target_send_bls_resp(io, cb, arg);
10013e641400SJames Smart return rc;
10023e641400SJames Smart }
10033e641400SJames Smart
10043e641400SJames Smart /* populate the FCP TMF response */
10053e641400SJames Smart fcprsp = io->rspbuf.virt;
10063e641400SJames Smart memset(fcprsp, 0, sizeof(*fcprsp));
10073e641400SJames Smart
10083e641400SJames Smart fcprsp->rsp_ext.resp.fr_flags |= FCP_SNS_LEN_VAL;
10093e641400SJames Smart
10103e641400SJames Smart if (addl_rsp_info) {
10113e641400SJames Smart memcpy(fcprsp->info._fr_resvd, addl_rsp_info,
10123e641400SJames Smart sizeof(fcprsp->info._fr_resvd));
10133e641400SJames Smart }
10143e641400SJames Smart fcprsp->info.rsp_code = fcp_rspcode;
10153e641400SJames Smart
10163e641400SJames Smart io->wire_len = sizeof(*fcprsp);
10173e641400SJames Smart
10183e641400SJames Smart fcprsp->rsp_ext.ext.fr_rsp_len =
10193e641400SJames Smart cpu_to_be32(sizeof(struct fcp_resp_rsp_info));
10203e641400SJames Smart
10213e641400SJames Smart io->sgl[0].addr = io->rspbuf.phys;
10223e641400SJames Smart io->sgl[0].dif_addr = 0;
10233e641400SJames Smart io->sgl[0].len = io->wire_len;
10243e641400SJames Smart io->sgl_count = 1;
10253e641400SJames Smart
10263e641400SJames Smart memset(&io->iparam, 0, sizeof(io->iparam));
10273e641400SJames Smart io->iparam.fcp_tgt.ox_id = io->init_task_tag;
10283e641400SJames Smart io->iparam.fcp_tgt.offset = 0;
10293e641400SJames Smart io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
10303e641400SJames Smart io->iparam.fcp_tgt.timeout = io->timeout;
10313e641400SJames Smart
10323e641400SJames Smart rc = efct_scsi_io_dispatch(io, efct_target_io_cb);
10333e641400SJames Smart
10343e641400SJames Smart return rc;
10353e641400SJames Smart }
10363e641400SJames Smart
10373e641400SJames Smart static int
efct_target_abort_cb(struct efct_hw_io * hio,u32 length,int status,u32 ext_status,void * app)10383e641400SJames Smart efct_target_abort_cb(struct efct_hw_io *hio, u32 length, int status,
10393e641400SJames Smart u32 ext_status, void *app)
10403e641400SJames Smart {
10413e641400SJames Smart struct efct_io *io = app;
10423e641400SJames Smart struct efct *efct;
10433e641400SJames Smart enum efct_scsi_io_status scsi_status;
10443e641400SJames Smart efct_scsi_io_cb_t abort_cb;
10453e641400SJames Smart void *abort_cb_arg;
10463e641400SJames Smart
10473e641400SJames Smart efct = io->efct;
10483e641400SJames Smart
10493e641400SJames Smart if (!io->abort_cb)
10503e641400SJames Smart goto done;
10513e641400SJames Smart
10523e641400SJames Smart abort_cb = io->abort_cb;
10533e641400SJames Smart abort_cb_arg = io->abort_cb_arg;
10543e641400SJames Smart
10553e641400SJames Smart io->abort_cb = NULL;
10563e641400SJames Smart io->abort_cb_arg = NULL;
10573e641400SJames Smart
10583e641400SJames Smart switch (status) {
10593e641400SJames Smart case SLI4_FC_WCQE_STATUS_SUCCESS:
10603e641400SJames Smart scsi_status = EFCT_SCSI_STATUS_GOOD;
10613e641400SJames Smart break;
10623e641400SJames Smart case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
10633e641400SJames Smart switch (ext_status) {
10643e641400SJames Smart case SLI4_FC_LOCAL_REJECT_NO_XRI:
10653e641400SJames Smart scsi_status = EFCT_SCSI_STATUS_NO_IO;
10663e641400SJames Smart break;
10673e641400SJames Smart case SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS:
10683e641400SJames Smart scsi_status = EFCT_SCSI_STATUS_ABORT_IN_PROGRESS;
10693e641400SJames Smart break;
10703e641400SJames Smart default:
10713e641400SJames Smart /*we have seen 0x15 (abort in progress)*/
10723e641400SJames Smart scsi_status = EFCT_SCSI_STATUS_ERROR;
10733e641400SJames Smart break;
10743e641400SJames Smart }
10753e641400SJames Smart break;
10763e641400SJames Smart case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
10773e641400SJames Smart scsi_status = EFCT_SCSI_STATUS_CHECK_RESPONSE;
10783e641400SJames Smart break;
10793e641400SJames Smart default:
10803e641400SJames Smart scsi_status = EFCT_SCSI_STATUS_ERROR;
10813e641400SJames Smart break;
10823e641400SJames Smart }
10833e641400SJames Smart /* invoke callback */
10843e641400SJames Smart abort_cb(io->io_to_abort, scsi_status, 0, abort_cb_arg);
10853e641400SJames Smart
10863e641400SJames Smart done:
10873e641400SJames Smart /* done with IO to abort,efct_ref_get(): efct_scsi_tgt_abort_io() */
10883e641400SJames Smart kref_put(&io->io_to_abort->ref, io->io_to_abort->release);
10893e641400SJames Smart
10903e641400SJames Smart efct_io_pool_io_free(efct->xport->io_pool, io);
10913e641400SJames Smart
10923e641400SJames Smart efct_scsi_check_pending(efct);
10933e641400SJames Smart return 0;
10943e641400SJames Smart }
10953e641400SJames Smart
10963e641400SJames Smart int
efct_scsi_tgt_abort_io(struct efct_io * io,efct_scsi_io_cb_t cb,void * arg)10973e641400SJames Smart efct_scsi_tgt_abort_io(struct efct_io *io, efct_scsi_io_cb_t cb, void *arg)
10983e641400SJames Smart {
10993e641400SJames Smart struct efct *efct;
11003e641400SJames Smart struct efct_xport *xport;
11013e641400SJames Smart int rc;
11023e641400SJames Smart struct efct_io *abort_io = NULL;
11033e641400SJames Smart
11043e641400SJames Smart efct = io->efct;
11053e641400SJames Smart xport = efct->xport;
11063e641400SJames Smart
11073e641400SJames Smart /* take a reference on IO being aborted */
11083e641400SJames Smart if (kref_get_unless_zero(&io->ref) == 0) {
11093e641400SJames Smart /* command no longer active */
11103e641400SJames Smart scsi_io_printf(io, "command no longer active\n");
11113e641400SJames Smart return -EIO;
11123e641400SJames Smart }
11133e641400SJames Smart
11143e641400SJames Smart /*
11153e641400SJames Smart * allocate a new IO to send the abort request. Use efct_io_alloc()
11163e641400SJames Smart * directly, as we need an IO object that will not fail allocation
11173e641400SJames Smart * due to allocations being disabled (in efct_scsi_io_alloc())
11183e641400SJames Smart */
11193e641400SJames Smart abort_io = efct_io_pool_io_alloc(efct->xport->io_pool);
11203e641400SJames Smart if (!abort_io) {
11213e641400SJames Smart atomic_add_return(1, &xport->io_alloc_failed_count);
11223e641400SJames Smart kref_put(&io->ref, io->release);
11233e641400SJames Smart return -EIO;
11243e641400SJames Smart }
11253e641400SJames Smart
11263e641400SJames Smart /* Save the target server callback and argument */
11273e641400SJames Smart /* set generic fields */
11283e641400SJames Smart abort_io->cmd_tgt = true;
11293e641400SJames Smart abort_io->node = io->node;
11303e641400SJames Smart
11313e641400SJames Smart /* set type and abort-specific fields */
11323e641400SJames Smart abort_io->io_type = EFCT_IO_TYPE_ABORT;
11333e641400SJames Smart abort_io->display_name = "tgt_abort";
11343e641400SJames Smart abort_io->io_to_abort = io;
11353e641400SJames Smart abort_io->send_abts = false;
11363e641400SJames Smart abort_io->abort_cb = cb;
11373e641400SJames Smart abort_io->abort_cb_arg = arg;
11383e641400SJames Smart
11393e641400SJames Smart /* now dispatch IO */
11403e641400SJames Smart rc = efct_scsi_io_dispatch_abort(abort_io, efct_target_abort_cb);
11413e641400SJames Smart if (rc)
11423e641400SJames Smart kref_put(&io->ref, io->release);
11433e641400SJames Smart return rc;
11443e641400SJames Smart }
11453e641400SJames Smart
11463e641400SJames Smart void
efct_scsi_io_complete(struct efct_io * io)11473e641400SJames Smart efct_scsi_io_complete(struct efct_io *io)
11483e641400SJames Smart {
11493e641400SJames Smart if (io->io_free) {
11503e641400SJames Smart efc_log_debug(io->efct, "completion for non-busy io tag 0x%x\n",
11513e641400SJames Smart io->tag);
11523e641400SJames Smart return;
11533e641400SJames Smart }
11543e641400SJames Smart
11553e641400SJames Smart scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
11563e641400SJames Smart kref_put(&io->ref, io->release);
11573e641400SJames Smart }
1158