LCOV - code coverage report
Current view: top level - spdk/lib/scsi - scsi_pr.c (source / functions) Hit Total Coverage
Test: Combined Lines: 265 517 51.3 %
Date: 2024-07-13 22:49:35 Functions: 21 28 75.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 152 345 44.1 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2019 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "scsi_internal.h"
       7                 :            : 
       8                 :            : #include "spdk/endian.h"
       9                 :            : 
      10                 :            : /* Get registrant by I_T nexus */
      11                 :            : static struct spdk_scsi_pr_registrant *
      12                 :        540 : scsi_pr_get_registrant(struct spdk_scsi_lun *lun,
      13                 :            :                        struct spdk_scsi_port *initiator_port,
      14                 :            :                        struct spdk_scsi_port *target_port)
      15                 :            : {
      16                 :            :         struct spdk_scsi_pr_registrant *reg, *tmp;
      17                 :            : 
      18         [ +  + ]:        916 :         TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
      19         [ +  + ]:        740 :                 if (initiator_port == reg->initiator_port &&
      20         [ +  - ]:        364 :                     target_port == reg->target_port) {
      21                 :        364 :                         return reg;
      22                 :            :                 }
      23                 :            :         }
      24                 :            : 
      25                 :        176 :         return NULL;
      26                 :            : }
      27                 :            : 
      28                 :            : static bool
      29                 :          8 : scsi2_it_nexus_is_holder(struct spdk_scsi_lun *lun,
      30                 :            :                          struct spdk_scsi_port *initiator_port,
      31                 :            :                          struct spdk_scsi_port *target_port)
      32                 :            : {
      33                 :          8 :         struct spdk_scsi_pr_registrant *reg = lun->reservation.holder;
      34                 :            : 
      35         [ -  + ]:          8 :         assert(reg != NULL);
      36                 :            : 
      37         [ +  + ]:          8 :         if ((reg->initiator_port == initiator_port) &&
      38         [ +  - ]:          4 :             (reg->target_port == target_port)) {
      39                 :          4 :                 return true;
      40                 :            :         }
      41                 :            : 
      42                 :          4 :         return false;
      43                 :            : }
      44                 :            : 
      45                 :            : /* Reservation type is all registrants or not */
      46                 :            : static inline bool
      47                 :        156 : scsi_pr_is_all_registrants_type(struct spdk_scsi_lun *lun)
      48                 :            : {
      49         [ +  + ]:        264 :         return (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS ||
      50         [ +  + ]:        108 :                 lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS);
      51                 :            : }
      52                 :            : 
      53                 :            : /* Registrant is reservation holder or not */
      54                 :            : static inline bool
      55                 :        124 : scsi_pr_registrant_is_holder(struct spdk_scsi_lun *lun,
      56                 :            :                              struct spdk_scsi_pr_registrant *reg)
      57                 :            : {
      58   [ +  +  +  + ]:        124 :         if (reg != NULL && scsi_pr_is_all_registrants_type(lun)) {
      59                 :         36 :                 return true;
      60                 :            :         }
      61                 :            : 
      62                 :         88 :         return (lun->reservation.holder == reg);
      63                 :            : }
      64                 :            : 
      65                 :            : /* LUN holds a reservation or not */
      66                 :            : static inline bool
      67                 :   29563714 : scsi_pr_has_reservation(struct spdk_scsi_lun *lun)
      68                 :            : {
      69                 :   29563714 :         return !(lun->reservation.holder == NULL);
      70                 :            : }
      71                 :            : 
      72                 :            : static int
      73                 :         96 : scsi_pr_register_registrant(struct spdk_scsi_lun *lun,
      74                 :            :                             struct spdk_scsi_port *initiator_port,
      75                 :            :                             struct spdk_scsi_port *target_port,
      76                 :            :                             uint64_t sa_rkey)
      77                 :            : {
      78                 :            :         struct spdk_scsi_pr_registrant *reg;
      79                 :            : 
      80                 :            :         /* Register sa_rkey with the I_T nexus */
      81                 :         96 :         reg = calloc(1, sizeof(*reg));
      82         [ -  + ]:         96 :         if (!reg) {
      83                 :          0 :                 return -ENOMEM;
      84                 :            :         }
      85                 :            : 
      86   [ -  +  -  + ]:         96 :         SPDK_DEBUGLOG(scsi, "REGISTER: new registrant registered "
      87                 :            :                       "with key 0x%"PRIx64"\n", sa_rkey);
      88                 :            : 
      89                 :            :         /* New I_T nexus */
      90                 :         96 :         reg->initiator_port = initiator_port;
      91         [ +  - ]:         96 :         if (initiator_port) {
      92         [ -  + ]:         96 :                 snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s",
      93                 :         96 :                          initiator_port->name);
      94                 :         96 :                 reg->transport_id_len = initiator_port->transport_id_len;
      95   [ -  +  -  + ]:         96 :                 memcpy(reg->transport_id, initiator_port->transport_id, reg->transport_id_len);
      96                 :            :         }
      97                 :         96 :         reg->target_port = target_port;
      98         [ +  - ]:         96 :         if (target_port) {
      99         [ -  + ]:         96 :                 snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s",
     100                 :         96 :                          target_port->name);
     101                 :         96 :                 reg->relative_target_port_id = target_port->index;
     102                 :            :         }
     103                 :         96 :         reg->rkey = sa_rkey;
     104                 :         96 :         TAILQ_INSERT_TAIL(&lun->reg_head, reg, link);
     105                 :         96 :         lun->pr_generation++;
     106                 :            : 
     107                 :         96 :         return 0;
     108                 :            : }
     109                 :            : 
     110                 :            : static void
     111                 :         32 : scsi_pr_release_reservation(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg)
     112                 :            : {
     113                 :         32 :         bool all_regs = false;
     114                 :            :         struct spdk_scsi_pr_registrant *curr_reg, *tmp;
     115                 :            : 
     116   [ -  +  -  + ]:         32 :         SPDK_DEBUGLOG(scsi, "REGISTER: release reservation "
     117                 :            :                       "with type %u\n", lun->reservation.rtype);
     118                 :            : 
     119                 :            :         /* TODO: Unit Attention */
     120                 :         32 :         all_regs = scsi_pr_is_all_registrants_type(lun);
     121         [ +  + ]:         32 :         if (all_regs) {
     122         [ +  + ]:         32 :                 TAILQ_FOREACH_SAFE(curr_reg, &lun->reg_head, link, tmp) {
     123         [ +  + ]:         28 :                         if (curr_reg != reg) {
     124                 :         20 :                                 lun->reservation.holder = curr_reg;
     125                 :         20 :                                 lun->reservation.crkey = curr_reg->rkey;
     126                 :         20 :                                 return;
     127                 :            :                         }
     128                 :            :                 }
     129                 :            :         }
     130                 :            : 
     131         [ -  + ]:         12 :         memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation));
     132                 :            : }
     133                 :            : 
     134                 :            : static void
     135                 :         48 : scsi_pr_reserve_reservation(struct spdk_scsi_lun *lun,
     136                 :            :                             enum spdk_scsi_pr_type_code type,
     137                 :            :                             uint64_t rkey,
     138                 :            :                             struct spdk_scsi_pr_registrant *holder)
     139                 :            : {
     140                 :         48 :         lun->reservation.rtype = type;
     141                 :         48 :         lun->reservation.crkey = rkey;
     142                 :         48 :         lun->reservation.holder = holder;
     143                 :         48 : }
     144                 :            : 
     145                 :            : static void
     146                 :         36 : scsi_pr_unregister_registrant(struct spdk_scsi_lun *lun,
     147                 :            :                               struct spdk_scsi_pr_registrant *reg)
     148                 :            : {
     149   [ -  +  -  + ]:         36 :         SPDK_DEBUGLOG(scsi, "REGISTER: unregister registrant\n");
     150                 :            : 
     151         [ +  + ]:         36 :         TAILQ_REMOVE(&lun->reg_head, reg, link);
     152         [ +  + ]:         36 :         if (scsi_pr_registrant_is_holder(lun, reg)) {
     153                 :         24 :                 scsi_pr_release_reservation(lun, reg);
     154                 :            :         }
     155                 :            : 
     156                 :         36 :         free(reg);
     157                 :         36 :         lun->pr_generation++;
     158                 :         36 : }
     159                 :            : 
     160                 :            : static void
     161                 :         32 : scsi_pr_replace_registrant_key(struct spdk_scsi_lun *lun,
     162                 :            :                                struct spdk_scsi_pr_registrant *reg,
     163                 :            :                                uint64_t sa_rkey)
     164                 :            : {
     165   [ -  +  -  + ]:         32 :         SPDK_DEBUGLOG(scsi, "REGISTER: replace with new "
     166                 :            :                       "reservation key 0x%"PRIx64"\n", sa_rkey);
     167                 :         32 :         reg->rkey = sa_rkey;
     168                 :         32 :         lun->pr_generation++;
     169                 :         32 : }
     170                 :            : 
     171                 :            : static int
     172                 :         44 : scsi_pr_out_reserve(struct spdk_scsi_task *task,
     173                 :            :                     enum spdk_scsi_pr_type_code rtype, uint64_t rkey,
     174                 :            :                     uint8_t spec_i_pt, uint8_t all_tg_pt, uint8_t aptpl)
     175                 :            : {
     176                 :         44 :         struct spdk_scsi_lun *lun = task->lun;
     177                 :            :         struct spdk_scsi_pr_registrant *reg;
     178                 :            : 
     179   [ -  +  -  + ]:         44 :         SPDK_DEBUGLOG(scsi, "PR OUT RESERVE: rkey 0x%"PRIx64", requested "
     180                 :            :                       "reservation type %u, type %u\n", rkey, rtype, lun->reservation.rtype);
     181                 :            : 
     182                 :            :         /* TODO: don't support now */
     183   [ +  -  +  -  :         44 :         if (spec_i_pt || all_tg_pt || aptpl) {
                   -  + ]
     184                 :          0 :                 SPDK_ERRLOG("Unsupported spec_i_pt/all_tg_pt fields "
     185                 :            :                             "or invalid aptpl field\n");
     186                 :          0 :                 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
     187                 :            :                                           SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
     188                 :            :                                           SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
     189                 :            :                                           SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     190                 :          0 :                 return -EINVAL;
     191                 :            :         }
     192                 :            : 
     193                 :         44 :         reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
     194                 :            :         /* No registration for the I_T nexus */
     195         [ -  + ]:         44 :         if (!reg) {
     196                 :          0 :                 SPDK_ERRLOG("No registration\n");
     197                 :          0 :                 goto conflict;
     198                 :            :         }
     199                 :            : 
     200                 :            :         /* invalid reservation key */
     201         [ -  + ]:         44 :         if (reg->rkey != rkey) {
     202                 :          0 :                 SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match 0x%"PRIx64"\n",
     203                 :            :                             rkey, reg->rkey);
     204                 :          0 :                 goto conflict;
     205                 :            :         }
     206                 :            : 
     207                 :            :         /* reservation holder already exists */
     208         [ +  + ]:         44 :         if (scsi_pr_has_reservation(lun)) {
     209         [ +  + ]:         12 :                 if (rtype != lun->reservation.rtype) {
     210                 :          4 :                         SPDK_ERRLOG("Reservation type doesn't match\n");
     211                 :          4 :                         goto conflict;
     212                 :            :                 }
     213                 :            : 
     214         [ +  + ]:          8 :                 if (!scsi_pr_registrant_is_holder(lun, reg)) {
     215                 :          4 :                         SPDK_ERRLOG("Only 1 holder is allowed for type %u\n", rtype);
     216                 :          4 :                         goto conflict;
     217                 :            :                 }
     218                 :            :         } else {
     219                 :            :                 /* current I_T nexus is the first reservation holder */
     220                 :         32 :                 scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
     221                 :            :         }
     222                 :            : 
     223                 :         36 :         return 0;
     224                 :            : 
     225                 :          8 : conflict:
     226                 :          8 :         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
     227                 :            :                                   SPDK_SCSI_SENSE_NO_SENSE,
     228                 :            :                                   SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
     229                 :            :                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     230                 :          8 :         return -EINVAL;
     231                 :            : }
     232                 :            : 
     233                 :            : static int
     234                 :        180 : scsi_pr_out_register(struct spdk_scsi_task *task,
     235                 :            :                      enum spdk_scsi_pr_out_service_action_code action,
     236                 :            :                      uint64_t rkey, uint64_t sa_rkey,
     237                 :            :                      uint8_t spec_i_pt, uint8_t all_tg_pt, uint8_t aptpl)
     238                 :            : {
     239                 :        180 :         struct spdk_scsi_lun *lun = task->lun;
     240                 :            :         struct spdk_scsi_pr_registrant *reg;
     241                 :            :         int sc, sk, asc;
     242                 :            : 
     243   [ -  +  -  + ]:        180 :         SPDK_DEBUGLOG(scsi, "PR OUT REGISTER: rkey 0x%"PRIx64", "
     244                 :            :                       "sa_key 0x%"PRIx64", reservation type %u\n", rkey, sa_rkey, lun->reservation.rtype);
     245                 :            : 
     246                 :            :         /* TODO: don't support now */
     247   [ +  -  +  -  :        180 :         if (spec_i_pt || all_tg_pt || aptpl) {
                   -  + ]
     248                 :          0 :                 SPDK_ERRLOG("Unsupported spec_i_pt/all_tg_pt/aptpl field\n");
     249                 :          0 :                 sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
     250                 :          0 :                 sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
     251                 :          0 :                 asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB;
     252                 :          0 :                 goto error_exit;
     253                 :            :         }
     254                 :            : 
     255                 :        180 :         reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
     256                 :            :         /* an unregistered I_T nexus session */
     257         [ +  + ]:        180 :         if (!reg) {
     258   [ -  +  -  - ]:         96 :                 if (rkey && (action == SPDK_SCSI_PR_OUT_REGISTER)) {
     259                 :          0 :                         SPDK_ERRLOG("Reservation key field is not empty\n");
     260                 :          0 :                         sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
     261                 :          0 :                         sk = SPDK_SCSI_SENSE_NO_SENSE;
     262                 :          0 :                         asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
     263                 :          0 :                         goto error_exit;
     264                 :            :                 }
     265                 :            : 
     266         [ -  + ]:         96 :                 if (!sa_rkey) {
     267                 :            :                         /* Do nothing except return GOOD status */
     268   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(scsi, "REGISTER: service action "
     269                 :            :                                       "reservation key is zero, do noting\n");
     270                 :          0 :                         return 0;
     271                 :            :                 }
     272                 :            :                 /* Add a new registrant for the I_T nexus */
     273                 :         96 :                 return scsi_pr_register_registrant(lun, task->initiator_port,
     274                 :            :                                                    task->target_port, sa_rkey);
     275                 :            :         } else {
     276                 :            :                 /* a registered I_T nexus */
     277   [ +  +  +  - ]:         84 :                 if (rkey != reg->rkey && action == SPDK_SCSI_PR_OUT_REGISTER) {
     278                 :         32 :                         SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match "
     279                 :            :                                     "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
     280                 :         32 :                         sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
     281                 :         32 :                         sk = SPDK_SCSI_SENSE_NO_SENSE;
     282                 :         32 :                         asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
     283                 :         32 :                         goto error_exit;
     284                 :            :                 }
     285                 :            : 
     286         [ +  + ]:         52 :                 if (!sa_rkey) {
     287                 :            :                         /* unregister */
     288                 :         20 :                         scsi_pr_unregister_registrant(lun, reg);
     289                 :            :                 } else {
     290                 :            :                         /* replace */
     291                 :         32 :                         scsi_pr_replace_registrant_key(lun, reg, sa_rkey);
     292                 :            :                 }
     293                 :            :         }
     294                 :            : 
     295                 :         52 :         return 0;
     296                 :            : 
     297                 :         32 : error_exit:
     298                 :         32 :         spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
     299                 :         32 :         return -EINVAL;
     300                 :            : }
     301                 :            : 
     302                 :            : static int
     303                 :          8 : scsi_pr_out_release(struct spdk_scsi_task *task,
     304                 :            :                     enum spdk_scsi_pr_type_code rtype, uint64_t rkey)
     305                 :            : {
     306                 :          8 :         struct spdk_scsi_lun *lun = task->lun;
     307                 :            :         struct spdk_scsi_pr_registrant *reg;
     308                 :            :         int sk, asc;
     309                 :            : 
     310   [ -  +  -  + ]:          8 :         SPDK_DEBUGLOG(scsi, "PR OUT RELEASE: rkey 0x%"PRIx64", "
     311                 :            :                       "reservation type %u\n", rkey, rtype);
     312                 :            : 
     313                 :          8 :         reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
     314         [ -  + ]:          8 :         if (!reg) {
     315                 :          0 :                 SPDK_ERRLOG("No registration\n");
     316                 :          0 :                 sk = SPDK_SCSI_SENSE_NOT_READY;
     317                 :          0 :                 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
     318                 :          0 :                 goto check_condition;
     319                 :            :         }
     320                 :            : 
     321                 :            :         /* no reservation holder */
     322         [ -  + ]:          8 :         if (!scsi_pr_has_reservation(lun)) {
     323   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(scsi, "RELEASE: no reservation holder\n");
     324                 :          0 :                 return 0;
     325                 :            :         }
     326                 :            : 
     327   [ +  -  -  + ]:          8 :         if (lun->reservation.rtype != rtype || rkey != lun->reservation.crkey) {
     328                 :          0 :                 sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
     329                 :          0 :                 asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB;
     330                 :          0 :                 goto check_condition;
     331                 :            :         }
     332                 :            : 
     333                 :            :         /* I_T nexus is not a persistent reservation holder */
     334         [ -  + ]:          8 :         if (!scsi_pr_registrant_is_holder(lun, reg)) {
     335   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(scsi, "RELEASE: current I_T nexus is not holder\n");
     336                 :          0 :                 return 0;
     337                 :            :         }
     338                 :            : 
     339                 :          8 :         scsi_pr_release_reservation(lun, reg);
     340                 :            : 
     341                 :          8 :         return 0;
     342                 :            : 
     343                 :          0 : check_condition:
     344                 :          0 :         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, sk, asc,
     345                 :            :                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     346                 :          0 :         return -EINVAL;
     347                 :            : }
     348                 :            : 
     349                 :            : static int
     350                 :          0 : scsi_pr_out_clear(struct spdk_scsi_task *task, uint64_t rkey)
     351                 :            : {
     352                 :          0 :         struct spdk_scsi_lun *lun = task->lun;
     353                 :            :         struct spdk_scsi_pr_registrant *reg, *tmp;
     354                 :            :         int sc, sk, asc;
     355                 :            : 
     356   [ #  #  #  # ]:          0 :         SPDK_DEBUGLOG(scsi, "PR OUT CLEAR: rkey 0x%"PRIx64"\n", rkey);
     357                 :            : 
     358                 :          0 :         reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
     359         [ #  # ]:          0 :         if (!reg) {
     360                 :          0 :                 SPDK_ERRLOG("No registration\n");
     361                 :          0 :                 sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
     362                 :          0 :                 sk = SPDK_SCSI_SENSE_NOT_READY;
     363                 :          0 :                 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
     364                 :          0 :                 goto error_exit;
     365                 :            :         }
     366                 :            : 
     367         [ #  # ]:          0 :         if (rkey != reg->rkey) {
     368                 :          0 :                 SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match "
     369                 :            :                             "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
     370                 :          0 :                 sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
     371                 :          0 :                 sk = SPDK_SCSI_SENSE_NO_SENSE;
     372                 :          0 :                 asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
     373                 :          0 :                 goto error_exit;
     374                 :            :         }
     375                 :            : 
     376         [ #  # ]:          0 :         TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
     377                 :          0 :                 scsi_pr_unregister_registrant(lun, reg);
     378                 :            :         }
     379                 :            : 
     380                 :          0 :         return 0;
     381                 :            : 
     382                 :          0 : error_exit:
     383                 :          0 :         spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     384                 :          0 :         return -EINVAL;
     385                 :            : }
     386                 :            : 
     387                 :            : static void
     388                 :         12 : scsi_pr_remove_all_regs_by_key(struct spdk_scsi_lun *lun, uint64_t sa_rkey)
     389                 :            : {
     390                 :            :         struct spdk_scsi_pr_registrant *reg, *tmp;
     391                 :            : 
     392         [ +  + ]:         44 :         TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
     393         [ +  + ]:         32 :                 if (reg->rkey == sa_rkey) {
     394                 :         12 :                         scsi_pr_unregister_registrant(lun, reg);
     395                 :            :                 }
     396                 :            :         }
     397                 :         12 : }
     398                 :            : 
     399                 :            : static void
     400                 :          4 : scsi_pr_remove_all_other_regs(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg)
     401                 :            : {
     402                 :            :         struct spdk_scsi_pr_registrant *reg_tmp, *reg_tmp2;
     403                 :            : 
     404         [ +  + ]:         12 :         TAILQ_FOREACH_SAFE(reg_tmp, &lun->reg_head, link, reg_tmp2) {
     405         [ +  + ]:          8 :                 if (reg_tmp != reg) {
     406                 :          4 :                         scsi_pr_unregister_registrant(lun, reg_tmp);
     407                 :            :                 }
     408                 :            :         }
     409                 :          4 : }
     410                 :            : 
     411                 :            : static int
     412                 :         28 : scsi_pr_out_preempt(struct spdk_scsi_task *task,
     413                 :            :                     enum spdk_scsi_pr_out_service_action_code action,
     414                 :            :                     enum spdk_scsi_pr_type_code rtype,
     415                 :            :                     uint64_t rkey, uint64_t sa_rkey)
     416                 :            : {
     417                 :         28 :         struct spdk_scsi_lun *lun = task->lun;
     418                 :            :         struct spdk_scsi_pr_registrant *reg;
     419                 :         28 :         bool all_regs = false;
     420                 :            : 
     421   [ -  +  -  + ]:         28 :         SPDK_DEBUGLOG(scsi, "PR OUT PREEMPT: rkey 0x%"PRIx64", sa_rkey 0x%"PRIx64" "
     422                 :            :                       "action %u, type %u, reservation type %u\n",
     423                 :            :                       rkey, sa_rkey, action, rtype, lun->reservation.rtype);
     424                 :            : 
     425                 :            :         /* I_T nexus is not registered */
     426                 :         28 :         reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
     427         [ -  + ]:         28 :         if (!reg) {
     428                 :          0 :                 SPDK_ERRLOG("No registration\n");
     429                 :          0 :                 goto conflict;
     430                 :            :         }
     431         [ -  + ]:         28 :         if (rkey != reg->rkey) {
     432                 :          0 :                 SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match "
     433                 :            :                             "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
     434                 :          0 :                 goto conflict;
     435                 :            :         }
     436                 :            : 
     437                 :            :         /* no persistent reservation */
     438         [ +  + ]:         28 :         if (!scsi_pr_has_reservation(lun)) {
     439                 :          4 :                 scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
     440   [ -  +  -  + ]:          4 :                 SPDK_DEBUGLOG(scsi, "PREEMPT: no persistent reservation\n");
     441                 :          4 :                 goto exit;
     442                 :            :         }
     443                 :            : 
     444                 :         24 :         all_regs = scsi_pr_is_all_registrants_type(lun);
     445                 :            : 
     446         [ +  + ]:         24 :         if (all_regs) {
     447         [ -  + ]:          4 :                 if (sa_rkey != 0) {
     448                 :          0 :                         scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
     449   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(scsi, "PREEMPT: All registrants type with sa_rkey\n");
     450                 :            :                 } else {
     451                 :            :                         /* remove all other registrants and release persistent reservation if any */
     452                 :          4 :                         scsi_pr_remove_all_other_regs(lun, reg);
     453                 :            :                         /* create persistent reservation using new type and scope */
     454                 :          4 :                         scsi_pr_reserve_reservation(lun, rtype, 0, reg);
     455   [ -  +  -  + ]:          4 :                         SPDK_DEBUGLOG(scsi, "PREEMPT: All registrants type with sa_rkey zeroed\n");
     456                 :            :                 }
     457                 :          4 :                 goto exit;
     458                 :            :         }
     459                 :            : 
     460         [ -  + ]:         20 :         assert(lun->reservation.crkey != 0);
     461                 :            : 
     462         [ +  + ]:         20 :         if (sa_rkey != lun->reservation.crkey) {
     463         [ +  + ]:          8 :                 if (!sa_rkey) {
     464                 :          4 :                         SPDK_ERRLOG("Zeroed sa_rkey\n");
     465                 :          4 :                         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
     466                 :            :                                                   SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
     467                 :            :                                                   SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
     468                 :            :                                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     469                 :          4 :                         return -EINVAL;
     470                 :            :                 }
     471                 :          4 :                 scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
     472                 :          4 :                 goto exit;
     473                 :            :         }
     474                 :            : 
     475         [ +  + ]:         12 :         if (scsi_pr_registrant_is_holder(lun, reg)) {
     476                 :          8 :                 scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
     477   [ -  +  -  + ]:          8 :                 SPDK_DEBUGLOG(scsi, "PREEMPT: preempt itself with type %u\n", rtype);
     478                 :          8 :                 goto exit;
     479                 :            :         }
     480                 :            : 
     481                 :            :         /* unregister registrants if any */
     482                 :          4 :         scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
     483                 :          4 :         reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
     484         [ -  + ]:          4 :         if (!reg) {
     485                 :          0 :                 SPDK_ERRLOG("Current I_T nexus registrant was removed\n");
     486                 :          0 :                 goto conflict;
     487                 :            :         }
     488                 :            : 
     489                 :            :         /* preempt the holder */
     490                 :          4 :         scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
     491                 :            : 
     492                 :         24 : exit:
     493                 :         24 :         lun->pr_generation++;
     494                 :         24 :         return 0;
     495                 :            : 
     496                 :          0 : conflict:
     497                 :          0 :         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
     498                 :            :                                   SPDK_SCSI_SENSE_NO_SENSE,
     499                 :            :                                   SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
     500                 :            :                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     501                 :          0 :         return -EINVAL;
     502                 :            : }
     503                 :            : 
     504                 :            : int
     505                 :          0 : scsi_pr_out(struct spdk_scsi_task *task, uint8_t *cdb,
     506                 :            :             uint8_t *data, uint16_t data_len)
     507                 :            : {
     508                 :          0 :         int rc = -1;
     509                 :            :         uint64_t rkey, sa_rkey;
     510                 :            :         uint8_t spec_i_pt, all_tg_pt, aptpl;
     511                 :            :         enum spdk_scsi_pr_out_service_action_code action;
     512                 :            :         enum spdk_scsi_pr_scope_code scope;
     513                 :            :         enum spdk_scsi_pr_type_code rtype;
     514                 :          0 :         struct spdk_scsi_pr_out_param_list *param = (struct spdk_scsi_pr_out_param_list *)data;
     515                 :            : 
     516                 :          0 :         action = cdb[1] & 0x0f;
     517                 :          0 :         scope = (cdb[2] >> 4) & 0x0f;
     518                 :          0 :         rtype = cdb[2] & 0x0f;
     519                 :            : 
     520                 :          0 :         rkey = from_be64(&param->rkey);
     521                 :          0 :         sa_rkey = from_be64(&param->sa_rkey);
     522                 :          0 :         aptpl = param->aptpl;
     523                 :          0 :         spec_i_pt = param->spec_i_pt;
     524                 :          0 :         all_tg_pt = param->all_tg_pt;
     525                 :            : 
     526   [ #  #  #  #  :          0 :         switch (action) {
                   #  # ]
     527                 :          0 :         case SPDK_SCSI_PR_OUT_REGISTER:
     528                 :            :         case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY:
     529                 :          0 :                 rc = scsi_pr_out_register(task, action, rkey, sa_rkey,
     530                 :            :                                           spec_i_pt, all_tg_pt, aptpl);
     531                 :          0 :                 break;
     532                 :          0 :         case SPDK_SCSI_PR_OUT_RESERVE:
     533         [ #  # ]:          0 :                 if (scope != SPDK_SCSI_PR_LU_SCOPE) {
     534                 :          0 :                         goto invalid;
     535                 :            :                 }
     536                 :          0 :                 rc = scsi_pr_out_reserve(task, rtype, rkey,
     537                 :            :                                          spec_i_pt, all_tg_pt, aptpl);
     538                 :          0 :                 break;
     539                 :          0 :         case SPDK_SCSI_PR_OUT_RELEASE:
     540         [ #  # ]:          0 :                 if (scope != SPDK_SCSI_PR_LU_SCOPE) {
     541                 :          0 :                         goto invalid;
     542                 :            :                 }
     543                 :          0 :                 rc = scsi_pr_out_release(task, rtype, rkey);
     544                 :          0 :                 break;
     545                 :          0 :         case SPDK_SCSI_PR_OUT_CLEAR:
     546                 :          0 :                 rc = scsi_pr_out_clear(task, rkey);
     547                 :          0 :                 break;
     548                 :          0 :         case SPDK_SCSI_PR_OUT_PREEMPT:
     549         [ #  # ]:          0 :                 if (scope != SPDK_SCSI_PR_LU_SCOPE) {
     550                 :          0 :                         goto invalid;
     551                 :            :                 }
     552                 :          0 :                 rc = scsi_pr_out_preempt(task, action, rtype, rkey, sa_rkey);
     553                 :          0 :                 break;
     554                 :          0 :         default:
     555                 :          0 :                 SPDK_ERRLOG("Invalid service action code %u\n", action);
     556                 :          0 :                 goto invalid;
     557                 :            :         }
     558                 :            : 
     559                 :          0 :         return rc;
     560                 :            : 
     561                 :          0 : invalid:
     562                 :          0 :         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
     563                 :            :                                   SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
     564                 :            :                                   SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
     565                 :            :                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     566                 :          0 :         return -EINVAL;
     567                 :            : }
     568                 :            : 
     569                 :            : static int
     570                 :          0 : scsi_pr_in_read_keys(struct spdk_scsi_task *task, uint8_t *data,
     571                 :            :                      uint16_t data_len)
     572                 :            : {
     573                 :          0 :         struct spdk_scsi_lun *lun = task->lun;
     574                 :            :         struct spdk_scsi_pr_in_read_keys_data *keys;
     575                 :            :         struct spdk_scsi_pr_registrant *reg, *tmp;
     576                 :          0 :         uint16_t count = 0;
     577                 :            : 
     578   [ #  #  #  # ]:          0 :         SPDK_DEBUGLOG(scsi, "PR IN READ KEYS\n");
     579                 :          0 :         keys = (struct spdk_scsi_pr_in_read_keys_data *)data;
     580                 :            : 
     581                 :          0 :         to_be32(&keys->header.pr_generation, lun->pr_generation);
     582         [ #  # ]:          0 :         TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
     583         [ #  # ]:          0 :                 if (((count + 1) * 8 + sizeof(keys->header)) > data_len) {
     584                 :          0 :                         break;
     585                 :            :                 }
     586                 :          0 :                 to_be64(&keys->rkeys[count], reg->rkey);
     587                 :          0 :                 count++;
     588                 :            :         }
     589                 :          0 :         to_be32(&keys->header.additional_len, count * 8);
     590                 :            : 
     591                 :          0 :         return (sizeof(keys->header) + count * 8);
     592                 :            : }
     593                 :            : 
     594                 :            : static int
     595                 :          0 : scsi_pr_in_read_reservations(struct spdk_scsi_task *task,
     596                 :            :                              uint8_t *data, uint16_t data_len)
     597                 :            : {
     598                 :          0 :         struct spdk_scsi_lun *lun = task->lun;
     599                 :            :         struct spdk_scsi_pr_in_read_reservations_data *param;
     600                 :          0 :         bool all_regs = false;
     601                 :            : 
     602   [ #  #  #  # ]:          0 :         SPDK_DEBUGLOG(scsi, "PR IN READ RESERVATIONS\n");
     603                 :          0 :         param = (struct spdk_scsi_pr_in_read_reservations_data *)(data);
     604                 :            : 
     605                 :          0 :         to_be32(&param->header.pr_generation, lun->pr_generation);
     606         [ #  # ]:          0 :         if (scsi_pr_has_reservation(lun)) {
     607                 :          0 :                 all_regs = scsi_pr_is_all_registrants_type(lun);
     608         [ #  # ]:          0 :                 if (all_regs) {
     609                 :          0 :                         to_be64(&param->rkey, 0);
     610                 :            :                 } else {
     611                 :          0 :                         to_be64(&param->rkey, lun->reservation.crkey);
     612                 :            :                 }
     613                 :          0 :                 to_be32(&param->header.additional_len, 16);
     614                 :          0 :                 param->scope = SPDK_SCSI_PR_LU_SCOPE;
     615                 :          0 :                 param->type = lun->reservation.rtype;
     616   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(scsi, "READ RESERVATIONS with valid reservation\n");
     617                 :          0 :                 return sizeof(*param);
     618                 :            :         }
     619                 :            : 
     620                 :            :         /* no reservation */
     621                 :          0 :         to_be32(&param->header.additional_len, 0);
     622   [ #  #  #  # ]:          0 :         SPDK_DEBUGLOG(scsi, "READ RESERVATIONS no reservation\n");
     623                 :          0 :         return sizeof(param->header);
     624                 :            : }
     625                 :            : 
     626                 :            : static int
     627                 :          0 : scsi_pr_in_report_capabilities(struct spdk_scsi_task *task,
     628                 :            :                                uint8_t *data, uint16_t data_len)
     629                 :            : {
     630                 :            :         struct spdk_scsi_pr_in_report_capabilities_data *param;
     631                 :            : 
     632   [ #  #  #  # ]:          0 :         SPDK_DEBUGLOG(scsi, "PR IN REPORT CAPABILITIES\n");
     633                 :          0 :         param = (struct spdk_scsi_pr_in_report_capabilities_data *)data;
     634                 :            : 
     635         [ #  # ]:          0 :         memset(param, 0, sizeof(*param));
     636                 :          0 :         to_be16(&param->length, sizeof(*param));
     637                 :            :         /* Compatible reservation handling to support RESERVE/RELEASE defined in SPC-2 */
     638                 :          0 :         param->crh = 1;
     639                 :          0 :         param->tmv = 1;
     640                 :          0 :         param->wr_ex = 1;
     641                 :          0 :         param->ex_ac = 1;
     642                 :          0 :         param->wr_ex_ro = 1;
     643                 :          0 :         param->ex_ac_ro = 1;
     644                 :          0 :         param->wr_ex_ar = 1;
     645                 :          0 :         param->ex_ac_ar = 1;
     646                 :            : 
     647                 :          0 :         return sizeof(*param);
     648                 :            : }
     649                 :            : 
     650                 :            : static int
     651                 :          0 : scsi_pr_in_read_full_status(struct spdk_scsi_task *task,
     652                 :            :                             uint8_t *data, uint16_t data_len)
     653                 :            : {
     654                 :          0 :         struct spdk_scsi_lun *lun = task->lun;
     655                 :            :         struct spdk_scsi_pr_in_full_status_data *param;
     656                 :            :         struct spdk_scsi_pr_in_full_status_desc *desc;
     657                 :            :         struct spdk_scsi_pr_registrant *reg, *tmp;
     658                 :          0 :         bool all_regs = false;
     659                 :          0 :         uint32_t add_len = 0;
     660                 :            : 
     661   [ #  #  #  # ]:          0 :         SPDK_DEBUGLOG(scsi, "PR IN READ FULL STATUS\n");
     662                 :            : 
     663                 :          0 :         all_regs = scsi_pr_is_all_registrants_type(lun);
     664                 :          0 :         param = (struct spdk_scsi_pr_in_full_status_data *)data;
     665                 :          0 :         to_be32(&param->header.pr_generation, lun->pr_generation);
     666                 :            : 
     667         [ #  # ]:          0 :         TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
     668                 :          0 :                 desc = (struct spdk_scsi_pr_in_full_status_desc *)
     669                 :          0 :                        ((uint8_t *)param->desc_list + add_len);
     670         [ #  # ]:          0 :                 if (add_len + sizeof(*desc) + sizeof(param->header) > data_len) {
     671                 :          0 :                         break;
     672                 :            :                 }
     673                 :          0 :                 add_len += sizeof(*desc);
     674                 :          0 :                 desc->rkey = reg->rkey;
     675   [ #  #  #  # ]:          0 :                 if (all_regs || lun->reservation.holder == reg) {
     676                 :          0 :                         desc->r_holder = true;
     677                 :          0 :                         desc->type = lun->reservation.rtype;
     678                 :            :                 } else {
     679                 :          0 :                         desc->r_holder = false;
     680                 :          0 :                         desc->type = 0;
     681                 :            :                 }
     682                 :          0 :                 desc->all_tg_pt = 0;
     683                 :          0 :                 desc->scope = SPDK_SCSI_PR_LU_SCOPE;
     684                 :          0 :                 desc->relative_target_port_id = reg->relative_target_port_id;
     685         [ #  # ]:          0 :                 if (add_len + reg->transport_id_len + sizeof(param->header) > data_len) {
     686                 :          0 :                         break;
     687                 :            :                 }
     688                 :          0 :                 add_len += reg->transport_id_len;
     689   [ #  #  #  # ]:          0 :                 memcpy(&desc->transport_id, reg->transport_id, reg->transport_id_len);
     690                 :          0 :                 to_be32(&desc->desc_len, reg->transport_id_len);
     691                 :            :         }
     692                 :          0 :         to_be32(&param->header.additional_len, add_len);
     693                 :            : 
     694                 :          0 :         return (sizeof(param->header) + add_len);
     695                 :            : }
     696                 :            : 
     697                 :            : int
     698                 :          0 : scsi_pr_in(struct spdk_scsi_task *task, uint8_t *cdb,
     699                 :            :            uint8_t *data, uint16_t data_len)
     700                 :            : {
     701                 :            :         enum spdk_scsi_pr_in_action_code action;
     702                 :          0 :         int rc = 0;
     703                 :            : 
     704                 :          0 :         action = cdb[1] & 0x1f;
     705         [ #  # ]:          0 :         if (data_len < sizeof(struct spdk_scsi_pr_in_read_header)) {
     706                 :          0 :                 goto invalid;
     707                 :            :         }
     708                 :            : 
     709   [ #  #  #  #  :          0 :         switch (action) {
                      # ]
     710                 :          0 :         case SPDK_SCSI_PR_IN_READ_KEYS:
     711                 :          0 :                 rc = scsi_pr_in_read_keys(task, data, data_len);
     712                 :          0 :                 break;
     713                 :          0 :         case SPDK_SCSI_PR_IN_READ_RESERVATION:
     714         [ #  # ]:          0 :                 if (data_len < sizeof(struct spdk_scsi_pr_in_read_reservations_data)) {
     715                 :          0 :                         goto invalid;
     716                 :            :                 }
     717                 :          0 :                 rc = scsi_pr_in_read_reservations(task, data, data_len);
     718                 :          0 :                 break;
     719                 :          0 :         case SPDK_SCSI_PR_IN_REPORT_CAPABILITIES:
     720                 :          0 :                 rc = scsi_pr_in_report_capabilities(task, data, data_len);
     721                 :          0 :                 break;
     722                 :          0 :         case SPDK_SCSI_PR_IN_READ_FULL_STATUS:
     723                 :          0 :                 rc = scsi_pr_in_read_full_status(task, data, data_len);
     724                 :          0 :                 break;
     725                 :          0 :         default:
     726                 :          0 :                 goto invalid;
     727                 :            :         }
     728                 :            : 
     729                 :          0 :         return rc;
     730                 :            : 
     731                 :          0 : invalid:
     732                 :          0 :         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
     733                 :            :                                   SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
     734                 :            :                                   SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
     735                 :            :                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     736                 :          0 :         return -EINVAL;
     737                 :            : }
     738                 :            : 
     739                 :            : int
     740                 :   29563626 : scsi_pr_check(struct spdk_scsi_task *task)
     741                 :            : {
     742                 :   29563626 :         struct spdk_scsi_lun *lun = task->lun;
     743                 :   29563626 :         uint8_t *cdb = task->cdb;
     744                 :            :         enum spdk_scsi_pr_type_code rtype;
     745                 :            :         enum spdk_scsi_pr_out_service_action_code action;
     746                 :            :         struct spdk_scsi_pr_registrant *reg;
     747                 :   29563626 :         bool dma_to_device = false;
     748                 :            : 
     749                 :            :         /* no reservation holders */
     750         [ +  + ]:   29563626 :         if (!scsi_pr_has_reservation(lun)) {
     751                 :   29563574 :                 return 0;
     752                 :            :         }
     753                 :            : 
     754                 :         52 :         rtype = lun->reservation.rtype;
     755         [ -  + ]:         52 :         assert(rtype != 0);
     756                 :            : 
     757                 :         52 :         reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
     758                 :            :         /* current I_T nexus hold the reservation */
     759         [ +  + ]:         52 :         if (scsi_pr_registrant_is_holder(lun, reg)) {
     760                 :          8 :                 return 0;
     761                 :            :         }
     762                 :            : 
     763                 :            :         /* reservation is held by other I_T nexus */
     764   [ +  -  -  + ]:         44 :         switch (cdb[0]) {
     765                 :          4 :         case SPDK_SPC_INQUIRY:
     766                 :            :         case SPDK_SPC_REPORT_LUNS:
     767                 :            :         case SPDK_SPC_REQUEST_SENSE:
     768                 :            :         case SPDK_SPC_LOG_SENSE:
     769                 :            :         case SPDK_SPC_TEST_UNIT_READY:
     770                 :            :         case SPDK_SBC_START_STOP_UNIT:
     771                 :            :         case SPDK_SBC_READ_CAPACITY_10:
     772                 :            :         case SPDK_SPC_PERSISTENT_RESERVE_IN:
     773                 :            :         case SPDK_SPC_SERVICE_ACTION_IN_16:
     774                 :            :         /* CRH enabled, processed by scsi2_reserve() */
     775                 :            :         case SPDK_SPC2_RESERVE_6:
     776                 :            :         case SPDK_SPC2_RESERVE_10:
     777                 :            :         /* CRH enabled, processed by scsi2_release() */
     778                 :            :         case SPDK_SPC2_RELEASE_6:
     779                 :            :         case SPDK_SPC2_RELEASE_10:
     780                 :          4 :                 return 0;
     781                 :          0 :         case SPDK_SPC_MODE_SELECT_6:
     782                 :            :         case SPDK_SPC_MODE_SELECT_10:
     783                 :            :         case SPDK_SPC_MODE_SENSE_6:
     784                 :            :         case SPDK_SPC_MODE_SENSE_10:
     785                 :            :         case SPDK_SPC_LOG_SELECT:
     786                 :            :                 /* I_T nexus is registrant but not holder */
     787         [ #  # ]:          0 :                 if (!reg) {
     788   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(scsi, "CHECK: current I_T nexus "
     789                 :            :                                       "is not registered, cdb 0x%x\n", cdb[0]);
     790                 :          0 :                         goto conflict;
     791                 :            :                 }
     792                 :          0 :                 return 0;
     793                 :          0 :         case SPDK_SPC_PERSISTENT_RESERVE_OUT:
     794                 :          0 :                 action = cdb[1] & 0x1f;
     795   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(scsi, "CHECK: PR OUT action %u\n", action);
     796   [ #  #  #  # ]:          0 :                 switch (action) {
     797                 :          0 :                 case SPDK_SCSI_PR_OUT_RELEASE:
     798                 :            :                 case SPDK_SCSI_PR_OUT_CLEAR:
     799                 :            :                 case SPDK_SCSI_PR_OUT_PREEMPT:
     800                 :            :                 case SPDK_SCSI_PR_OUT_PREEMPT_AND_ABORT:
     801         [ #  # ]:          0 :                         if (!reg) {
     802                 :          0 :                                 SPDK_ERRLOG("CHECK: PR OUT action %u\n", action);
     803                 :          0 :                                 goto conflict;
     804                 :            :                         }
     805                 :          0 :                         return 0;
     806                 :          0 :                 case SPDK_SCSI_PR_OUT_REGISTER:
     807                 :            :                 case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY:
     808                 :          0 :                         return 0;
     809                 :          0 :                 case SPDK_SCSI_PR_OUT_REG_AND_MOVE:
     810                 :          0 :                         SPDK_ERRLOG("CHECK: PR OUT action %u\n", action);
     811                 :          0 :                         goto conflict;
     812                 :          0 :                 default:
     813                 :          0 :                         SPDK_ERRLOG("CHECK: PR OUT invalid action %u\n", action);
     814                 :          0 :                         goto conflict;
     815                 :            :                 }
     816                 :            : 
     817                 :            :         /* For most SBC R/W commands */
     818                 :         40 :         default:
     819                 :         40 :                 break;
     820                 :            :         }
     821                 :            : 
     822      [ +  +  - ]:         40 :         switch (cdb[0]) {
     823                 :         20 :         case SPDK_SBC_READ_6:
     824                 :            :         case SPDK_SBC_READ_10:
     825                 :            :         case SPDK_SBC_READ_12:
     826                 :            :         case SPDK_SBC_READ_16:
     827                 :         20 :                 break;
     828                 :         20 :         case SPDK_SBC_WRITE_6:
     829                 :            :         case SPDK_SBC_WRITE_10:
     830                 :            :         case SPDK_SBC_WRITE_12:
     831                 :            :         case SPDK_SBC_WRITE_16:
     832                 :            :         case SPDK_SBC_UNMAP:
     833                 :            :         case SPDK_SBC_SYNCHRONIZE_CACHE_10:
     834                 :            :         case SPDK_SBC_SYNCHRONIZE_CACHE_16:
     835                 :         20 :                 dma_to_device = true;
     836                 :         20 :                 break;
     837                 :          0 :         default:
     838                 :          0 :                 SPDK_ERRLOG("CHECK: unsupported SCSI command cdb 0x%x\n", cdb[0]);
     839                 :          0 :                 goto conflict;
     840                 :            :         }
     841                 :            : 
     842   [ -  +  +  +  :         40 :         switch (rtype) {
                      - ]
     843                 :          0 :         case SPDK_SCSI_PR_WRITE_EXCLUSIVE:
     844         [ #  # ]:          0 :                 if (dma_to_device) {
     845                 :          0 :                         SPDK_ERRLOG("CHECK: Write Exclusive reservation type "
     846                 :            :                                     "rejects command 0x%x\n", cdb[0]);
     847                 :          0 :                         goto conflict;
     848                 :            :                 }
     849                 :          0 :                 break;
     850                 :         16 :         case SPDK_SCSI_PR_EXCLUSIVE_ACCESS:
     851                 :         16 :                 SPDK_ERRLOG("CHECK: Exclusive Access reservation type "
     852                 :            :                             "rejects command 0x%x\n", cdb[0]);
     853                 :         16 :                 goto conflict;
     854                 :         16 :         case SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY:
     855                 :            :         case SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS:
     856   [ +  +  +  + ]:         16 :                 if (!reg && dma_to_device) {
     857                 :          4 :                         SPDK_ERRLOG("CHECK: Registrants only reservation "
     858                 :            :                                     "type  reject command 0x%x\n", cdb[0]);
     859                 :          4 :                         goto conflict;
     860                 :            :                 }
     861                 :         12 :                 break;
     862                 :          8 :         case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY:
     863                 :            :         case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS:
     864         [ +  - ]:          8 :                 if (!reg) {
     865                 :          8 :                         SPDK_ERRLOG("CHECK: All Registrants reservation "
     866                 :            :                                     "type  reject command 0x%x\n", cdb[0]);
     867                 :          8 :                         goto conflict;
     868                 :            :                 }
     869                 :          0 :                 break;
     870                 :          0 :         default:
     871                 :          0 :                 break;
     872                 :            :         }
     873                 :            : 
     874                 :         12 :         return 0;
     875                 :            : 
     876                 :         28 : conflict:
     877                 :         28 :         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
     878                 :            :                                   SPDK_SCSI_SENSE_NO_SENSE,
     879                 :            :                                   SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
     880                 :            :                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     881                 :         28 :         return -1;
     882                 :            : }
     883                 :            : 
     884                 :            : static int
     885                 :         28 : scsi2_check_reservation_conflict(struct spdk_scsi_task *task)
     886                 :            : {
     887                 :         28 :         struct spdk_scsi_lun *lun = task->lun;
     888                 :            :         struct spdk_scsi_pr_registrant *reg;
     889                 :         28 :         bool conflict = false;
     890                 :            : 
     891                 :         28 :         reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
     892         [ +  + ]:         28 :         if (reg) {
     893                 :            :                 /*
     894                 :            :                  * From spc4r31 5.9.3 Exceptions to SPC-2 RESERVE and RELEASE
     895                 :            :                  * behavior
     896                 :            :                  *
     897                 :            :                  * A RESERVE(6) or RESERVE(10) command shall complete with GOOD
     898                 :            :                  * status, but no reservation shall be established and the
     899                 :            :                  * persistent reservation shall not be changed, if the command
     900                 :            :                  * is received from a) and b) below.
     901                 :            :                  *
     902                 :            :                  * A RELEASE(6) or RELEASE(10) command shall complete with GOOD
     903                 :            :                  * status, but the persistent reservation shall not be released,
     904                 :            :                  * if the command is received from a) and b)
     905                 :            :                  *
     906                 :            :                  * a) An I_T nexus that is a persistent reservation holder; or
     907                 :            :                  * b) An I_T nexus that is registered if a registrants only or
     908                 :            :                  *    all registrants type persistent reservation is present.
     909                 :            :                  *
     910                 :            :                  * In all other cases, a RESERVE(6) command, RESERVE(10) command,
     911                 :            :                  * RELEASE(6) command, or RELEASE(10) command shall be processed
     912                 :            :                  * as defined in SPC-2.
     913                 :            :                  */
     914         [ -  + ]:          8 :                 if (scsi_pr_registrant_is_holder(lun, reg)) {
     915                 :          0 :                         return 1;
     916                 :            :                 }
     917                 :            : 
     918         [ -  + ]:          8 :                 if (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY ||
     919         [ #  # ]:          0 :                     lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY) {
     920                 :          8 :                         return 1;
     921                 :            :                 }
     922                 :            : 
     923                 :          0 :                 conflict = true;
     924                 :            :         } else {
     925                 :            :                 /*
     926                 :            :                  * From spc2r20 5.5.1 Reservations overview:
     927                 :            :                  *
     928                 :            :                  * If a logical unit has executed a PERSISTENT RESERVE OUT
     929                 :            :                  * command with the REGISTER or the REGISTER AND IGNORE
     930                 :            :                  * EXISTING KEY service action and is still registered by any
     931                 :            :                  * initiator, all RESERVE commands and all RELEASE commands
     932                 :            :                  * regardless of initiator shall conflict and shall terminate
     933                 :            :                  * with a RESERVATION CONFLICT status.
     934                 :            :                  */
     935                 :         20 :                 conflict = TAILQ_EMPTY(&lun->reg_head) ? false : true;
     936                 :            :         }
     937                 :            : 
     938         [ -  + ]:         20 :         if (conflict) {
     939                 :          0 :                 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
     940                 :            :                                           SPDK_SCSI_SENSE_NO_SENSE,
     941                 :            :                                           SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
     942                 :            :                                           SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     943                 :          0 :                 return -1;
     944                 :            :         }
     945                 :            : 
     946                 :         20 :         return 0;
     947                 :            : }
     948                 :            : 
     949                 :            : int
     950                 :         12 : scsi2_reserve(struct spdk_scsi_task *task, uint8_t *cdb)
     951                 :            : {
     952                 :         12 :         struct spdk_scsi_lun *lun = task->lun;
     953                 :         12 :         struct spdk_scsi_pr_registrant *reg = &lun->scsi2_holder;
     954                 :            :         int ret;
     955                 :            : 
     956                 :            :         /* Obsolete Bits and LongID set, returning ILLEGAL_REQUEST */
     957         [ -  + ]:         12 :         if (cdb[1] & 0x3) {
     958                 :          0 :                 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
     959                 :            :                                           SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
     960                 :            :                                           SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
     961                 :            :                                           SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     962                 :          0 :                 return -1;
     963                 :            :         }
     964                 :            : 
     965                 :         12 :         ret = scsi2_check_reservation_conflict(task);
     966                 :            :         /* PERSISTENT RESERVE is enabled */
     967         [ +  + ]:         12 :         if (ret == 1) {
     968                 :          4 :                 return 0;
     969         [ -  + ]:          8 :         } else if (ret < 0) {
     970                 :          0 :                 return ret;
     971                 :            :         }
     972                 :            : 
     973                 :            :         /* SPC2 RESERVE */
     974                 :          8 :         reg->initiator_port = task->initiator_port;
     975         [ +  - ]:          8 :         if (task->initiator_port) {
     976         [ -  + ]:          8 :                 snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s",
     977                 :          8 :                          task->initiator_port->name);
     978                 :          8 :                 reg->transport_id_len = task->initiator_port->transport_id_len;
     979   [ -  +  -  + ]:          8 :                 memcpy(reg->transport_id, task->initiator_port->transport_id,
     980                 :          8 :                        reg->transport_id_len);
     981                 :            :         }
     982                 :          8 :         reg->target_port = task->target_port;
     983         [ +  - ]:          8 :         if (task->target_port) {
     984         [ -  + ]:          8 :                 snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s",
     985                 :          8 :                          task->target_port->name);
     986                 :            :         }
     987                 :            : 
     988                 :          8 :         lun->reservation.flags = SCSI_SPC2_RESERVE;
     989                 :          8 :         lun->reservation.holder = &lun->scsi2_holder;
     990                 :            : 
     991                 :          8 :         return 0;
     992                 :            : }
     993                 :            : 
     994                 :            : int
     995                 :         16 : scsi2_release(struct spdk_scsi_task *task)
     996                 :            : {
     997                 :         16 :         struct spdk_scsi_lun *lun = task->lun;
     998                 :            :         int ret;
     999                 :            : 
    1000                 :         16 :         ret = scsi2_check_reservation_conflict(task);
    1001                 :            :         /* PERSISTENT RESERVE is enabled */
    1002         [ +  + ]:         16 :         if (ret == 1) {
    1003                 :          4 :                 return 0;
    1004         [ -  + ]:         12 :         } else if (ret < 0) {
    1005                 :          0 :                 return ret;
    1006                 :            :         }
    1007                 :            : 
    1008         [ +  + ]:         12 :         if (!(lun->reservation.flags & SCSI_SPC2_RESERVE)) {
    1009                 :          4 :                 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
    1010                 :            :                                           SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
    1011                 :            :                                           SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
    1012                 :            :                                           SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
    1013                 :          4 :                 return -EINVAL;
    1014                 :            :         }
    1015                 :            : 
    1016         [ -  + ]:          8 :         memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation));
    1017         [ -  + ]:          8 :         memset(&lun->scsi2_holder, 0, sizeof(struct spdk_scsi_pr_registrant));
    1018                 :            : 
    1019                 :          8 :         return 0;
    1020                 :            : }
    1021                 :            : 
    1022                 :            : int
    1023                 :         12 : scsi2_reserve_check(struct spdk_scsi_task *task)
    1024                 :            : {
    1025                 :         12 :         struct spdk_scsi_lun *lun = task->lun;
    1026                 :         12 :         uint8_t *cdb = task->cdb;
    1027                 :            : 
    1028         [ +  + ]:         12 :         switch (cdb[0]) {
    1029                 :          4 :         case SPDK_SPC_INQUIRY:
    1030                 :            :         case SPDK_SPC2_RELEASE_6:
    1031                 :            :         case SPDK_SPC2_RELEASE_10:
    1032                 :          4 :                 return 0;
    1033                 :            : 
    1034                 :          8 :         default:
    1035                 :          8 :                 break;
    1036                 :            :         }
    1037                 :            : 
    1038                 :            :         /* no reservation holders */
    1039         [ -  + ]:          8 :         if (!scsi_pr_has_reservation(lun)) {
    1040                 :          0 :                 return 0;
    1041                 :            :         }
    1042                 :            : 
    1043         [ +  + ]:          8 :         if (scsi2_it_nexus_is_holder(lun, task->initiator_port, task->target_port)) {
    1044                 :          4 :                 return 0;
    1045                 :            :         }
    1046                 :            : 
    1047                 :          4 :         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
    1048                 :            :                                   SPDK_SCSI_SENSE_NO_SENSE,
    1049                 :            :                                   SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
    1050                 :            :                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
    1051                 :          4 :         return -1;
    1052                 :            : }

Generated by: LCOV version 1.14