@@ -49,6 +49,11 @@ bool sedopal_discovery_verbose;
4949 */
5050bool sedopal_discovery_udev ;
5151
52+ /*
53+ * level 0 discovery buffer
54+ */
55+ char level0_discovery_buf [4096 ];
56+
5257struct sedopal_feature_parser {
5358 uint32_t features ;
5459 void * tper_desc ;
@@ -205,6 +210,15 @@ int sedopal_cmd_initialize(int fd)
205210 struct opal_lr_act lr_act = {};
206211 struct opal_user_lr_setup lr_setup = {};
207212 struct opal_new_pw new_pw = {};
213+ uint8_t locking_state ;
214+
215+ locking_state = sedopal_locking_state (fd );
216+
217+ if (locking_state & OPAL_FEATURE_LOCKING_ENABLED ) {
218+ fprintf (stderr ,
219+ "Error: cannot initialize an initialized drive\n" );
220+ return - EOPNOTSUPP ;
221+ }
208222
209223 sedopal_ask_key = true;
210224 sedopal_ask_new_key = true;
@@ -319,6 +333,15 @@ int sedopal_lock_unlock(int fd, int lock_state)
319333{
320334 int rc ;
321335 struct opal_lock_unlock opal_lu = {};
336+ uint8_t locking_state ;
337+
338+ locking_state = sedopal_locking_state (fd );
339+
340+ if (!(locking_state & OPAL_FEATURE_LOCKING_ENABLED )) {
341+ fprintf (stderr ,
342+ "Error: cannot lock/unlock an uninitialized drive\n" );
343+ return - EOPNOTSUPP ;
344+ }
322345
323346 rc = sedopal_set_key (& opal_lu .session .opal_key );
324347 if (rc != 0 )
@@ -433,6 +456,21 @@ int sedopal_cmd_revert(int fd)
433456 } else {
434457#ifdef IOC_OPAL_REVERT_LSP
435458 struct opal_revert_lsp revert_lsp ;
459+ uint8_t locking_state ;
460+
461+ locking_state = sedopal_locking_state (fd );
462+
463+ if (!(locking_state & OPAL_FEATURE_LOCKING_ENABLED )) {
464+ fprintf (stderr ,
465+ "Error: can't revert an uninitialized drive\n" );
466+ return - EOPNOTSUPP ;
467+ }
468+
469+ if (locking_state & OPAL_FEATURE_LOCKED ) {
470+ fprintf (stderr ,
471+ "Error: cannot revert drive while locked\n" );
472+ return - EOPNOTSUPP ;
473+ }
436474
437475 rc = sedopal_set_key (& revert_lsp .key );
438476 if (rc != 0 )
@@ -958,22 +996,18 @@ void sedopal_print_features(struct sedopal_feature_parser *sfp)
958996}
959997
960998/*
961- * Query a drive to determine if it's SED Opal capable and
962- * it's current locking status.
999+ * Query a drive to retrieve it's level 0 features.
9631000 */
964- int sedopal_cmd_discover (int fd )
1001+ int sedopal_discover_device (int fd , struct level_0_discovery_features * * feat ,
1002+ struct level_0_discovery_features * * feat_end )
9651003{
9661004#ifdef IOC_OPAL_DISCOVERY
967- int rc , feat_length ;
1005+ int rc ;
9681006 struct opal_discovery discover ;
9691007 struct level_0_discovery_header * dh ;
970- struct level_0_discovery_features * feat ;
971- struct level_0_discovery_features * feat_end ;
972- char buf [4096 ];
973- struct sedopal_feature_parser sfp = {};
9741008
975- discover .data = (uintptr_t )buf ;
976- discover .size = sizeof (buf );
1009+ discover .data = (uintptr_t )level0_discovery_buf ;
1010+ discover .size = sizeof (level0_discovery_buf );
9771011
9781012 rc = ioctl (fd , IOC_OPAL_DISCOVERY , & discover );
9791013 if (rc < 0 ) {
@@ -987,10 +1021,33 @@ int sedopal_cmd_discover(int fd)
9871021 *
9881022 * TCG Opal Specification v2.0.2 section 3.1.1
9891023 */
990- dh = (struct level_0_discovery_header * )buf ;
991- feat = (struct level_0_discovery_features * )(dh + 1 );
992- feat_end = (struct level_0_discovery_features * )
993- (buf + be32toh (dh -> parameter_length ));
1024+ dh = (struct level_0_discovery_header * )level0_discovery_buf ;
1025+ * feat = (struct level_0_discovery_features * )(dh + 1 );
1026+ * feat_end = (struct level_0_discovery_features * )
1027+ (level0_discovery_buf + be32toh (dh -> parameter_length ));
1028+
1029+ return 0
1030+ ;
1031+ #else /* IOC_OPAL_DISCOVERY */
1032+ fprintf (stderr , "ERROR : NVMe device discovery is not supported\n" );
1033+ return - EOPNOTSUPP ;
1034+ #endif
1035+ }
1036+
1037+ /*
1038+ * Query a drive to determine if it's SED Opal capable and
1039+ * it's current locking status.
1040+ */
1041+ int sedopal_cmd_discover (int fd )
1042+ {
1043+ int rc , feat_length ;
1044+ struct level_0_discovery_features * feat ;
1045+ struct level_0_discovery_features * feat_end ;
1046+ struct sedopal_feature_parser sfp = {};
1047+
1048+ rc = sedopal_discover_device (fd , & feat , & feat_end );
1049+ if (rc != 0 )
1050+ return rc ;
9941051
9951052 /*
9961053 * iterate through all the features that were returned
@@ -1016,8 +1073,37 @@ int sedopal_cmd_discover(int fd)
10161073
10171074
10181075 return rc ;
1019- #else /* IOC_OPAL_DISCOVERY */
1020- fprintf (stderr , "ERROR : NVMe device discovery is not supported\n" );
1021- return - EOPNOTSUPP ;
1022- #endif
1076+ }
1077+
1078+ /*
1079+ * Query a drive to determine its locking state
1080+ */
1081+ int sedopal_locking_state (int fd )
1082+ {
1083+ int rc , feat_length ;
1084+ struct level_0_discovery_features * feat ;
1085+ struct level_0_discovery_features * feat_end ;
1086+
1087+ rc = sedopal_discover_device (fd , & feat , & feat_end );
1088+ if (rc != 0 )
1089+ return rc ;
1090+
1091+ /*
1092+ * iterate through all the features that were returned
1093+ */
1094+ while (feat < feat_end ) {
1095+ uint16_t code = be16toh (feat -> code );
1096+
1097+ if (code == OPAL_FEATURE_CODE_LOCKING ) {
1098+ struct locking_desc * ld = (struct locking_desc * ) (feat + 1 );
1099+
1100+ return ld -> features ;
1101+ }
1102+
1103+ feat_length = feat -> length + 4 /* hdr */ ;
1104+ feat = (struct level_0_discovery_features * )
1105+ ((char * )feat + feat_length );
1106+ }
1107+
1108+ return 0 ;
10231109}
0 commit comments