Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: sed-opal: Add ioctl to return device status

Provide a mechanism to retrieve basic status information about
the device, including the "supported" flag indicating whether
SED-OPAL is supported. The information returned is from the various
feature descriptors received during the discovery0 step, and so
this ioctl does nothing more than perform the discovery0 step
and then save the information received. See "struct opal_status"
and OPAL_FL_* bits for the status information currently returned.

This is necessary to be able to check whether a device is OPAL
enabled, set up, locked or unlocked from userspace programs
like systemd-cryptsetup and libcryptsetup. Right now we just
have to assume the user 'knows' or blindly attempt setup/lock/unlock
operations.

Signed-off-by: Douglas Miller <dougmill@linux.vnet.ibm.com>
Tested-by: Luca Boccassi <bluca@debian.org>
Reviewed-by: Scott Bauer <sbauer@plzdonthack.me>
Acked-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Link: https://lore.kernel.org/r/20220816140713.84893-1-luca.boccassi@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

dougmill@linux.vnet.ibm.com and committed by
Jens Axboe
c6ea7060 1c23f9e6

+96 -12
+5
block/opal_proto.h
··· 39 39 #define FIRST_TPER_SESSION_NUM 4096 40 40 41 41 #define TPER_SYNC_SUPPORTED 0x01 42 + /* FC_LOCKING features */ 43 + #define LOCKING_SUPPORTED_MASK 0x01 44 + #define LOCKING_ENABLED_MASK 0x02 45 + #define LOCKED_MASK 0x04 42 46 #define MBR_ENABLED_MASK 0x10 47 + #define MBR_DONE_MASK 0x20 43 48 44 49 #define TINY_ATOM_DATA_MASK 0x3F 45 50 #define TINY_ATOM_SIGNED 0x40
+77 -12
block/sed-opal.c
··· 74 74 }; 75 75 76 76 struct opal_dev { 77 - bool supported; 78 - bool mbr_enabled; 77 + u32 flags; 79 78 80 79 void *data; 81 80 sec_send_recv *send_recv; ··· 279 280 return true; 280 281 } 281 282 283 + static bool check_lcksuppt(const void *data) 284 + { 285 + const struct d0_locking_features *lfeat = data; 286 + u8 sup_feat = lfeat->supported_features; 287 + 288 + return !!(sup_feat & LOCKING_SUPPORTED_MASK); 289 + } 290 + 291 + static bool check_lckenabled(const void *data) 292 + { 293 + const struct d0_locking_features *lfeat = data; 294 + u8 sup_feat = lfeat->supported_features; 295 + 296 + return !!(sup_feat & LOCKING_ENABLED_MASK); 297 + } 298 + 299 + static bool check_locked(const void *data) 300 + { 301 + const struct d0_locking_features *lfeat = data; 302 + u8 sup_feat = lfeat->supported_features; 303 + 304 + return !!(sup_feat & LOCKED_MASK); 305 + } 306 + 282 307 static bool check_mbrenabled(const void *data) 283 308 { 284 309 const struct d0_locking_features *lfeat = data; 285 310 u8 sup_feat = lfeat->supported_features; 286 311 287 312 return !!(sup_feat & MBR_ENABLED_MASK); 313 + } 314 + 315 + static bool check_mbrdone(const void *data) 316 + { 317 + const struct d0_locking_features *lfeat = data; 318 + u8 sup_feat = lfeat->supported_features; 319 + 320 + return !!(sup_feat & MBR_DONE_MASK); 288 321 } 289 322 290 323 static bool check_sum(const void *data) ··· 466 435 u32 hlen = be32_to_cpu(hdr->length); 467 436 468 437 print_buffer(dev->resp, hlen); 469 - dev->mbr_enabled = false; 438 + dev->flags &= OPAL_FL_SUPPORTED; 470 439 471 440 if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) { 472 441 pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n", ··· 492 461 check_geometry(dev, body); 493 462 break; 494 463 case FC_LOCKING: 495 - dev->mbr_enabled = check_mbrenabled(body->features); 464 + if (check_lcksuppt(body->features)) 465 + dev->flags |= OPAL_FL_LOCKING_SUPPORTED; 466 + if (check_lckenabled(body->features)) 467 + dev->flags |= OPAL_FL_LOCKING_ENABLED; 468 + if (check_locked(body->features)) 469 + dev->flags |= OPAL_FL_LOCKED; 470 + if (check_mbrenabled(body->features)) 471 + dev->flags |= OPAL_FL_MBR_ENABLED; 472 + if (check_mbrdone(body->features)) 473 + dev->flags |= OPAL_FL_MBR_DONE; 496 474 break; 497 475 case FC_ENTERPRISE: 498 476 case FC_DATASTORE: ··· 2149 2109 mutex_lock(&dev->dev_lock); 2150 2110 setup_opal_dev(dev); 2151 2111 ret = opal_discovery0_step(dev); 2152 - dev->supported = !ret; 2112 + if (!ret) 2113 + dev->flags |= OPAL_FL_SUPPORTED; 2153 2114 mutex_unlock(&dev->dev_lock); 2154 2115 2155 2116 return ret; ··· 2189 2148 2190 2149 INIT_LIST_HEAD(&dev->unlk_lst); 2191 2150 mutex_init(&dev->dev_lock); 2151 + dev->flags = 0; 2192 2152 dev->data = data; 2193 2153 dev->send_recv = send_recv; 2194 2154 if (check_opal_support(dev) != 0) { ··· 2570 2528 if (!dev) 2571 2529 return false; 2572 2530 2573 - if (!dev->supported) 2531 + if (!(dev->flags & OPAL_FL_SUPPORTED)) 2574 2532 return false; 2575 2533 2576 2534 mutex_lock(&dev->dev_lock); ··· 2588 2546 was_failure = true; 2589 2547 } 2590 2548 2591 - if (dev->mbr_enabled) { 2549 + if (dev->flags & OPAL_FL_MBR_ENABLED) { 2592 2550 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key); 2593 2551 if (ret) 2594 2552 pr_debug("Failed to set MBR Done in S3 resume\n"); ··· 2662 2620 return ret; 2663 2621 } 2664 2622 2623 + static int opal_get_status(struct opal_dev *dev, void __user *data) 2624 + { 2625 + struct opal_status sts = {0}; 2626 + 2627 + /* 2628 + * check_opal_support() error is not fatal, 2629 + * !dev->supported is a valid condition 2630 + */ 2631 + if (!check_opal_support(dev)) 2632 + sts.flags = dev->flags; 2633 + if (copy_to_user(data, &sts, sizeof(sts))) { 2634 + pr_debug("Error copying status to userspace\n"); 2635 + return -EFAULT; 2636 + } 2637 + return 0; 2638 + } 2639 + 2665 2640 int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg) 2666 2641 { 2667 2642 void *p; ··· 2688 2629 return -EACCES; 2689 2630 if (!dev) 2690 2631 return -ENOTSUPP; 2691 - if (!dev->supported) 2632 + if (!(dev->flags & OPAL_FL_SUPPORTED)) 2692 2633 return -ENOTSUPP; 2693 2634 2694 - p = memdup_user(arg, _IOC_SIZE(cmd)); 2695 - if (IS_ERR(p)) 2696 - return PTR_ERR(p); 2635 + if (cmd & IOC_IN) { 2636 + p = memdup_user(arg, _IOC_SIZE(cmd)); 2637 + if (IS_ERR(p)) 2638 + return PTR_ERR(p); 2639 + } 2697 2640 2698 2641 switch (cmd) { 2699 2642 case IOC_OPAL_SAVE: ··· 2746 2685 case IOC_OPAL_GENERIC_TABLE_RW: 2747 2686 ret = opal_generic_read_write_table(dev, p); 2748 2687 break; 2688 + case IOC_OPAL_GET_STATUS: 2689 + ret = opal_get_status(dev, arg); 2690 + break; 2749 2691 default: 2750 2692 break; 2751 2693 } 2752 2694 2753 - kfree(p); 2695 + if (cmd & IOC_IN) 2696 + kfree(p); 2754 2697 return ret; 2755 2698 } 2756 2699 EXPORT_SYMBOL_GPL(sed_ioctl);
+1
include/linux/sed-opal.h
··· 43 43 case IOC_OPAL_MBR_DONE: 44 44 case IOC_OPAL_WRITE_SHADOW_MBR: 45 45 case IOC_OPAL_GENERIC_TABLE_RW: 46 + case IOC_OPAL_GET_STATUS: 46 47 return true; 47 48 } 48 49 return false;
+13
include/uapi/linux/sed-opal.h
··· 132 132 __u64 priv; 133 133 }; 134 134 135 + #define OPAL_FL_SUPPORTED 0x00000001 136 + #define OPAL_FL_LOCKING_SUPPORTED 0x00000002 137 + #define OPAL_FL_LOCKING_ENABLED 0x00000004 138 + #define OPAL_FL_LOCKED 0x00000008 139 + #define OPAL_FL_MBR_ENABLED 0x00000010 140 + #define OPAL_FL_MBR_DONE 0x00000020 141 + 142 + struct opal_status { 143 + __u32 flags; 144 + __u32 reserved; 145 + }; 146 + 135 147 #define IOC_OPAL_SAVE _IOW('p', 220, struct opal_lock_unlock) 136 148 #define IOC_OPAL_LOCK_UNLOCK _IOW('p', 221, struct opal_lock_unlock) 137 149 #define IOC_OPAL_TAKE_OWNERSHIP _IOW('p', 222, struct opal_key) ··· 160 148 #define IOC_OPAL_MBR_DONE _IOW('p', 233, struct opal_mbr_done) 161 149 #define IOC_OPAL_WRITE_SHADOW_MBR _IOW('p', 234, struct opal_shadow_mbr) 162 150 #define IOC_OPAL_GENERIC_TABLE_RW _IOW('p', 235, struct opal_read_write_table) 151 + #define IOC_OPAL_GET_STATUS _IOR('p', 236, struct opal_status) 163 152 164 153 #endif /* _UAPI_SED_OPAL_H */