linux/drivers/target/tcm_fc/tfc_cmd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2010 Cisco Systems, Inc.
   4 */
   5
   6/* XXX TBD some includes may be extraneous */
   7
   8#include <linux/module.h>
   9#include <linux/moduleparam.h>
  10#include <linux/utsname.h>
  11#include <linux/init.h>
  12#include <linux/slab.h>
  13#include <linux/kthread.h>
  14#include <linux/types.h>
  15#include <linux/string.h>
  16#include <linux/configfs.h>
  17#include <linux/ctype.h>
  18#include <linux/hash.h>
  19#include <asm/unaligned.h>
  20#include <scsi/scsi_tcq.h>
  21#include <scsi/libfc.h>
  22#include <scsi/fc_encode.h>
  23
  24#include <target/target_core_base.h>
  25#include <target/target_core_fabric.h>
  26
  27#include "tcm_fc.h"
  28
  29/*
  30 * Dump cmd state for debugging.
  31 */
  32static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
  33{
  34        struct fc_exch *ep;
  35        struct fc_seq *sp;
  36        struct se_cmd *se_cmd;
  37        struct scatterlist *sg;
  38        int count;
  39
  40        se_cmd = &cmd->se_cmd;
  41        pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n",
  42                caller, cmd, cmd->sess, cmd->seq, se_cmd);
  43
  44        pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n",
  45                caller, cmd, se_cmd->t_data_nents,
  46               se_cmd->data_length, se_cmd->se_cmd_flags);
  47
  48        for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, count)
  49                pr_debug("%s: cmd %p sg %p page %p "
  50                        "len 0x%x off 0x%x\n",
  51                        caller, cmd, sg,
  52                        sg_page(sg), sg->length, sg->offset);
  53
  54        sp = cmd->seq;
  55        if (sp) {
  56                ep = fc_seq_exch(sp);
  57                pr_debug("%s: cmd %p sid %x did %x "
  58                        "ox_id %x rx_id %x seq_id %x e_stat %x\n",
  59                        caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid,
  60                        sp->id, ep->esb_stat);
  61        }
  62}
  63
  64void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
  65{
  66        if (unlikely(ft_debug_logging))
  67                _ft_dump_cmd(cmd, caller);
  68}
  69
  70static void ft_free_cmd(struct ft_cmd *cmd)
  71{
  72        struct fc_frame *fp;
  73        struct ft_sess *sess;
  74
  75        if (!cmd)
  76                return;
  77        sess = cmd->sess;
  78        fp = cmd->req_frame;
  79        if (fr_seq(fp))
  80                fc_seq_release(fr_seq(fp));
  81        fc_frame_free(fp);
  82        target_free_tag(sess->se_sess, &cmd->se_cmd);
  83        ft_sess_put(sess);      /* undo get from lookup at recv */
  84}
  85
  86void ft_release_cmd(struct se_cmd *se_cmd)
  87{
  88        struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
  89
  90        ft_free_cmd(cmd);
  91}
  92
  93int ft_check_stop_free(struct se_cmd *se_cmd)
  94{
  95        return transport_generic_free_cmd(se_cmd, 0);
  96}
  97
  98/*
  99 * Send response.
 100 */
 101int ft_queue_status(struct se_cmd *se_cmd)
 102{
 103        struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
 104        struct fc_frame *fp;
 105        struct fcp_resp_with_ext *fcp;
 106        struct fc_lport *lport;
 107        struct fc_exch *ep;
 108        size_t len;
 109        int rc;
 110
 111        if (cmd->aborted)
 112                return 0;
 113        ft_dump_cmd(cmd, __func__);
 114        ep = fc_seq_exch(cmd->seq);
 115        lport = ep->lp;
 116        len = sizeof(*fcp) + se_cmd->scsi_sense_length;
 117        fp = fc_frame_alloc(lport, len);
 118        if (!fp) {
 119                se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
 120                return -ENOMEM;
 121        }
 122
 123        fcp = fc_frame_payload_get(fp, len);
 124        memset(fcp, 0, len);
 125        fcp->resp.fr_status = se_cmd->scsi_status;
 126
 127        len = se_cmd->scsi_sense_length;
 128        if (len) {
 129                fcp->resp.fr_flags |= FCP_SNS_LEN_VAL;
 130                fcp->ext.fr_sns_len = htonl(len);
 131                memcpy((fcp + 1), se_cmd->sense_buffer, len);
 132        }
 133
 134        /*
 135         * Test underflow and overflow with one mask.  Usually both are off.
 136         * Bidirectional commands are not handled yet.
 137         */
 138        if (se_cmd->se_cmd_flags & (SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT)) {
 139                if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
 140                        fcp->resp.fr_flags |= FCP_RESID_OVER;
 141                else
 142                        fcp->resp.fr_flags |= FCP_RESID_UNDER;
 143                fcp->ext.fr_resid = cpu_to_be32(se_cmd->residual_count);
 144        }
 145
 146        /*
 147         * Send response.
 148         */
 149        cmd->seq = fc_seq_start_next(cmd->seq);
 150        fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP,
 151                       FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0);
 152
 153        rc = fc_seq_send(lport, cmd->seq, fp);
 154        if (rc) {
 155                pr_info_ratelimited("%s: Failed to send response frame %p, "
 156                                    "xid <0x%x>\n", __func__, fp, ep->xid);
 157                /*
 158                 * Generate a TASK_SET_FULL status to notify the initiator
 159                 * to reduce it's queue_depth after the se_cmd response has
 160                 * been re-queued by target-core.
 161                 */
 162                se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
 163                return -ENOMEM;
 164        }
 165        fc_exch_done(cmd->seq);
 166        /*
 167         * Drop the extra ACK_KREF reference taken by target_submit_cmd()
 168         * ahead of ft_check_stop_free() -> transport_generic_free_cmd()
 169         * final se_cmd->cmd_kref put.
 170         */
 171        target_put_sess_cmd(&cmd->se_cmd);
 172        return 0;
 173}
 174
 175/*
 176 * Send TX_RDY (transfer ready).
 177 */
 178int ft_write_pending(struct se_cmd *se_cmd)
 179{
 180        struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
 181        struct fc_frame *fp;
 182        struct fcp_txrdy *txrdy;
 183        struct fc_lport *lport;
 184        struct fc_exch *ep;
 185        struct fc_frame_header *fh;
 186        u32 f_ctl;
 187
 188        ft_dump_cmd(cmd, __func__);
 189
 190        if (cmd->aborted)
 191                return 0;
 192        ep = fc_seq_exch(cmd->seq);
 193        lport = ep->lp;
 194        fp = fc_frame_alloc(lport, sizeof(*txrdy));
 195        if (!fp)
 196                return -ENOMEM; /* Signal QUEUE_FULL */
 197
 198        txrdy = fc_frame_payload_get(fp, sizeof(*txrdy));
 199        memset(txrdy, 0, sizeof(*txrdy));
 200        txrdy->ft_burst_len = htonl(se_cmd->data_length);
 201
 202        cmd->seq = fc_seq_start_next(cmd->seq);
 203        fc_fill_fc_hdr(fp, FC_RCTL_DD_DATA_DESC, ep->did, ep->sid, FC_TYPE_FCP,
 204                       FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 205
 206        fh = fc_frame_header_get(fp);
 207        f_ctl = ntoh24(fh->fh_f_ctl);
 208
 209        /* Only if it is 'Exchange Responder' */
 210        if (f_ctl & FC_FC_EX_CTX) {
 211                /* Target is 'exchange responder' and sending XFER_READY
 212                 * to 'exchange initiator (initiator)'
 213                 */
 214                if ((ep->xid <= lport->lro_xid) &&
 215                    (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
 216                        if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
 217                            lport->tt.ddp_target(lport, ep->xid,
 218                                                 se_cmd->t_data_sg,
 219                                                 se_cmd->t_data_nents))
 220                                cmd->was_ddp_setup = 1;
 221                }
 222        }
 223        fc_seq_send(lport, cmd->seq, fp);
 224        return 0;
 225}
 226
 227int ft_get_cmd_state(struct se_cmd *se_cmd)
 228{
 229        return 0;
 230}
 231
 232/*
 233 * FC sequence response handler for follow-on sequences (data) and aborts.
 234 */
 235static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
 236{
 237        struct ft_cmd *cmd = arg;
 238        struct fc_frame_header *fh;
 239
 240        if (IS_ERR(fp)) {
 241                /* XXX need to find cmd if queued */
 242                cmd->seq = NULL;
 243                cmd->aborted = true;
 244                return;
 245        }
 246
 247        fh = fc_frame_header_get(fp);
 248
 249        switch (fh->fh_r_ctl) {
 250        case FC_RCTL_DD_SOL_DATA:       /* write data */
 251                ft_recv_write_data(cmd, fp);
 252                break;
 253        case FC_RCTL_DD_UNSOL_CTL:      /* command */
 254        case FC_RCTL_DD_SOL_CTL:        /* transfer ready */
 255        case FC_RCTL_DD_DATA_DESC:      /* transfer ready */
 256        default:
 257                pr_debug("%s: unhandled frame r_ctl %x\n",
 258                       __func__, fh->fh_r_ctl);
 259                ft_invl_hw_context(cmd);
 260                fc_frame_free(fp);
 261                transport_generic_free_cmd(&cmd->se_cmd, 0);
 262                break;
 263        }
 264}
 265
 266/*
 267 * Send a FCP response including SCSI status and optional FCP rsp_code.
 268 * status is SAM_STAT_GOOD (zero) iff code is valid.
 269 * This is used in error cases, such as allocation failures.
 270 */
 271static void ft_send_resp_status(struct fc_lport *lport,
 272                                const struct fc_frame *rx_fp,
 273                                u32 status, enum fcp_resp_rsp_codes code)
 274{
 275        struct fc_frame *fp;
 276        struct fc_seq *sp;
 277        const struct fc_frame_header *fh;
 278        size_t len;
 279        struct fcp_resp_with_ext *fcp;
 280        struct fcp_resp_rsp_info *info;
 281
 282        fh = fc_frame_header_get(rx_fp);
 283        pr_debug("FCP error response: did %x oxid %x status %x code %x\n",
 284                  ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code);
 285        len = sizeof(*fcp);
 286        if (status == SAM_STAT_GOOD)
 287                len += sizeof(*info);
 288        fp = fc_frame_alloc(lport, len);
 289        if (!fp)
 290                return;
 291        fcp = fc_frame_payload_get(fp, len);
 292        memset(fcp, 0, len);
 293        fcp->resp.fr_status = status;
 294        if (status == SAM_STAT_GOOD) {
 295                fcp->ext.fr_rsp_len = htonl(sizeof(*info));
 296                fcp->resp.fr_flags |= FCP_RSP_LEN_VAL;
 297                info = (struct fcp_resp_rsp_info *)(fcp + 1);
 298                info->rsp_code = code;
 299        }
 300
 301        fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0);
 302        sp = fr_seq(fp);
 303        if (sp) {
 304                fc_seq_send(lport, sp, fp);
 305                fc_exch_done(sp);
 306        } else {
 307                lport->tt.frame_send(lport, fp);
 308        }
 309}
 310
 311/*
 312 * Send error or task management response.
 313 */
 314static void ft_send_resp_code(struct ft_cmd *cmd,
 315                              enum fcp_resp_rsp_codes code)
 316{
 317        ft_send_resp_status(cmd->sess->tport->lport,
 318                            cmd->req_frame, SAM_STAT_GOOD, code);
 319}
 320
 321
 322/*
 323 * Send error or task management response.
 324 * Always frees the cmd and associated state.
 325 */
 326static void ft_send_resp_code_and_free(struct ft_cmd *cmd,
 327                                      enum fcp_resp_rsp_codes code)
 328{
 329        ft_send_resp_code(cmd, code);
 330        ft_free_cmd(cmd);
 331}
 332
 333/*
 334 * Handle Task Management Request.
 335 */
 336static void ft_send_tm(struct ft_cmd *cmd)
 337{
 338        struct fcp_cmnd *fcp;
 339        int rc;
 340        u8 tm_func;
 341
 342        fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
 343
 344        switch (fcp->fc_tm_flags) {
 345        case FCP_TMF_LUN_RESET:
 346                tm_func = TMR_LUN_RESET;
 347                break;
 348        case FCP_TMF_TGT_RESET:
 349                tm_func = TMR_TARGET_WARM_RESET;
 350                break;
 351        case FCP_TMF_CLR_TASK_SET:
 352                tm_func = TMR_CLEAR_TASK_SET;
 353                break;
 354        case FCP_TMF_ABT_TASK_SET:
 355                tm_func = TMR_ABORT_TASK_SET;
 356                break;
 357        case FCP_TMF_CLR_ACA:
 358                tm_func = TMR_CLEAR_ACA;
 359                break;
 360        default:
 361                /*
 362                 * FCP4r01 indicates having a combination of
 363                 * tm_flags set is invalid.
 364                 */
 365                pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
 366                ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
 367                return;
 368        }
 369
 370        /* FIXME: Add referenced task tag for ABORT_TASK */
 371        rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess,
 372                &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
 373                cmd, tm_func, GFP_KERNEL, 0, TARGET_SCF_ACK_KREF);
 374        if (rc < 0)
 375                ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
 376}
 377
 378/*
 379 * Send status from completed task management request.
 380 */
 381void ft_queue_tm_resp(struct se_cmd *se_cmd)
 382{
 383        struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
 384        struct se_tmr_req *tmr = se_cmd->se_tmr_req;
 385        enum fcp_resp_rsp_codes code;
 386
 387        if (cmd->aborted)
 388                return;
 389        switch (tmr->response) {
 390        case TMR_FUNCTION_COMPLETE:
 391                code = FCP_TMF_CMPL;
 392                break;
 393        case TMR_LUN_DOES_NOT_EXIST:
 394                code = FCP_TMF_INVALID_LUN;
 395                break;
 396        case TMR_FUNCTION_REJECTED:
 397                code = FCP_TMF_REJECTED;
 398                break;
 399        case TMR_TASK_DOES_NOT_EXIST:
 400        case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
 401        default:
 402                code = FCP_TMF_FAILED;
 403                break;
 404        }
 405        pr_debug("tmr fn %d resp %d fcp code %d\n",
 406                  tmr->function, tmr->response, code);
 407        ft_send_resp_code(cmd, code);
 408        /*
 409         * Drop the extra ACK_KREF reference taken by target_submit_tmr()
 410         * ahead of ft_check_stop_free() -> transport_generic_free_cmd()
 411         * final se_cmd->cmd_kref put.
 412         */
 413        target_put_sess_cmd(&cmd->se_cmd);
 414}
 415
 416void ft_aborted_task(struct se_cmd *se_cmd)
 417{
 418        return;
 419}
 420
 421static void ft_send_work(struct work_struct *work);
 422
 423/*
 424 * Handle incoming FCP command.
 425 */
 426static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
 427{
 428        struct ft_cmd *cmd;
 429        struct fc_lport *lport = sess->tport->lport;
 430        struct se_session *se_sess = sess->se_sess;
 431        int tag, cpu;
 432
 433        tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
 434        if (tag < 0)
 435                goto busy;
 436
 437        cmd = &((struct ft_cmd *)se_sess->sess_cmd_map)[tag];
 438        memset(cmd, 0, sizeof(struct ft_cmd));
 439
 440        cmd->se_cmd.map_tag = tag;
 441        cmd->se_cmd.map_cpu = cpu;
 442        cmd->sess = sess;
 443        cmd->seq = fc_seq_assign(lport, fp);
 444        if (!cmd->seq) {
 445                target_free_tag(se_sess, &cmd->se_cmd);
 446                goto busy;
 447        }
 448        cmd->req_frame = fp;            /* hold frame during cmd */
 449
 450        INIT_WORK(&cmd->work, ft_send_work);
 451        queue_work(sess->tport->tpg->workqueue, &cmd->work);
 452        return;
 453
 454busy:
 455        pr_debug("cmd or seq allocation failure - sending BUSY\n");
 456        ft_send_resp_status(lport, fp, SAM_STAT_BUSY, 0);
 457        fc_frame_free(fp);
 458        ft_sess_put(sess);              /* undo get from lookup */
 459}
 460
 461
 462/*
 463 * Handle incoming FCP frame.
 464 * Caller has verified that the frame is type FCP.
 465 */
 466void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp)
 467{
 468        struct fc_frame_header *fh = fc_frame_header_get(fp);
 469
 470        switch (fh->fh_r_ctl) {
 471        case FC_RCTL_DD_UNSOL_CMD:      /* command */
 472                ft_recv_cmd(sess, fp);
 473                break;
 474        case FC_RCTL_DD_SOL_DATA:       /* write data */
 475        case FC_RCTL_DD_UNSOL_CTL:
 476        case FC_RCTL_DD_SOL_CTL:
 477        case FC_RCTL_DD_DATA_DESC:      /* transfer ready */
 478        case FC_RCTL_ELS4_REQ:          /* SRR, perhaps */
 479        default:
 480                pr_debug("%s: unhandled frame r_ctl %x\n",
 481                       __func__, fh->fh_r_ctl);
 482                fc_frame_free(fp);
 483                ft_sess_put(sess);      /* undo get from lookup */
 484                break;
 485        }
 486}
 487
 488/*
 489 * Send new command to target.
 490 */
 491static void ft_send_work(struct work_struct *work)
 492{
 493        struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
 494        struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
 495        struct fcp_cmnd *fcp;
 496        int data_dir = 0;
 497        int task_attr;
 498
 499        fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
 500        if (!fcp)
 501                goto err;
 502
 503        if (fcp->fc_flags & FCP_CFL_LEN_MASK)
 504                goto err;               /* not handling longer CDBs yet */
 505
 506        /*
 507         * Check for FCP task management flags
 508         */
 509        if (fcp->fc_tm_flags) {
 510                ft_send_tm(cmd);
 511                return;
 512        }
 513
 514        switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
 515        case 0:
 516                data_dir = DMA_NONE;
 517                break;
 518        case FCP_CFL_RDDATA:
 519                data_dir = DMA_FROM_DEVICE;
 520                break;
 521        case FCP_CFL_WRDATA:
 522                data_dir = DMA_TO_DEVICE;
 523                break;
 524        case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
 525                goto err;       /* TBD not supported by tcm_fc yet */
 526        }
 527        /*
 528         * Locate the SAM Task Attr from fc_pri_ta
 529         */
 530        switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
 531        case FCP_PTA_HEADQ:
 532                task_attr = TCM_HEAD_TAG;
 533                break;
 534        case FCP_PTA_ORDERED:
 535                task_attr = TCM_ORDERED_TAG;
 536                break;
 537        case FCP_PTA_ACA:
 538                task_attr = TCM_ACA_TAG;
 539                break;
 540        case FCP_PTA_SIMPLE:
 541        default:
 542                task_attr = TCM_SIMPLE_TAG;
 543        }
 544
 545        fc_seq_set_resp(cmd->seq, ft_recv_seq, cmd);
 546        cmd->se_cmd.tag = fc_seq_exch(cmd->seq)->rxid;
 547        /*
 548         * Use a single se_cmd->cmd_kref as we expect to release se_cmd
 549         * directly from ft_check_stop_free callback in response path.
 550         */
 551        if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
 552                              &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
 553                              ntohl(fcp->fc_dl), task_attr, data_dir,
 554                              TARGET_SCF_ACK_KREF | TARGET_SCF_USE_CPUID))
 555                goto err;
 556
 557        pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd);
 558        return;
 559
 560err:
 561        ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
 562}
 563