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

block: sed-opal: Add support to read/write opal tables generically

This feature gives the user RW access to any opal table with admin1
authority. The flags described in the new structure determines if the user
wants to read/write the data. Flags are checked for valid values in
order to allow future features to be added to the ioctl.

The user can provide the desired table's UID. Also, the ioctl provides a
size and offset field and internally will loop data accesses to return
the full data block. Read overrun is prevented by the initiator's
sec_send_recv() backend. The ioctl provides a private field with the
intention to accommodate any future expansions to the ioctl.

Reviewed-by: Scott Bauer <sbauer@plzdonthack.me>
Reviewed-by: Jon Derrick <jonathan.derrick@intel.com>
Signed-off-by: Revanth Rajashekar <revanth.rajashekar@intel.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Revanth Rajashekar and committed by
Jens Axboe
51f421c8 3495ea1b

+193 -1
-1
block/opal_proto.h
··· 76 76 * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 77 77 * Section: 6.3 Assigned UIDs 78 78 */ 79 - #define OPAL_UID_LENGTH 8 80 79 #define OPAL_METHOD_LENGTH 8 81 80 #define OPAL_MSID_KEYLEN 15 82 81 #define OPAL_UID_LENGTH_HALF 4
+172
block/sed-opal.c
··· 1967 1967 return 0; 1968 1968 } 1969 1969 1970 + static int write_table_data(struct opal_dev *dev, void *data) 1971 + { 1972 + struct opal_read_write_table *write_tbl = data; 1973 + 1974 + return generic_table_write_data(dev, write_tbl->data, write_tbl->offset, 1975 + write_tbl->size, write_tbl->table_uid); 1976 + } 1977 + 1978 + static int read_table_data_cont(struct opal_dev *dev) 1979 + { 1980 + int err; 1981 + const char *data_read; 1982 + 1983 + err = parse_and_check_status(dev); 1984 + if (err) 1985 + return err; 1986 + 1987 + dev->prev_d_len = response_get_string(&dev->parsed, 1, &data_read); 1988 + dev->prev_data = (void *)data_read; 1989 + if (!dev->prev_data) { 1990 + pr_debug("%s: Couldn't read data from the table.\n", __func__); 1991 + return OPAL_INVAL_PARAM; 1992 + } 1993 + 1994 + return 0; 1995 + } 1996 + 1997 + /* 1998 + * IO_BUFFER_LENGTH = 2048 1999 + * sizeof(header) = 56 2000 + * No. of Token Bytes in the Response = 11 2001 + * MAX size of data that can be carried in response buffer 2002 + * at a time is : 2048 - (56 + 11) = 1981 = 0x7BD. 2003 + */ 2004 + #define OPAL_MAX_READ_TABLE (0x7BD) 2005 + 2006 + static int read_table_data(struct opal_dev *dev, void *data) 2007 + { 2008 + struct opal_read_write_table *read_tbl = data; 2009 + int err; 2010 + size_t off = 0, max_read_size = OPAL_MAX_READ_TABLE; 2011 + u64 table_len, len; 2012 + u64 offset = read_tbl->offset, read_size = read_tbl->size - 1; 2013 + u8 __user *dst; 2014 + 2015 + err = generic_get_table_info(dev, read_tbl->table_uid, OPAL_TABLE_ROWS); 2016 + if (err) { 2017 + pr_debug("Couldn't get the table size\n"); 2018 + return err; 2019 + } 2020 + 2021 + table_len = response_get_u64(&dev->parsed, 4); 2022 + 2023 + /* Check if the user is trying to read from the table limits */ 2024 + if (read_size > table_len || offset > table_len - read_size) { 2025 + pr_debug("Read size exceeds the Table size limits (%llu vs. %llu)\n", 2026 + offset + read_size, table_len); 2027 + return -EINVAL; 2028 + } 2029 + 2030 + while (off < read_size) { 2031 + err = cmd_start(dev, read_tbl->table_uid, opalmethod[OPAL_GET]); 2032 + 2033 + add_token_u8(&err, dev, OPAL_STARTLIST); 2034 + add_token_u8(&err, dev, OPAL_STARTNAME); 2035 + add_token_u8(&err, dev, OPAL_STARTROW); 2036 + add_token_u64(&err, dev, offset + off); /* start row value */ 2037 + add_token_u8(&err, dev, OPAL_ENDNAME); 2038 + 2039 + add_token_u8(&err, dev, OPAL_STARTNAME); 2040 + add_token_u8(&err, dev, OPAL_ENDROW); 2041 + 2042 + len = min(max_read_size, (size_t)(read_size - off)); 2043 + add_token_u64(&err, dev, offset + off + len); /* end row value 2044 + */ 2045 + add_token_u8(&err, dev, OPAL_ENDNAME); 2046 + add_token_u8(&err, dev, OPAL_ENDLIST); 2047 + 2048 + if (err) { 2049 + pr_debug("Error building read table data command.\n"); 2050 + break; 2051 + } 2052 + 2053 + err = finalize_and_send(dev, read_table_data_cont); 2054 + if (err) 2055 + break; 2056 + 2057 + /* len+1: This includes the NULL terminator at the end*/ 2058 + if (dev->prev_d_len > len + 1) { 2059 + err = -EOVERFLOW; 2060 + break; 2061 + } 2062 + 2063 + dst = (u8 __user *)(uintptr_t)read_tbl->data; 2064 + if (copy_to_user(dst + off, dev->prev_data, dev->prev_d_len)) { 2065 + pr_debug("Error copying data to userspace\n"); 2066 + err = -EFAULT; 2067 + break; 2068 + } 2069 + dev->prev_data = NULL; 2070 + 2071 + off += len; 2072 + } 2073 + 2074 + return err; 2075 + } 2076 + 1970 2077 static int end_opal_session(struct opal_dev *dev, void *data) 1971 2078 { 1972 2079 int err = 0; ··· 2560 2453 } 2561 2454 EXPORT_SYMBOL(opal_unlock_from_suspend); 2562 2455 2456 + static int opal_read_table(struct opal_dev *dev, 2457 + struct opal_read_write_table *rw_tbl) 2458 + { 2459 + const struct opal_step read_table_steps[] = { 2460 + { start_admin1LSP_opal_session, &rw_tbl->key }, 2461 + { read_table_data, rw_tbl }, 2462 + { end_opal_session, } 2463 + }; 2464 + int ret = 0; 2465 + 2466 + if (!rw_tbl->size) 2467 + return ret; 2468 + 2469 + return execute_steps(dev, read_table_steps, 2470 + ARRAY_SIZE(read_table_steps)); 2471 + } 2472 + 2473 + static int opal_write_table(struct opal_dev *dev, 2474 + struct opal_read_write_table *rw_tbl) 2475 + { 2476 + const struct opal_step write_table_steps[] = { 2477 + { start_admin1LSP_opal_session, &rw_tbl->key }, 2478 + { write_table_data, rw_tbl }, 2479 + { end_opal_session, } 2480 + }; 2481 + int ret = 0; 2482 + 2483 + if (!rw_tbl->size) 2484 + return ret; 2485 + 2486 + return execute_steps(dev, write_table_steps, 2487 + ARRAY_SIZE(write_table_steps)); 2488 + } 2489 + 2490 + static int opal_generic_read_write_table(struct opal_dev *dev, 2491 + struct opal_read_write_table *rw_tbl) 2492 + { 2493 + int ret, bit_set; 2494 + 2495 + mutex_lock(&dev->dev_lock); 2496 + setup_opal_dev(dev); 2497 + 2498 + bit_set = fls64(rw_tbl->flags) - 1; 2499 + switch (bit_set) { 2500 + case OPAL_READ_TABLE: 2501 + ret = opal_read_table(dev, rw_tbl); 2502 + break; 2503 + case OPAL_WRITE_TABLE: 2504 + ret = opal_write_table(dev, rw_tbl); 2505 + break; 2506 + default: 2507 + pr_debug("Invalid bit set in the flag (%016llx).\n", 2508 + rw_tbl->flags); 2509 + ret = -EINVAL; 2510 + break; 2511 + } 2512 + 2513 + mutex_unlock(&dev->dev_lock); 2514 + 2515 + return ret; 2516 + } 2517 + 2563 2518 int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg) 2564 2519 { 2565 2520 void *p; ··· 2683 2514 break; 2684 2515 case IOC_OPAL_PSID_REVERT_TPR: 2685 2516 ret = opal_reverttper(dev, p, true); 2517 + break; 2518 + case IOC_OPAL_GENERIC_TABLE_RW: 2519 + ret = opal_generic_read_write_table(dev, p); 2686 2520 break; 2687 2521 default: 2688 2522 break;
+1
include/linux/sed-opal.h
··· 42 42 case IOC_OPAL_PSID_REVERT_TPR: 43 43 case IOC_OPAL_MBR_DONE: 44 44 case IOC_OPAL_WRITE_SHADOW_MBR: 45 + case IOC_OPAL_GENERIC_TABLE_RW: 45 46 return true; 46 47 } 47 48 return false;
+20
include/uapi/linux/sed-opal.h
··· 113 113 __u64 size; 114 114 }; 115 115 116 + /* Opal table operations */ 117 + enum opal_table_ops { 118 + OPAL_READ_TABLE, 119 + OPAL_WRITE_TABLE, 120 + }; 121 + 122 + #define OPAL_UID_LENGTH 8 123 + struct opal_read_write_table { 124 + struct opal_key key; 125 + const __u64 data; 126 + const __u8 table_uid[OPAL_UID_LENGTH]; 127 + __u64 offset; 128 + __u64 size; 129 + #define OPAL_TABLE_READ (1 << OPAL_READ_TABLE) 130 + #define OPAL_TABLE_WRITE (1 << OPAL_WRITE_TABLE) 131 + __u64 flags; 132 + __u64 priv; 133 + }; 134 + 116 135 #define IOC_OPAL_SAVE _IOW('p', 220, struct opal_lock_unlock) 117 136 #define IOC_OPAL_LOCK_UNLOCK _IOW('p', 221, struct opal_lock_unlock) 118 137 #define IOC_OPAL_TAKE_OWNERSHIP _IOW('p', 222, struct opal_key) ··· 147 128 #define IOC_OPAL_PSID_REVERT_TPR _IOW('p', 232, struct opal_key) 148 129 #define IOC_OPAL_MBR_DONE _IOW('p', 233, struct opal_mbr_done) 149 130 #define IOC_OPAL_WRITE_SHADOW_MBR _IOW('p', 234, struct opal_shadow_mbr) 131 + #define IOC_OPAL_GENERIC_TABLE_RW _IOW('p', 235, struct opal_read_write_table) 150 132 151 133 #endif /* _UAPI_SED_OPAL_H */