]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
sed-opal: add IOC_OPAL_REACTIVATE_LSP.
authorOndrej Kozina <okozina@redhat.com>
Fri, 6 Feb 2026 14:17:58 +0000 (15:17 +0100)
committerJens Axboe <axboe@kernel.dk>
Mon, 9 Mar 2026 20:29:59 +0000 (14:29 -0600)
This adds the 'Reactivate' method as described in the
"TCG Storage Opal SSC Feature Set: Single User Mode"
document (ch. 3.1.1.1).

The method enables switching an already active SED OPAL2 device,
with appropriate firmware support for Single User Mode (SUM),
to or from SUM.

Signed-off-by: Ondrej Kozina <okozina@redhat.com>
Reviewed-and-tested-by: Milan Broz <gmazyland@gmail.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/opal_proto.h
block/sed-opal.c
include/linux/sed-opal.h
include/uapi/linux/sed-opal.h

index 3ccee5977c1058cf008f35b6566334acb6b9fd51..d138785b819822b45a123ee6d11f9c405ce89bc3 100644 (file)
@@ -155,6 +155,7 @@ enum opal_method {
        OPAL_AUTHENTICATE,
        OPAL_RANDOM,
        OPAL_ERASE,
+       OPAL_REACTIVATE,
 };
 
 enum opal_token {
index 83bee47aa29f62a2f277d46b0586ff42841639c6..5d06f5f433bf920f180ab226972fc9e4c436dea9 100644 (file)
@@ -220,6 +220,8 @@ static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
                { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
        [OPAL_ERASE] =
                { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
+       [OPAL_REACTIVATE] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x01 },
 };
 
 static int end_opal_session_error(struct opal_dev *dev);
@@ -2287,6 +2289,74 @@ static int activate_lsp(struct opal_dev *dev, void *data)
        return finalize_and_send(dev, parse_and_check_status);
 }
 
