1111 */
1212
1313#include <assert.h>
14+ #include <ctype.h>
1415#include <err.h>
1516#include <stdio.h>
1617#include <stdlib.h>
@@ -240,10 +241,280 @@ int do_identify(nvme_mi_ep_t ep, int argc, char **argv)
240241 return 0 ;
241242}
242243
244+ void fhexdump (FILE * fp , const unsigned char * buf , int len )
245+ {
246+ const int row_len = 16 ;
247+ int i , j ;
248+
249+ for (i = 0 ; i < len ; i += row_len ) {
250+ char hbuf [row_len * strlen ("00 " ) + 1 ];
251+ char cbuf [row_len + strlen ("|" ) + 1 ];
252+
253+ for (j = 0 ; (j < row_len ) && ((i + j ) < len ); j ++ ) {
254+ unsigned char c = buf [i + j ];
255+
256+ sprintf (hbuf + j * 3 , "%02x " , c );
257+
258+ if (!isprint (c ))
259+ c = '.' ;
260+
261+ sprintf (cbuf + j , "%c" , c );
262+ }
263+
264+ strcat (cbuf , "|" );
265+
266+ fprintf (fp , "%08x %*s |%s\n" , i ,
267+ 0 - (int )sizeof (hbuf ) + 1 , hbuf , cbuf );
268+ }
269+ }
270+
271+ void hexdump (const unsigned char * buf , int len )
272+ {
273+ fhexdump (stdout , buf , len );
274+ }
275+
276+ int do_get_log_page (nvme_mi_ep_t ep , int argc , char * * argv )
277+ {
278+ struct nvme_get_log_args args = { 0 };
279+ struct nvme_mi_ctrl * ctrl ;
280+ uint8_t buf [512 ];
281+ uint16_t ctrl_id ;
282+ int rc , tmp ;
283+
284+ if (argc < 2 ) {
285+ fprintf (stderr , "no controller ID specified\n" );
286+ return -1 ;
287+ }
288+
289+ tmp = atoi (argv [1 ]);
290+ if (tmp < 0 || tmp > 0xffff ) {
291+ fprintf (stderr , "invalid controller ID\n" );
292+ return -1 ;
293+ }
294+
295+ ctrl_id = tmp & 0xffff ;
296+
297+ args .args_size = sizeof (args );
298+ args .log = buf ;
299+ args .len = sizeof (buf );
300+
301+ if (argc > 2 ) {
302+ tmp = atoi (argv [2 ]);
303+ args .lid = tmp & 0xff ;
304+ } else {
305+ args .lid = 0x1 ;
306+ }
307+
308+ ctrl = nvme_mi_init_ctrl (ep , ctrl_id );
309+ if (!ctrl ) {
310+ warn ("can't create controller" );
311+ return -1 ;
312+ }
313+
314+ rc = nvme_mi_admin_get_log_page (ctrl , & args );
315+ if (rc ) {
316+ warn ("can't perform Get Log page command" );
317+ return -1 ;
318+ }
319+
320+ printf ("Get log page (log id = 0x%02x) data:\n" , args .lid );
321+ hexdump (buf , args .len );
322+
323+ return 0 ;
324+ }
325+
326+ int do_admin_raw (nvme_mi_ep_t ep , int argc , char * * argv )
327+ {
328+ struct nvme_mi_admin_req_hdr req ;
329+ struct nvme_mi_admin_resp_hdr * resp ;
330+ struct nvme_mi_ctrl * ctrl ;
331+ size_t resp_data_len ;
332+ unsigned long tmp ;
333+ uint8_t buf [512 ];
334+ uint16_t ctrl_id ;
335+ uint8_t opcode ;
336+ __le32 * cdw ;
337+ int i , rc ;
338+
339+ if (argc < 2 ) {
340+ fprintf (stderr , "no controller ID specified\n" );
341+ return -1 ;
342+ }
343+
344+ if (argc < 3 ) {
345+ fprintf (stderr , "no opcode specified\n" );
346+ return -1 ;
347+ }
348+
349+ tmp = atoi (argv [1 ]);
350+ if (tmp < 0 || tmp > 0xffff ) {
351+ fprintf (stderr , "invalid controller ID\n" );
352+ return -1 ;
353+ }
354+ ctrl_id = tmp & 0xffff ;
355+
356+ tmp = atoi (argv [2 ]);
357+ if (tmp < 0 || tmp > 0xff ) {
358+ fprintf (stderr , "invalid opcode\n" );
359+ return -1 ;
360+ }
361+ opcode = tmp & 0xff ;
362+
363+ memset (& req , 0 , sizeof (req ));
364+ req .opcode = opcode ;
365+ req .ctrl_id = cpu_to_le16 (ctrl_id );
366+
367+ /* The cdw10 - cdw16 fields are contiguous in req; set from argv. */
368+ cdw = (void * )& req + offsetof(typeof (req ), cdw10 );
369+ for (i = 0 ; i < 6 ; i ++ ) {
370+ if (argc >= 4 + i )
371+ tmp = strtoul (argv [3 + i ], NULL , 0 );
372+ else
373+ tmp = 0 ;
374+ * cdw = cpu_to_le32 (tmp & 0xffffffff );
375+ cdw ++ ;
376+ }
377+
378+ printf ("Admin request:\n" );
379+ printf (" opcode: 0x%02x\n" , req .opcode );
380+ printf (" ctrl: 0x%04x\n" , le16_to_cpu (req .ctrl_id ));
381+ printf (" cdw10: 0x%08x\n" , le32_to_cpu (req .cdw10 ));
382+ printf (" cdw11: 0x%08x\n" , le32_to_cpu (req .cdw11 ));
383+ printf (" cdw12: 0x%08x\n" , le32_to_cpu (req .cdw12 ));
384+ printf (" cdw13: 0x%08x\n" , le32_to_cpu (req .cdw13 ));
385+ printf (" cdw14: 0x%08x\n" , le32_to_cpu (req .cdw14 ));
386+ printf (" cdw15: 0x%08x\n" , le32_to_cpu (req .cdw15 ));
387+ printf (" raw:\n" );
388+ hexdump ((void * )& req , sizeof (req ));
389+
390+ memset (buf , 0 , sizeof (buf ));
391+ resp = (void * )buf ;
392+
393+ ctrl = nvme_mi_init_ctrl (ep , ctrl_id );
394+ if (!ctrl ) {
395+ warn ("can't create controller" );
396+ return -1 ;
397+ }
398+
399+ resp_data_len = sizeof (buf ) - sizeof (* resp );
400+
401+ rc = nvme_mi_admin_xfer (ctrl , & req , 0 , resp , 0 , & resp_data_len );
402+ if (rc ) {
403+ warn ("nvme_admin_xfer failed: %d" , rc );
404+ return -1 ;
405+ }
406+
407+ printf ("Admin response:\n" );
408+ printf (" Status: 0x%02x\n" , resp -> status );
409+ printf (" cdw0: 0x%08x\n" , le32_to_cpu (resp -> cdw0 ));
410+ printf (" cdw1: 0x%08x\n" , le32_to_cpu (resp -> cdw1 ));
411+ printf (" cdw3: 0x%08x\n" , le32_to_cpu (resp -> cdw3 ));
412+ printf (" data [%zd bytes]\n" , resp_data_len );
413+
414+ hexdump (buf + sizeof (* resp ), resp_data_len );
415+ return 0 ;
416+ }
417+
418+ static struct {
419+ uint8_t id ;
420+ const char * name ;
421+ } sec_protos [] = {
422+ { 0x00 , "Security protocol information" },
423+ { 0xea , "NVMe" },
424+ { 0xec , "JEDEC Universal Flash Storage" },
425+ { 0xed , "SDCard TrustedFlash Security" },
426+ { 0xee , "IEEE 1667" },
427+ { 0xef , "ATA Device Server Password Security" },
428+ };
429+
430+ static const char * sec_proto_description (uint8_t id )
431+ {
432+ unsigned int i ;
433+
434+ for (i = 0 ; i < ARRAY_SIZE (sec_protos ); i ++ ) {
435+ if (sec_protos [i ].id == id )
436+ return sec_protos [i ].name ;
437+ }
438+
439+ if (id >= 0xf0 )
440+ return "Vendor specific" ;
441+
442+ return "unknown" ;
443+ }
444+
445+ int do_security_info (nvme_mi_ep_t ep , int argc , char * * argv )
446+ {
447+ struct nvme_security_receive_args args = { 0 };
448+ nvme_mi_ctrl_t ctrl ;
449+ int i , rc , n_proto ;
450+ unsigned long tmp ;
451+ uint16_t ctrl_id ;
452+ struct {
453+ uint8_t rsvd [6 ];
454+ uint16_t len ;
455+ uint8_t protocols [256 ];
456+ } proto_info ;
457+
458+ if (argc != 2 ) {
459+ fprintf (stderr , "no controller ID specified\n" );
460+ return -1 ;
461+ }
462+
463+ tmp = atoi (argv [1 ]);
464+ if (tmp < 0 || tmp > 0xffff ) {
465+ fprintf (stderr , "invalid controller ID\n" );
466+ return -1 ;
467+ }
468+
469+ ctrl_id = tmp & 0xffff ;
470+
471+ ctrl = nvme_mi_init_ctrl (ep , ctrl_id );
472+ if (!ctrl ) {
473+ warn ("can't create controller" );
474+ return -1 ;
475+ }
476+
477+ /* protocol 0x00, spsp 0x0000: retrieve supported protocols */
478+ args .args_size = sizeof (args );
479+ args .data = & proto_info ;
480+ args .data_len = sizeof (proto_info );
481+
482+ rc = nvme_mi_admin_security_recv (ctrl , & args );
483+ if (rc ) {
484+ warnx ("can't perform Security Receive command: rc %d" , rc );
485+ return -1 ;
486+ }
487+
488+ if (args .data_len < 6 ) {
489+ warnx ("Short response in security receive command (%d bytes)" ,
490+ args .data_len );
491+ return -1 ;
492+ }
493+
494+ n_proto = be16_to_cpu (proto_info .len );
495+ if (args .data_len < 6 + n_proto ) {
496+ warnx ("Short response in security receive command (%d bytes), "
497+ "for %d protocols" , args .data_len , n_proto );
498+ return -1 ;
499+ }
500+
501+ printf ("Supported protocols:\n" );
502+ for (i = 0 ; i < n_proto ; i ++ ) {
503+ uint8_t id = proto_info .protocols [i ];
504+ printf (" 0x%02x: %s\n" , id , sec_proto_description (id ));
505+ }
506+
507+ return 0 ;
508+ }
509+
510+
243511enum action {
244512 ACTION_INFO ,
245513 ACTION_CONTROLLERS ,
246514 ACTION_IDENTIFY ,
515+ ACTION_GET_LOG_PAGE ,
516+ ACTION_ADMIN_RAW ,
517+ ACTION_SECURITY_INFO ,
247518};
248519
249520int main (int argc , char * * argv )
@@ -261,7 +532,11 @@ int main(int argc, char **argv)
261532 fprintf (stderr , "where action is:\n"
262533 " info\n"
263534 " controllers\n"
264- " identify <controller-id> [--partial]\n" );
535+ " identify <controller-id> [--partial]\n"
536+ " get-log-page <controller-id> [<log-id>]\n"
537+ " admin <controller-id> <opcode> [<cdw10>, <cdw11>, ...]\n"
538+ " security-info <controller-id>\n"
539+ );
265540 return EXIT_FAILURE ;
266541 }
267542
@@ -283,6 +558,12 @@ int main(int argc, char **argv)
283558 action = ACTION_CONTROLLERS ;
284559 } else if (!strcmp (action_str , "identify" )) {
285560 action = ACTION_IDENTIFY ;
561+ } else if (!strcmp (action_str , "get-log-page" )) {
562+ action = ACTION_GET_LOG_PAGE ;
563+ } else if (!strcmp (action_str , "admin" )) {
564+ action = ACTION_ADMIN_RAW ;
565+ } else if (!strcmp (action_str , "security-info" )) {
566+ action = ACTION_SECURITY_INFO ;
286567 } else {
287568 fprintf (stderr , "invalid action '%s'\n" , action_str );
288569 return EXIT_FAILURE ;
@@ -307,6 +588,15 @@ int main(int argc, char **argv)
307588 case ACTION_IDENTIFY :
308589 rc = do_identify (ep , argc , argv );
309590 break ;
591+ case ACTION_GET_LOG_PAGE :
592+ rc = do_get_log_page (ep , argc , argv );
593+ break ;
594+ case ACTION_ADMIN_RAW :
595+ rc = do_admin_raw (ep , argc , argv );
596+ break ;
597+ case ACTION_SECURITY_INFO :
598+ rc = do_security_info (ep , argc , argv );
599+ break ;
310600 }
311601
312602 nvme_mi_close (ep );
0 commit comments