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