Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2010 Cisco Systems, Inc.
0004  */
0005 
0006 /* XXX TBD some includes may be extraneous */
0007 
0008 #include <linux/module.h>
0009 #include <linux/moduleparam.h>
0010 #include <linux/utsname.h>
0011 #include <linux/init.h>
0012 #include <linux/slab.h>
0013 #include <linux/kthread.h>
0014 #include <linux/types.h>
0015 #include <linux/string.h>
0016 #include <linux/configfs.h>
0017 #include <linux/ctype.h>
0018 #include <linux/hash.h>
0019 #include <asm/unaligned.h>
0020 #include <scsi/scsi_tcq.h>
0021 #include <scsi/libfc.h>
0022 
0023 #include <target/target_core_base.h>
0024 #include <target/target_core_fabric.h>
0025 
0026 #include "tcm_fc.h"
0027 
0028 /*
0029  * Dump cmd state for debugging.
0030  */
0031 static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
0032 {
0033     struct fc_exch *ep;
0034     struct fc_seq *sp;
0035     struct se_cmd *se_cmd;
0036     struct scatterlist *sg;
0037     int count;
0038 
0039     se_cmd = &cmd->se_cmd;
0040     pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n",
0041         caller, cmd, cmd->sess, cmd->seq, se_cmd);
0042 
0043     pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n",
0044         caller, cmd, se_cmd->t_data_nents,
0045            se_cmd->data_length, se_cmd->se_cmd_flags);
0046 
0047     for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, count)
0048         pr_debug("%s: cmd %p sg %p page %p "
0049             "len 0x%x off 0x%x\n",
0050             caller, cmd, sg,
0051             sg_page(sg), sg->length, sg->offset);
0052 
0053     sp = cmd->seq;
0054     if (sp) {
0055         ep = fc_seq_exch(sp);
0056         pr_debug("%s: cmd %p sid %x did %x "
0057             "ox_id %x rx_id %x seq_id %x e_stat %x\n",
0058             caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid,
0059             sp->id, ep->esb_stat);
0060     }
0061 }
0062 
0063 void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
0064 {
0065     if (unlikely(ft_debug_logging))
0066         _ft_dump_cmd(cmd, caller);
0067 }
0068 
0069 static void ft_free_cmd(struct ft_cmd *cmd)
0070 {
0071     struct fc_frame *fp;
0072     struct ft_sess *sess;
0073 
0074     if (!cmd)
0075         return;
0076     sess = cmd->sess;
0077     fp = cmd->req_frame;
0078     if (fr_seq(fp))
0079         fc_seq_release(fr_seq(fp));
0080     fc_frame_free(fp);
0081     target_free_tag(sess->se_sess, &cmd->se_cmd);
0082     ft_sess_put(sess);  /* undo get from lookup at recv */
0083 }
0084 
0085 void ft_release_cmd(struct se_cmd *se_cmd)
0086 {
0087     struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
0088 
0089     ft_free_cmd(cmd);
0090 }
0091 
0092 int ft_check_stop_free(struct se_cmd *se_cmd)
0093 {
0094     return transport_generic_free_cmd(se_cmd, 0);
0095 }
0096 
0097 /*
0098  * Send response.
0099  */
0100 int ft_queue_status(struct se_cmd *se_cmd)
0101 {
0102     struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
0103     struct fc_frame *fp;
0104     struct fcp_resp_with_ext *fcp;
0105     struct fc_lport *lport;
0106     struct fc_exch *ep;
0107     size_t len;
0108     int rc;
0109 
0110     if (cmd->aborted)
0111         return 0;
0112     ft_dump_cmd(cmd, __func__);
0113     ep = fc_seq_exch(cmd->seq);
0114     lport = ep->lp;
0115     len = sizeof(*fcp) + se_cmd->scsi_sense_length;
0116     fp = fc_frame_alloc(lport, len);
0117     if (!fp) {
0118         se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
0119         return -ENOMEM;
0120     }
0121 
0122     fcp = fc_frame_payload_get(fp, len);
0123     memset(fcp, 0, len);
0124     fcp->resp.fr_status = se_cmd->scsi_status;
0125 
0126     len = se_cmd->scsi_sense_length;
0127     if (len) {
0128         fcp->resp.fr_flags |= FCP_SNS_LEN_VAL;
0129         fcp->ext.fr_sns_len = htonl(len);
0130         memcpy((fcp + 1), se_cmd->sense_buffer, len);
0131     }
0132 
0133     /*
0134      * Test underflow and overflow with one mask.  Usually both are off.
0135      * Bidirectional commands are not handled yet.
0136      */
0137     if (se_cmd->se_cmd_flags & (SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT)) {
0138         if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
0139             fcp->resp.fr_flags |= FCP_RESID_OVER;
0140         else
0141             fcp->resp.fr_flags |= FCP_RESID_UNDER;
0142         fcp->ext.fr_resid = cpu_to_be32(se_cmd->residual_count);
0143     }
0144 
0145     /*
0146      * Send response.
0147      */
0148     cmd->seq = fc_seq_start_next(cmd->seq);
0149     fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP,
0150                FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0);
0151 
0152     rc = fc_seq_send(lport, cmd->seq, fp);
0153     if (rc) {
0154         pr_info_ratelimited("%s: Failed to send response frame %p, "
0155                     "xid <0x%x>\n", __func__, fp, ep->xid);
0156         /*
0157          * Generate a TASK_SET_FULL status to notify the initiator
0158          * to reduce it's queue_depth after the se_cmd response has
0159          * been re-queued by target-core.
0160          */
0161         se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
0162         return -ENOMEM;
0163     }
0164     fc_exch_done(cmd->seq);
0165     /*
0166      * Drop the extra ACK_KREF reference taken by target_submit_cmd()
0167      * ahead of ft_check_stop_free() -> transport_generic_free_cmd()
0168      * final se_cmd->cmd_kref put.
0169      */
0170     target_put_sess_cmd(&cmd->se_cmd);
0171     return 0;
0172 }
0173 
0174 /*
0175  * Send TX_RDY (transfer ready).
0176  */
0177 int ft_write_pending(struct se_cmd *se_cmd)
0178 {
0179     struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
0180     struct fc_frame *fp;
0181     struct fcp_txrdy *txrdy;
0182     struct fc_lport *lport;
0183     struct fc_exch *ep;
0184     struct fc_frame_header *fh;
0185     u32 f_ctl;
0186 
0187     ft_dump_cmd(cmd, __func__);
0188 
0189     if (cmd->aborted)
0190         return 0;
0191     ep = fc_seq_exch(cmd->seq);
0192     lport = ep->lp;
0193     fp = fc_frame_alloc(lport, sizeof(*txrdy));
0194     if (!fp)
0195         return -ENOMEM; /* Signal QUEUE_FULL */
0196 
0197     txrdy = fc_frame_payload_get(fp, sizeof(*txrdy));
0198     memset(txrdy, 0, sizeof(*txrdy));
0199     txrdy->ft_burst_len = htonl(se_cmd->data_length);
0200 
0201     cmd->seq = fc_seq_start_next(cmd->seq);
0202     fc_fill_fc_hdr(fp, FC_RCTL_DD_DATA_DESC, ep->did, ep->sid, FC_TYPE_FCP,
0203                FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
0204 
0205     fh = fc_frame_header_get(fp);
0206     f_ctl = ntoh24(fh->fh_f_ctl);
0207 
0208     /* Only if it is 'Exchange Responder' */
0209     if (f_ctl & FC_FC_EX_CTX) {
0210         /* Target is 'exchange responder' and sending XFER_READY
0211          * to 'exchange initiator (initiator)'
0212          */
0213         if ((ep->xid <= lport->lro_xid) &&
0214             (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
0215             if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
0216                 lport->tt.ddp_target(lport, ep->xid,
0217                          se_cmd->t_data_sg,
0218                          se_cmd->t_data_nents))
0219                 cmd->was_ddp_setup = 1;
0220         }
0221     }
0222     fc_seq_send(lport, cmd->seq, fp);
0223     return 0;
0224 }
0225 
0226 int ft_get_cmd_state(struct se_cmd *se_cmd)
0227 {
0228     return 0;
0229 }
0230 
0231 /*
0232  * FC sequence response handler for follow-on sequences (data) and aborts.
0233  */
0234 static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
0235 {
0236     struct ft_cmd *cmd = arg;
0237     struct fc_frame_header *fh;
0238 
0239     if (IS_ERR(fp)) {
0240         /* XXX need to find cmd if queued */
0241         cmd->seq = NULL;
0242         cmd->aborted = true;
0243         return;
0244     }
0245 
0246     fh = fc_frame_header_get(fp);
0247 
0248     switch (fh->fh_r_ctl) {
0249     case FC_RCTL_DD_SOL_DATA:   /* write data */
0250         ft_recv_write_data(cmd, fp);
0251         break;
0252     case FC_RCTL_DD_UNSOL_CTL:  /* command */
0253     case FC_RCTL_DD_SOL_CTL:    /* transfer ready */
0254     case FC_RCTL_DD_DATA_DESC:  /* transfer ready */
0255     default:
0256         pr_debug("%s: unhandled frame r_ctl %x\n",
0257                __func__, fh->fh_r_ctl);
0258         ft_invl_hw_context(cmd);
0259         fc_frame_free(fp);
0260         transport_generic_free_cmd(&cmd->se_cmd, 0);
0261         break;
0262     }
0263 }
0264 
0265 /*
0266  * Send a FCP response including SCSI status and optional FCP rsp_code.
0267  * status is SAM_STAT_GOOD (zero) iff code is valid.
0268  * This is used in error cases, such as allocation failures.
0269  */
0270 static void ft_send_resp_status(struct fc_lport *lport,
0271                 const struct fc_frame *rx_fp,
0272                 u32 status, enum fcp_resp_rsp_codes code)
0273 {
0274     struct fc_frame *fp;
0275     struct fc_seq *sp;
0276     const struct fc_frame_header *fh;
0277     size_t len;
0278     struct fcp_resp_with_ext *fcp;
0279     struct fcp_resp_rsp_info *info;
0280 
0281     fh = fc_frame_header_get(rx_fp);
0282     pr_debug("FCP error response: did %x oxid %x status %x code %x\n",
0283           ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code);
0284     len = sizeof(*fcp);
0285     if (status == SAM_STAT_GOOD)
0286         len += sizeof(*info);
0287     fp = fc_frame_alloc(lport, len);
0288     if (!fp)
0289         return;
0290     fcp = fc_frame_payload_get(fp, len);
0291     memset(fcp, 0, len);
0292     fcp->resp.fr_status = status;
0293     if (status == SAM_STAT_GOOD) {
0294         fcp->ext.fr_rsp_len = htonl(sizeof(*info));
0295         fcp->resp.fr_flags |= FCP_RSP_LEN_VAL;
0296         info = (struct fcp_resp_rsp_info *)(fcp + 1);
0297         info->rsp_code = code;
0298     }
0299 
0300     fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0);
0301     sp = fr_seq(fp);
0302     if (sp) {
0303         fc_seq_send(lport, sp, fp);
0304         fc_exch_done(sp);
0305     } else {
0306         lport->tt.frame_send(lport, fp);
0307     }
0308 }
0309 
0310 /*
0311  * Send error or task management response.
0312  */
0313 static void ft_send_resp_code(struct ft_cmd *cmd,
0314                   enum fcp_resp_rsp_codes code)
0315 {
0316     ft_send_resp_status(cmd->sess->tport->lport,
0317                 cmd->req_frame, SAM_STAT_GOOD, code);
0318 }
0319 
0320 
0321 /*
0322  * Send error or task management response.
0323  * Always frees the cmd and associated state.
0324  */
0325 static void ft_send_resp_code_and_free(struct ft_cmd *cmd,
0326                       enum fcp_resp_rsp_codes code)
0327 {
0328     ft_send_resp_code(cmd, code);
0329     ft_free_cmd(cmd);
0330 }
0331 
0332 /*
0333  * Handle Task Management Request.
0334  */
0335 static void ft_send_tm(struct ft_cmd *cmd)
0336 {
0337     struct fcp_cmnd *fcp;
0338     int rc;
0339     u8 tm_func;
0340 
0341     fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
0342 
0343     switch (fcp->fc_tm_flags) {
0344     case FCP_TMF_LUN_RESET:
0345         tm_func = TMR_LUN_RESET;
0346         break;
0347     case FCP_TMF_TGT_RESET:
0348         tm_func = TMR_TARGET_WARM_RESET;
0349         break;
0350     case FCP_TMF_CLR_TASK_SET:
0351         tm_func = TMR_CLEAR_TASK_SET;
0352         break;
0353     case FCP_TMF_ABT_TASK_SET:
0354         tm_func = TMR_ABORT_TASK_SET;
0355         break;
0356     case FCP_TMF_CLR_ACA:
0357         tm_func = TMR_CLEAR_ACA;
0358         break;
0359     default:
0360         /*
0361          * FCP4r01 indicates having a combination of
0362          * tm_flags set is invalid.
0363          */
0364         pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
0365         ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
0366         return;
0367     }
0368 
0369     /* FIXME: Add referenced task tag for ABORT_TASK */
0370     rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess,
0371         &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
0372         cmd, tm_func, GFP_KERNEL, 0, TARGET_SCF_ACK_KREF);
0373     if (rc < 0)
0374         ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
0375 }
0376 
0377 /*
0378  * Send status from completed task management request.
0379  */
0380 void ft_queue_tm_resp(struct se_cmd *se_cmd)
0381 {
0382     struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
0383     struct se_tmr_req *tmr = se_cmd->se_tmr_req;
0384     enum fcp_resp_rsp_codes code;
0385 
0386     if (cmd->aborted)
0387         return;
0388     switch (tmr->response) {
0389     case TMR_FUNCTION_COMPLETE:
0390         code = FCP_TMF_CMPL;
0391         break;
0392     case TMR_LUN_DOES_NOT_EXIST:
0393         code = FCP_TMF_INVALID_LUN;
0394         break;
0395     case TMR_FUNCTION_REJECTED:
0396         code = FCP_TMF_REJECTED;
0397         break;
0398     case TMR_TASK_DOES_NOT_EXIST:
0399     case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
0400     default:
0401         code = FCP_TMF_FAILED;
0402         break;
0403     }
0404     pr_debug("tmr fn %d resp %d fcp code %d\n",
0405           tmr->function, tmr->response, code);
0406     ft_send_resp_code(cmd, code);
0407     /*
0408      * Drop the extra ACK_KREF reference taken by target_submit_tmr()
0409      * ahead of ft_check_stop_free() -> transport_generic_free_cmd()
0410      * final se_cmd->cmd_kref put.
0411      */
0412     target_put_sess_cmd(&cmd->se_cmd);
0413 }
0414 
0415 void ft_aborted_task(struct se_cmd *se_cmd)
0416 {
0417     return;
0418 }
0419 
0420 static void ft_send_work(struct work_struct *work);
0421 
0422 /*
0423  * Handle incoming FCP command.
0424  */
0425 static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
0426 {
0427     struct ft_cmd *cmd;
0428     struct fc_lport *lport = sess->tport->lport;
0429     struct se_session *se_sess = sess->se_sess;
0430     int tag, cpu;
0431 
0432     tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
0433     if (tag < 0)
0434         goto busy;
0435 
0436     cmd = &((struct ft_cmd *)se_sess->sess_cmd_map)[tag];
0437     memset(cmd, 0, sizeof(struct ft_cmd));
0438 
0439     cmd->se_cmd.map_tag = tag;
0440     cmd->se_cmd.map_cpu = cpu;
0441     cmd->sess = sess;
0442     cmd->seq = fc_seq_assign(lport, fp);
0443     if (!cmd->seq) {
0444         target_free_tag(se_sess, &cmd->se_cmd);
0445         goto busy;
0446     }
0447     cmd->req_frame = fp;        /* hold frame during cmd */
0448 
0449     INIT_WORK(&cmd->work, ft_send_work);
0450     queue_work(sess->tport->tpg->workqueue, &cmd->work);
0451     return;
0452 
0453 busy:
0454     pr_debug("cmd or seq allocation failure - sending BUSY\n");
0455     ft_send_resp_status(lport, fp, SAM_STAT_BUSY, 0);
0456     fc_frame_free(fp);
0457     ft_sess_put(sess);      /* undo get from lookup */
0458 }
0459 
0460 
0461 /*
0462  * Handle incoming FCP frame.
0463  * Caller has verified that the frame is type FCP.
0464  */
0465 void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp)
0466 {
0467     struct fc_frame_header *fh = fc_frame_header_get(fp);
0468 
0469     switch (fh->fh_r_ctl) {
0470     case FC_RCTL_DD_UNSOL_CMD:  /* command */
0471         ft_recv_cmd(sess, fp);
0472         break;
0473     case FC_RCTL_DD_SOL_DATA:   /* write data */
0474     case FC_RCTL_DD_UNSOL_CTL:
0475     case FC_RCTL_DD_SOL_CTL:
0476     case FC_RCTL_DD_DATA_DESC:  /* transfer ready */
0477     case FC_RCTL_ELS4_REQ:      /* SRR, perhaps */
0478     default:
0479         pr_debug("%s: unhandled frame r_ctl %x\n",
0480                __func__, fh->fh_r_ctl);
0481         fc_frame_free(fp);
0482         ft_sess_put(sess);  /* undo get from lookup */
0483         break;
0484     }
0485 }
0486 
0487 /*
0488  * Send new command to target.
0489  */
0490 static void ft_send_work(struct work_struct *work)
0491 {
0492     struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
0493     struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
0494     struct fcp_cmnd *fcp;
0495     int data_dir = 0;
0496     int task_attr;
0497 
0498     fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
0499     if (!fcp)
0500         goto err;
0501 
0502     if (fcp->fc_flags & FCP_CFL_LEN_MASK)
0503         goto err;       /* not handling longer CDBs yet */
0504 
0505     /*
0506      * Check for FCP task management flags
0507      */
0508     if (fcp->fc_tm_flags) {
0509         ft_send_tm(cmd);
0510         return;
0511     }
0512 
0513     switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
0514     case 0:
0515         data_dir = DMA_NONE;
0516         break;
0517     case FCP_CFL_RDDATA:
0518         data_dir = DMA_FROM_DEVICE;
0519         break;
0520     case FCP_CFL_WRDATA:
0521         data_dir = DMA_TO_DEVICE;
0522         break;
0523     case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
0524         goto err;   /* TBD not supported by tcm_fc yet */
0525     }
0526     /*
0527      * Locate the SAM Task Attr from fc_pri_ta
0528      */
0529     switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
0530     case FCP_PTA_HEADQ:
0531         task_attr = TCM_HEAD_TAG;
0532         break;
0533     case FCP_PTA_ORDERED:
0534         task_attr = TCM_ORDERED_TAG;
0535         break;
0536     case FCP_PTA_ACA:
0537         task_attr = TCM_ACA_TAG;
0538         break;
0539     case FCP_PTA_SIMPLE:
0540     default:
0541         task_attr = TCM_SIMPLE_TAG;
0542     }
0543 
0544     fc_seq_set_resp(cmd->seq, ft_recv_seq, cmd);
0545     cmd->se_cmd.tag = fc_seq_exch(cmd->seq)->rxid;
0546 
0547     /*
0548      * Use a single se_cmd->cmd_kref as we expect to release se_cmd
0549      * directly from ft_check_stop_free callback in response path.
0550      */
0551     if (target_init_cmd(&cmd->se_cmd, cmd->sess->se_sess,
0552                 &cmd->ft_sense_buffer[0],
0553                 scsilun_to_int(&fcp->fc_lun), ntohl(fcp->fc_dl),
0554                 task_attr, data_dir, TARGET_SCF_ACK_KREF))
0555         goto err;
0556 
0557     if (target_submit_prep(&cmd->se_cmd, fcp->fc_cdb, NULL, 0, NULL, 0,
0558                    NULL, 0, GFP_KERNEL))
0559         return;
0560 
0561     target_submit(&cmd->se_cmd);
0562     pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd);
0563     return;
0564 
0565 err:
0566     ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
0567 }