diff --git a/block/opal_proto.h b/block/opal_proto.h index d138785b8198..7c24247aa186 100644 --- a/block/opal_proto.h +++ b/block/opal_proto.h @@ -19,6 +19,7 @@ enum { TCG_SECP_00 = 0, TCG_SECP_01, + TCG_SECP_02, }; /* @@ -273,6 +274,25 @@ struct opal_header { struct opal_data_subpacket subpkt; }; +/* + * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 + * Section: 3.3.4.7.5 STACK_RESET + */ +#define OPAL_STACK_RESET 0x0002 + +struct opal_stack_reset { + u8 extendedComID[4]; + __be32 request_code; +}; + +struct opal_stack_reset_response { + u8 extendedComID[4]; + __be32 request_code; + u8 reserved0[2]; + __be16 data_length; + __be32 response; +}; + #define FC_TPER 0x0001 #define FC_LOCKING 0x0002 #define FC_GEOMETRY 0x0003 diff --git a/block/sed-opal.c b/block/sed-opal.c index c34d19e91201..79b290d9458a 100644 --- a/block/sed-opal.c +++ b/block/sed-opal.c @@ -3545,6 +3545,50 @@ static int opal_get_sum_ranges(struct opal_dev *dev, struct opal_sum_ranges *opa return ret; } +static int opal_stack_reset(struct opal_dev *dev) +{ + struct opal_stack_reset *req; + struct opal_stack_reset_response *resp; + int ret; + + mutex_lock(&dev->dev_lock); + + memset(dev->cmd, 0, IO_BUFFER_LENGTH); + req = (struct opal_stack_reset *)dev->cmd; + req->extendedComID[0] = dev->comid >> 8; + req->extendedComID[1] = dev->comid & 0xFF; + req->request_code = cpu_to_be32(OPAL_STACK_RESET); + + ret = dev->send_recv(dev->data, dev->comid, TCG_SECP_02, + dev->cmd, IO_BUFFER_LENGTH, true); + if (ret) { + pr_debug("Error sending stack reset: %d\n", ret); + goto out; + } + + memset(dev->resp, 0, IO_BUFFER_LENGTH); + ret = dev->send_recv(dev->data, dev->comid, TCG_SECP_02, + dev->resp, IO_BUFFER_LENGTH, false); + if (ret) { + pr_debug("Error receiving stack reset response: %d\n", ret); + goto out; + } + + resp = (struct opal_stack_reset_response *)dev->resp; + if (be16_to_cpu(resp->data_length) != 4) { + pr_debug("Stack reset pending\n"); + ret = -EBUSY; + goto out; + } + if (be32_to_cpu(resp->response) != 0) { + pr_debug("Stack reset failed: %u\n", be32_to_cpu(resp->response)); + ret = -EIO; + } +out: + mutex_unlock(&dev->dev_lock); + return ret; +} + int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg) { void *p; @@ -3642,6 +3686,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg) case IOC_OPAL_GET_SUM_STATUS: ret = opal_get_sum_ranges(dev, p, arg); break; + case IOC_OPAL_STACK_RESET: + ret = opal_stack_reset(dev); + break; default: break; diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h index aa006edb612b..0630430cc01a 100644 --- a/include/linux/sed-opal.h +++ b/include/linux/sed-opal.h @@ -57,6 +57,7 @@ static inline bool is_sed_ioctl(unsigned int cmd) case IOC_OPAL_LR_SET_START_LEN: case IOC_OPAL_ENABLE_DISABLE_LR: case IOC_OPAL_GET_SUM_STATUS: + case IOC_OPAL_STACK_RESET: return true; } return false; diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h index 9830298ec51c..ef4d3be6ca7f 100644 --- a/include/uapi/linux/sed-opal.h +++ b/include/uapi/linux/sed-opal.h @@ -245,5 +245,6 @@ struct opal_revert_lsp { #define IOC_OPAL_LR_SET_START_LEN _IOW('p', 243, struct opal_user_lr_setup) #define IOC_OPAL_ENABLE_DISABLE_LR _IOW('p', 244, struct opal_user_lr_setup) #define IOC_OPAL_GET_SUM_STATUS _IOW('p', 245, struct opal_sum_ranges) +#define IOC_OPAL_STACK_RESET _IO('p', 246) #endif /* _UAPI_SED_OPAL_H */