+static int reactivate_lsp(struct opal_dev *dev, void *data)
+{
+       struct opal_lr_react *opal_react = data;
+       u8 user_lr[OPAL_UID_LENGTH];
+       int err, i;
+
+       err = cmd_start(dev, opaluid[OPAL_THISSP_UID],
+                       opalmethod[OPAL_REACTIVATE]);
+
+       if (err) {
+               pr_debug("Error building Reactivate LockingSP command.\n");
+               return err;
+       }
+
+       /*
+        * If neither 'entire_table' nor 'num_lrs' is set, the device
+        * gets reactivated with SUM disabled. Only Admin1PIN will change
+        * if set.
+        */
+       if (opal_react->entire_table) {
+               /* Entire Locking table (all locking ranges) will be put in SUM. */
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u64(&err, dev, OPAL_SUM_SET_LIST);
+               add_token_bytestring(&err, dev, opaluid[OPAL_LOCKING_TABLE], OPAL_UID_LENGTH);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+       } else if (opal_react->num_lrs) {
+               /* Subset of Locking table (selected locking range(s)) to be put in SUM */
+               err = build_locking_range(user_lr, sizeof(user_lr),
+                                         opal_react->lr[0]);
+               if (err)
+                       return err;
+
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u64(&err, dev, OPAL_SUM_SET_LIST);
+
+               add_token_u8(&err, dev, OPAL_STARTLIST);
+               add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
+               for (i = 1; i < opal_react->num_lrs; i++) {
+                       user_lr[7] = opal_react->lr[i];
+                       add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
+               }
+               add_token_u8(&err, dev, OPAL_ENDLIST);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+       }
+
+       /* Skipping the rangle policy parameter is same as setting its value to zero */
+       if (opal_react->range_policy && (opal_react->num_lrs || opal_react->entire_table)) {
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u64(&err, dev, OPAL_SUM_RANGE_POLICY);
+               add_token_u8(&err, dev, 1);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+       }
+
+       /*
+        * Optional parameter. If set, it changes the Admin1 PIN even when SUM
+        * is being disabled.
+        */
+       if (opal_react->new_admin_key.key_len) {
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u64(&err, dev, OPAL_SUM_ADMIN1_PIN);
+               add_token_bytestring(&err, dev, opal_react->new_admin_key.key,
+                                    opal_react->new_admin_key.key_len);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
 /* Determine if we're in the Manufactured Inactive or Active state */
 static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
 {
@@ -2957,6 +3027,32 @@ static int opal_activate_lsp(struct opal_dev *dev,
        return ret;
 }
 
+static int opal_reactivate_lsp(struct opal_dev *dev,
+                              struct opal_lr_react *opal_lr_react)
+{
+       const struct opal_step active_steps[] = {
+               { start_admin1LSP_opal_session, &opal_lr_react->key },
+               { reactivate_lsp, opal_lr_react },
+               /* No end_opal_session. The controller terminates the session */
+       };
+       int ret;
+
+       /* use either 'entire_table' parameter or set of locking ranges */
+       if (opal_lr_react->num_lrs > OPAL_MAX_LRS ||
+           (opal_lr_react->num_lrs && opal_lr_react->entire_table))
+               return -EINVAL;
+
+       ret = opal_get_key(dev, &opal_lr_react->key);
+       if (ret)
+               return ret;
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev);
+       ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
+       mutex_unlock(&dev->dev_lock);
+
+       return ret;
+}
+
 static int opal_setup_locking_range(struct opal_dev *dev,
                                    struct opal_user_lr_setup *opal_lrs)
 {
@@ -3315,6 +3411,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
        case IOC_OPAL_SET_SID_PW:
                ret = opal_set_new_sid_pw(dev, p);
                break;
+       case IOC_OPAL_REACTIVATE_LSP:
+               ret = opal_reactivate_lsp(dev, p);
+               break;
 
        default:
                break;
index 80f33a93f94437f32964a7979597ad1193d464f5..2ae5e6b0ac2139a77363486e80f80ba0917824a7 100644 (file)
@@ -53,6 +53,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
        case IOC_OPAL_DISCOVERY:
        case IOC_OPAL_REVERT_LSP:
        case IOC_OPAL_SET_SID_PW:
+       case IOC_OPAL_REACTIVATE_LSP:
                return true;
        }
        return false;
index 9025dd5a4f0ff97cb3b2127e79a63ca2a277e9c3..d03e590b6501281e9449798ebacb6b264da763e7 100644 (file)
@@ -74,6 +74,19 @@ struct opal_lr_act {
        __u8 align[2]; /* Align to 8 byte boundary */
 };
 
+struct opal_lr_react {
+       struct opal_key key;
+       struct opal_key new_admin_key; /* Set new Admin1 PIN if key_len is > 0 */
+       __u8 num_lrs; /*
+                      * Configure selected ranges (from lr[]) in SUM.
+                      * If num_lrs > 0 the 'entire_table' must be 0
+                      */
+       __u8 lr[OPAL_MAX_LRS];
+       __u8 range_policy; /* Set RangeStartRangeLengthPolicy parameter */
+       __u8 entire_table; /* Set all locking objects in SUM */
+       __u8 align[4]; /* Align to 8 byte boundary */
+};
+
 struct opal_session_info {
        __u32 sum;
        __u32 who;
@@ -216,5 +229,6 @@ struct opal_revert_lsp {
 #define IOC_OPAL_DISCOVERY          _IOW('p', 239, struct opal_discovery)
 #define IOC_OPAL_REVERT_LSP         _IOW('p', 240, struct opal_revert_lsp)
 #define IOC_OPAL_SET_SID_PW         _IOW('p', 241, struct opal_new_pw)
+#define IOC_OPAL_REACTIVATE_LSP     _IOW('p', 242, struct opal_lr_react)
 
 #endif /* _UAPI_SED_OPAL_H */