ce2039e6ab0994a314d47302af6cf0cd47e7547d
[multipath-tools/.git] / mpathpersist / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <fcntl.h>
6 #include "checkers.h"
7 #include "vector.h"
8 #include "config.h"
9 #include "structs.h"
10 #include <getopt.h>
11 #include <libudev.h>
12 #include "mpath_persist.h"
13 #include "main.h"
14 #include "debug.h"
15 #include <pthread.h>
16 #include <ctype.h>
17 #include <string.h>
18 #include <errno.h>
19 #include "version.h"
20
21 static const char * pr_type_strs[] = {
22         "obsolete [0]",
23         "Write Exclusive",
24         "obsolete [2]",
25         "Exclusive Access",
26         "obsolete [4]",
27         "Write Exclusive, registrants only",
28         "Exclusive Access, registrants only",
29         "Write Exclusive, all registrants",
30         "Exclusive Access, all registrants",
31         "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
32         "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
33 };
34
35 int get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids);
36 void mpath_print_buf_readcap(struct prin_resp *pr_buff);
37 void mpath_print_buf_readfullstat(struct prin_resp *pr_buff);
38 void mpath_print_buf_readresv(struct prin_resp *pr_buff);
39 void mpath_print_buf_readkeys(struct prin_resp *pr_buff);
40 void dumpHex(const char* str, int len, int no_ascii);
41 void * mpath_alloc_prin_response(int prin_sa);
42 void mpath_print_transport_id(struct prin_fulldescr *fdesc);
43 int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
44
45 int logsink;
46 struct config *multipath_conf;
47
48 struct config *get_multipath_config(void)
49 {
50         return multipath_conf;
51 }
52
53 void put_multipath_config(void * arg)
54 {
55         /* Noop for now */
56 }
57
58 void rcu_register_thread_memb(void) {}
59
60 void rcu_unregister_thread_memb(void) {}
61
62 struct udev *udev;
63
64 static int verbose, loglevel, noisy;
65
66 static int handle_args(int argc, char * argv[], int line);
67
68 static int do_batch_file(const char *batch_fn)
69 {
70         char command[] = "mpathpersist";
71         const int ARGV_CHUNK = 2;
72         const char delims[] = " \t\n";
73         size_t len = 0;
74         char *line = NULL;
75         ssize_t n;
76         int nline = 0;
77         int argl = ARGV_CHUNK;
78         FILE *fl;
79         char **argv = calloc(argl, sizeof(*argv));
80         int ret = MPATH_PR_SUCCESS;
81
82         if (argv == NULL)
83                 return MPATH_PR_OTHER;
84
85         fl = fopen(batch_fn, "r");
86         if (fl == NULL) {
87                 fprintf(stderr, "unable to open %s: %s\n",
88                         batch_fn, strerror(errno));
89                 free(argv);
90                 return MPATH_PR_SYNTAX_ERROR;
91         } else {
92                 if (verbose >= 2)
93                         fprintf(stderr, "running batch file %s\n",
94                                 batch_fn);
95         }
96
97         while ((n = getline(&line, &len, fl)) != -1) {
98                 char *_token, *token;
99                 int argc = 0;
100                 int rv;
101
102                 nline++;
103                 argv[argc++] = command;
104
105                 if (line[n-1] == '\n')
106                         line[n-1] = '\0';
107                 if (verbose >= 3)
108                         fprintf(stderr, "processing line %d: %s\n",
109                                 nline, line);
110
111                 for (token = strtok_r(line, delims, &_token);
112                      token != NULL && *token != '#';
113                      token = strtok_r(NULL, delims, &_token)) {
114
115                         if (argc >= argl) {
116                                 int argn = argl + ARGV_CHUNK;
117                                 char **tmp;
118
119                                 tmp = realloc(argv, argn * sizeof(*argv));
120                                 if (tmp == NULL)
121                                         break;
122                                 argv = tmp;
123                                 argl = argn;
124                         }
125
126                         if (argc == 1 && !strcmp(token, command))
127                                 continue;
128
129                         argv[argc++] = token;
130                 }
131
132                 if (argc <= 1)
133                         continue;
134
135                 if (verbose >= 2) {
136                         int i;
137
138                         fprintf(stderr, "## file %s line %d:", batch_fn, nline);
139                         for (i = 0; i < argc; i++)
140                                 fprintf(stderr, " %s", argv[i]);
141                         fprintf(stderr, "\n");
142                 }
143
144                 optind = 0;
145                 rv = handle_args(argc, argv, nline);
146                 if (rv != MPATH_PR_SUCCESS)
147                         ret = rv;
148         }
149
150         fclose(fl);
151         free(argv);
152         free(line);
153         return ret;
154 }
155
156 static int handle_args(int argc, char * argv[], int nline)
157 {
158         int fd, c, res;
159         const char *device_name = NULL;
160         int num_prin_sa = 0;
161         int num_prout_sa = 0;
162         int num_prout_param = 0;
163         int prin_flag = 0;
164         int prout_flag = 0;
165         int ret = 0;
166         int hex = 0;
167         uint64_t param_sark = 0;
168         unsigned int prout_type = 0;
169         int param_alltgpt = 0;
170         int param_aptpl = 0;
171         uint64_t param_rk = 0;
172         unsigned int param_rtp = 0;
173         int num_transportids = 0;
174         struct transportid transportids[MPATH_MX_TIDS];
175         int prout = 1;
176         int prin = 1;
177         int prin_sa = -1;
178         int prout_sa = -1;
179         int num_transport =0;
180         char *batch_fn = NULL;
181         void *resp = NULL;
182         struct transportid * tmp;
183         struct config *conf = multipath_conf;
184
185         memset(transportids, 0, MPATH_MX_TIDS * sizeof(struct transportid));
186
187         while (1)
188         {
189                 int option_index = 0;
190
191                 c = getopt_long (argc, argv, "v:Cd:hHioYZK:S:PAT:skrGILcRX:l:f:",
192                                 long_options, &option_index);
193                 if (c == -1)
194                         break;
195
196                 switch (c)
197                 {
198                         case 'f':
199                                 if (nline != 0) {
200                                         fprintf(stderr,
201                                                 "ERROR: -f option not allowed in batch file\n");
202                                         ret = MPATH_PR_SYNTAX_ERROR;
203                                         goto out;
204                                 }
205                                 if (batch_fn != NULL) {
206                                         fprintf(stderr,
207                                                 "ERROR: -f option can be used at most once\n");
208                                         ret = MPATH_PR_SYNTAX_ERROR;
209                                         goto out;
210                                 }
211                                 batch_fn = strdup(optarg);
212                                 break;
213                         case 'v':
214                                 if (nline == 0 && 1 != sscanf (optarg, "%d", &loglevel))
215                                 {
216                                         fprintf (stderr, "bad argument to '--verbose'\n");
217                                         return MPATH_PR_SYNTAX_ERROR;
218                                 }
219                                 break;
220
221                         case 'C':
222                                 prout_sa = MPATH_PROUT_CLEAR_SA;
223                                 ++num_prout_sa;
224                                 break;
225
226                         case 'd':
227                                 device_name = optarg;
228                                 break;
229
230                         case 'h':
231                                 usage ();
232                                 return 0;
233
234                         case 'H':
235                                 hex=1;
236                                 break;
237
238                         case 'i':
239                                 prin_flag = 1;
240                                 break;
241
242                         case 'o':
243                                 prout_flag = 1;
244                                 break;
245
246                         case 'Y':
247                                 param_alltgpt = 1;
248                                 ++num_prout_param;
249                                 break;
250                         case 'Z':
251                                 param_aptpl = 1;
252                                 ++num_prout_param;
253                                 break;
254                         case 'K':
255                                 if (1 != sscanf (optarg, "%" SCNx64 "", &param_rk))
256                                 {
257                                         fprintf (stderr, "bad argument to '--param-rk'\n");
258                                         return MPATH_PR_SYNTAX_ERROR;
259                                 }
260                                 ++num_prout_param;
261                                 break;
262
263                         case 'S':
264                                 if (1 != sscanf (optarg, "%" SCNx64 "", &param_sark))
265                                 {
266                                         fprintf (stderr, "bad argument to '--param-sark'\n");
267                                         return MPATH_PR_SYNTAX_ERROR;
268                                 }
269                                 ++num_prout_param;
270                                 break;
271
272                         case 'P':
273                                 prout_sa = MPATH_PROUT_PREE_SA;
274                                 ++num_prout_sa;
275                                 break;
276
277                         case 'A':
278                                 prout_sa = MPATH_PROUT_PREE_AB_SA;
279                                 ++num_prout_sa;
280                                 break;
281
282                         case 'T':
283                                 if (1 != sscanf (optarg, "%x", &prout_type))
284                                 {
285                                         fprintf (stderr, "bad argument to '--prout-type'\n");
286                                         return MPATH_PR_SYNTAX_ERROR;
287                                 }
288                                 ++num_prout_param;
289                                 break;
290
291                         case 's':
292                                 prin_sa = MPATH_PRIN_RFSTAT_SA;
293                                 ++num_prin_sa;
294                                 break;
295
296                         case 'k':
297                                 prin_sa = MPATH_PRIN_RKEY_SA;
298                                 ++num_prin_sa;
299                                 break;
300
301                         case 'r':
302                                 prin_sa = MPATH_PRIN_RRES_SA;
303                                 ++num_prin_sa;
304                                 break;
305
306                         case 'G':
307                                 prout_sa = MPATH_PROUT_REG_SA;
308                                 ++num_prout_sa;
309                                 break;
310
311                         case 'I':
312                                 prout_sa = MPATH_PROUT_REG_IGN_SA;
313                                 ++num_prout_sa;
314                                 break;
315
316                         case 'L':
317                                 prout_sa = MPATH_PROUT_REL_SA;
318                                 ++num_prout_sa;
319                                 break;
320
321                         case 'c':
322                                 prin_sa = MPATH_PRIN_RCAP_SA;
323                                 ++num_prin_sa;
324                                 break;
325
326                         case 'R':
327                                 prout_sa = MPATH_PROUT_RES_SA;
328                                 ++num_prout_sa;
329                                 break;
330
331                         case 'X':
332                                 if (0 != construct_transportid(optarg, transportids, num_transport)) {
333                                         fprintf(stderr, "bad argument to '--transport-id'\n");
334                                         return MPATH_PR_SYNTAX_ERROR;
335                                 }
336
337                                 ++num_transport;
338                                 break;
339
340                         case 'l':
341                                 if (1 != sscanf(optarg, "%u", &mpath_mx_alloc_len)) {
342                                         fprintf(stderr, "bad argument to '--alloc-length'\n");
343                                         return MPATH_PR_SYNTAX_ERROR;
344                                 } else if (MPATH_MAX_PARAM_LEN < mpath_mx_alloc_len) {
345                                         fprintf(stderr, "'--alloc-length' argument exceeds maximum"
346                                                         " limit(%d)\n", MPATH_MAX_PARAM_LEN);
347                                         return MPATH_PR_SYNTAX_ERROR;
348                                 }
349                                 break;
350
351                         default:
352                                 fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c);
353                                 ret = MPATH_PR_SYNTAX_ERROR;
354                                 goto out;
355                 }
356         }
357
358         if (optind < argc)
359         {
360
361                 if (NULL == device_name)
362                 {
363                         device_name = argv[optind];
364                         ++optind;
365                 }
366                 if (optind < argc)
367                 {
368                         for (; optind < argc; ++optind)
369                                 fprintf (stderr, "Unexpected extra argument: %s\n", argv[optind]);
370                         ret = MPATH_PR_SYNTAX_ERROR;
371                         goto out;
372                 }
373         }
374
375         if (nline == 0) {
376                 /* set verbosity */
377                 noisy = (loglevel >= 3) ? 1 : hex;
378                 verbose = (loglevel >= 3)? 3: loglevel;
379         }
380
381         if ((prout_flag + prin_flag) == 0 && batch_fn == NULL)
382         {
383                 fprintf (stderr, "choose either '--in' or '--out' \n");
384                 ret = MPATH_PR_SYNTAX_ERROR;
385                 goto out;
386         }
387         if ((prout_flag + prin_flag) > 1)
388         {
389                 fprintf (stderr, "choose either '--in' or '--out' \n");
390                 ret = MPATH_PR_SYNTAX_ERROR;
391                 goto out;
392         }
393         else if (prout_flag)
394         {                               /* syntax check on PROUT arguments */
395                 prin = 0;
396                 if ((1 != num_prout_sa) || (0 != num_prin_sa))
397                 {
398                         fprintf (stderr, " For Persistent Reserve Out only one "
399                                         "appropriate\n service action must be "
400                                         "chosen \n");
401                         ret = MPATH_PR_SYNTAX_ERROR;
402                         goto out;
403                 }
404         }
405         else if (prin_flag)
406         {                               /* syntax check on PRIN arguments */
407                 prout = 0;
408                 if (num_prout_sa > 0)
409                 {
410                         fprintf (stderr, " When a service action for Persistent "
411                                         "Reserve Out is chosen the\n"
412                                         " '--out' option must be given \n");
413                         ret = MPATH_PR_SYNTAX_ERROR;
414                         goto out;
415                 }
416                 if (0 == num_prin_sa)
417                 {
418                         fprintf (stderr,
419                                         " No service action given for Persistent Reserve IN\n");
420                         ret = MPATH_PR_SYNTAX_ERROR;
421                 }
422                 else if (num_prin_sa > 1)
423                 {
424                         fprintf (stderr, " Too many service actions given; choose "
425                                         "one only\n");
426                         ret = MPATH_PR_SYNTAX_ERROR;
427                 }
428         }
429         else
430         {
431                 if (batch_fn == NULL)
432                         ret = MPATH_PR_SYNTAX_ERROR;
433                 goto out;
434         }
435
436         if ((param_rtp) && (MPATH_PROUT_REG_MOV_SA != prout_sa))
437         {
438                 fprintf (stderr, " --relative-target-port"
439                                 " only useful with --register-move\n");
440                 ret = MPATH_PR_SYNTAX_ERROR;
441                 goto out;
442         }
443
444         if (((MPATH_PROUT_RES_SA == prout_sa) ||
445                                 (MPATH_PROUT_REL_SA == prout_sa) ||
446                                 (MPATH_PROUT_PREE_SA == prout_sa) ||
447                                 (MPATH_PROUT_PREE_AB_SA == prout_sa)) &&
448                         (0 == prout_type)) {
449                 fprintf(stderr, "Warning: --prout-type probably needs to be "
450                                 "given\n");
451         }
452         if ((verbose > 2) && num_transportids)
453         {
454                 fprintf (stderr, "number of tranport-ids decoded from "
455                                 "command line : %d\n", num_transportids);
456         }
457
458         if (device_name == NULL)
459         {
460                 fprintf (stderr, "No device name given \n");
461                 ret = MPATH_PR_SYNTAX_ERROR;
462                 goto out;
463         }
464
465         /* open device */
466         if ((fd = open (device_name, O_RDONLY)) < 0)
467         {
468                 fprintf (stderr, "%s: error opening file (rw) fd=%d\n",
469                                 device_name, fd);
470                 ret = MPATH_PR_FILE_ERROR;
471                 goto out;
472         }
473
474
475         if (prin)
476         {
477                 resp = mpath_alloc_prin_response(prin_sa);
478                 if (!resp)
479                 {
480                         fprintf (stderr, "failed to allocate PRIN response buffer\n");
481                         ret = MPATH_PR_OTHER;
482                         goto out;
483                 }
484
485                 ret = mpath_persistent_reserve_in (fd, prin_sa, resp, noisy, verbose);
486                 if (ret != MPATH_PR_SUCCESS )
487                 {
488                         fprintf (stderr, "Persistent Reserve IN command failed\n");
489                         goto out;
490                 }
491
492                 switch(prin_sa)
493                 {
494                         case MPATH_PRIN_RKEY_SA:
495                                 mpath_print_buf_readkeys(resp);
496                                 break;
497                         case MPATH_PRIN_RRES_SA:
498                                 mpath_print_buf_readresv(resp);
499                                 break;
500                         case MPATH_PRIN_RCAP_SA:
501                                 mpath_print_buf_readcap(resp);
502                                 break;
503                         case MPATH_PRIN_RFSTAT_SA:
504                                 mpath_print_buf_readfullstat(resp);
505                                 break;
506                 }
507                 free(resp);
508         }
509         else if (prout)
510         {
511                 int j;
512                 struct prout_param_descriptor *paramp;
513
514                 paramp= malloc(sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS )));
515
516                 memset(paramp, 0, sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS)));
517
518                 for (j = 7; j >= 0; --j) {
519                         paramp->key[j] = (param_rk & 0xff);
520                         param_rk >>= 8;
521                 }
522
523                 for (j = 7; j >= 0; --j) {
524                         paramp->sa_key[j] = (param_sark & 0xff);
525                         param_sark >>= 8;
526                 }
527
528                 if (param_alltgpt)
529                         paramp->sa_flags |= MPATH_F_ALL_TG_PT_MASK;
530                 if (param_aptpl)
531                         paramp->sa_flags |= MPATH_F_APTPL_MASK;
532
533                 if (num_transport)
534                 {
535                         paramp->sa_flags |= MPATH_F_SPEC_I_PT_MASK;
536                         paramp->num_transportid = num_transport;
537                         for (j = 0 ; j < num_transport; j++)
538                         {
539                                 paramp->trnptid_list[j] = (struct transportid *)malloc(sizeof(struct transportid));
540                                 memcpy(paramp->trnptid_list[j], &transportids[j],sizeof(struct transportid));
541                         }
542                 }
543
544                 /* PROUT commands other than 'register and move' */
545                 ret = mpath_persistent_reserve_out (fd, prout_sa, 0, prout_type,
546                                 paramp, noisy, verbose);
547                 for (j = 0 ; j < num_transport; j++)
548                 {
549                         tmp = paramp->trnptid_list[j];
550                         free(tmp);
551                 }
552                 free(paramp);
553         }
554
555         if (ret != MPATH_PR_SUCCESS)
556         {
557                 switch(ret)
558                 {
559                         case MPATH_PR_SENSE_UNIT_ATTENTION:
560                                 printf("persistent reserve out: scsi status: Unit Attention\n");
561                                 break;
562                         case MPATH_PR_RESERV_CONFLICT:
563                                 printf("persistent reserve out: scsi status: Reservation Conflict\n");
564                                 break;
565                 }
566                 printf("PR out: command failed\n");
567         }
568
569         res = close (fd);
570         if (res < 0)
571         {
572                 mpath_lib_exit(conf);
573                 udev_unref(udev);
574                 return MPATH_PR_FILE_ERROR;
575         }
576
577 out :
578         if (ret == MPATH_PR_SYNTAX_ERROR) {
579                 free(batch_fn);
580                 if (nline == 0)
581                         usage();
582                 else
583                         fprintf(stderr, "syntax error on line %d in batch file\n",
584                                 nline);
585         } else if (batch_fn != NULL) {
586                 int rv = do_batch_file(batch_fn);
587
588                 free(batch_fn);
589                 ret = ret == 0 ? rv : ret;
590         }
591         return (ret >= 0) ? ret : MPATH_PR_OTHER;
592 }
593
594 int main(int argc, char *argv[])
595 {
596         int ret;
597
598         if (optind == argc)
599         {
600
601                 fprintf (stderr, "No parameter used\n");
602                 usage ();
603                 exit (1);
604         }
605
606         if (getuid () != 0)
607         {
608                 fprintf (stderr, "need to be root\n");
609                 exit (1);
610         }
611
612         udev = udev_new();
613         multipath_conf = mpath_lib_init();
614         if(!multipath_conf) {
615                 udev_unref(udev);
616                 exit(1);
617         }
618
619         ret = handle_args(argc, argv, 0);
620
621         mpath_lib_exit(multipath_conf);
622         udev_unref(udev);
623
624         return (ret >= 0) ? ret : MPATH_PR_OTHER;
625 }
626
627 int
628 get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids)
629 {
630         int compact_len = 0;
631         unsigned char * ucp = transportid_arr;
632         int k, off, protocol_id, len;
633         for (k = 0, off = 0; ((k < num_transportids) && (k < max_transportid));
634                         ++k, off += MPATH_MX_TID_LEN) {
635                 protocol_id = ucp[off] & 0xf;
636                 if (5 == protocol_id) {
637                         len = (ucp[off + 2] << 8) + ucp[off + 3] + 4;
638                         if (len < 24)
639                                 len = 24;
640                         if (off > compact_len)
641                                 memmove(ucp + compact_len, ucp + off, len);
642                         compact_len += len;
643
644                 } else {
645                         if (off > compact_len)
646                                 memmove(ucp + compact_len, ucp + off, 24);
647                         compact_len += 24;
648                 }
649         }
650
651         return compact_len;
652 }
653
654 void mpath_print_buf_readkeys( struct prin_resp *pr_buff)
655 {
656         int i,j,k, num;
657         unsigned char *keyp;
658         uint64_t prkey;
659         printf("  PR generation=0x%x, ", pr_buff->prin_descriptor.prin_readkeys.prgeneration);
660
661         num = pr_buff->prin_descriptor.prin_readkeys.additional_length / 8;
662         if (0 == num) {
663                 printf("        0 registered reservation key.\n");
664                 return;
665         }
666         else if (1 == num)
667                 printf("        1 registered reservation key follows:\n");
668         else
669                 printf("        %d registered reservation keys follow:\n", num);
670
671
672         keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
673         for (i = 0; i < num ; i++)
674         {
675                 prkey = 0;
676                 for (j = 0; j < 8; ++j) {
677
678                         if (j > 0)
679                                 prkey <<= 8;
680                         prkey |= keyp[j];
681                 }
682                 printf("    0x%" PRIx64 "\n", prkey);
683                 k=8*i+j;
684                 keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[k];
685         }
686 }
687
688 void mpath_print_buf_readresv( struct prin_resp *pr_buff)
689 {
690         int j, num, scope=0, type=0;
691         unsigned char *keyp;
692         uint64_t prkey;
693
694         num = pr_buff->prin_descriptor.prin_readresv.additional_length / 8;
695         if (0 == num)
696         {
697                 printf("  PR generation=0x%x, there is NO reservation held \n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
698                 return ;
699         }
700         else
701                 printf("  PR generation=0x%x, Reservation follows:\n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
702         keyp = (unsigned  char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
703         prkey = 0;
704         for (j = 0; j < 8; ++j) {
705                 if (j > 0)
706                         prkey <<= 8;
707                 prkey |= keyp[j];
708         }
709
710         printf("   Key = 0x%" PRIx64 "\n", prkey);
711
712         scope = (pr_buff->prin_descriptor.prin_readresv.scope_type >> 4) &  0x0f;
713         type = pr_buff->prin_descriptor.prin_readresv.scope_type & 0x0f;
714
715         if (scope == 0)
716                 printf("  scope = LU_SCOPE, type = %s", pr_type_strs[type]);
717         else
718                 printf("  scope = %d, type = %s", scope, pr_type_strs[type]);
719
720         printf("\n");
721
722 }
723
724 void mpath_print_buf_readcap( struct prin_resp *pr_buff)
725 {
726         if ( pr_buff->prin_descriptor.prin_readcap.length <= 2 ) {
727                 fprintf(stderr, "Unexpected response for PRIN Report "
728                                 "Capabilities\n");
729                 return; //MALFORMED;
730         }
731
732         printf("Report capabilities response:\n");
733
734         printf("  Compatible Reservation Handling(CRH): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10));
735         printf("  Specify Initiator Ports Capable(SIP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8));
736         printf("  All Target Ports Capable(ATP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4 ));
737         printf("  Persist Through Power Loss Capable(PTPL_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0]));
738         printf("  Type Mask Valid(TMV): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80));
739         printf("  Allow Commands: %d\n", !!(( pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7));
740         printf("  Persist Through Power Loss Active(PTPL_A): %d\n",
741                         !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1));
742
743         if(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80)
744         {
745                 printf("    Support indicated in Type mask:\n");
746
747                 printf("      %s: %d\n", pr_type_strs[7], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x80);
748                 printf("      %s: %d\n", pr_type_strs[6], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x40);
749                 printf("      %s: %d\n", pr_type_strs[5], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x20);
750                 printf("      %s: %d\n", pr_type_strs[3], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x8);
751                 printf("      %s: %d\n", pr_type_strs[1], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x2);
752                 printf("      %s: %d\n", pr_type_strs[8], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x100);
753         }
754 }
755
756 void mpath_print_buf_readfullstat( struct prin_resp *pr_buff)
757 {
758
759         int i,j, num;
760         uint64_t  prkey;
761         uint16_t  rel_pt_addr;
762         unsigned char * keyp;
763
764         num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
765         if (0 == num)
766         {
767                 printf("  PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
768                 return ;
769         }
770         else
771                 printf("  PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
772
773         for (i = 0 ; i < num; i++)
774         {
775                 keyp = (unsigned  char *)&pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key;
776
777                 prkey = 0;
778                 for (j = 0; j < 8; ++j) {
779                         if (j > 0)
780                                 prkey <<= 8;
781                         prkey |= *keyp;
782                         ++keyp;
783                 }
784                 printf("   Key = 0x%" PRIx64 "\n", prkey);
785
786                 if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x02)
787                         printf("      All target ports bit set\n");
788                 else {
789                         printf("      All target ports bit clear\n");
790
791                         rel_pt_addr = pr_buff->prin_descriptor.prin_readfd.descriptors[i]->rtpi;
792                         printf("      Relative port address: 0x%x\n",
793                                         rel_pt_addr);
794                 }
795
796                 if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x1) {
797                         printf("      << Reservation holder >>\n");
798                         j = ((pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type >> 4) & 0xf);
799                         if (0 == j)
800                                 printf("      scope: LU_SCOPE, ");
801                         else
802                                 printf("      scope: %d ", j);
803                         j = (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type & 0xf);
804                         printf(" type: %s\n", pr_type_strs[j]);
805                 } else
806                         printf("      not reservation holder\n");
807                 mpath_print_transport_id(pr_buff->prin_descriptor.prin_readfd.descriptors[i]);
808         }
809 }
810
811 static void usage(void)
812 {
813         fprintf(stderr, VERSION_STRING);
814         fprintf(stderr,
815                         "Usage: mpathpersist [OPTIONS] [DEVICE]\n"
816                         " Options:\n"
817                         "    --verbose|-v level         verbosity level\n"
818                         "                   0           Critical messages\n"
819                         "                   1           Error messages\n"
820                         "                   2           Warning messages\n"
821                         "                   3           Informational messages\n"
822                         "                   4           Informational messages with trace enabled\n"
823                         "    --clear|-C                 PR Out: Clear\n"
824                         "    --device=DEVICE|-d DEVICE  query or change DEVICE\n"
825                         "    --batch-file|-f FILE       run commands from FILE\n"
826                         "    --help|-h                  output this usage message\n"
827                         "    --hex|-H                   output response in hex\n"
828                         "    --in|-i                    request PR In command \n"
829                         "    --out|-o                   request PR Out command\n"
830                         "    --param-alltgpt|-Y         PR Out parameter 'ALL_TG_PT\n"
831                         "    --param-aptpl|-Z           PR Out parameter 'APTPL'\n"
832                         "    --read-keys|-k             PR In: Read Keys\n"
833                         "    --param-rk=RK|-K RK        PR Out parameter reservation key\n"
834                         "    --param-sark=SARK|-S SARK  PR Out parameter service action\n"
835                         "                               reservation key (SARK is in hex)\n"
836                         "    --preempt|-P               PR Out: Preempt\n"
837                         "    --preempt-abort|-A         PR Out: Preempt and Abort\n"
838                         "    --prout-type=TYPE|-T TYPE  PR Out command type\n"
839                         "    --read-full-status|-s      PR In: Read Full Status\n"
840                         "    --read-keys|-k             PR In: Read Keys\n"
841                         "    --read-reservation|-r      PR In: Read Reservation\n"
842                         "    --register|-G              PR Out: Register\n"
843                         "    --register-ignore|-I       PR Out: Register and Ignore\n"
844                         "    --release|-L               PR Out: Release\n"
845                         "    --report-capabilities|-c   PR In: Report Capabilities\n"
846                         "    --reserve|-R               PR Out: Reserve\n"
847                         "    --transport-id=TIDS|-X TIDS  TransportIDs can be mentioned\n"
848                         "                                 in several forms\n"
849                         "    --alloc-length=LEN|-l LEN  PR In: maximum allocation length\n"
850                         " Examples:\n"
851                         "     mpathpersist --out --register --param-sark=123abc --prout-type=5 /dev/mapper/mpath9\n"
852                         "     mpathpersist -i -k /dev/mapper/mpath9\n"
853                         "     mpathpersist --out --reserve --param-sark=123abc --prout-type=8 -d /dev/mapper/mpath9\n"
854                         "     mpathpersist -i -s -d /dev/mapper/mpath9\n");
855 }
856
857 void
858 mpath_print_transport_id(struct prin_fulldescr *fdesc)
859 {
860         switch (fdesc->trnptid.protocol_id) {
861         case MPATH_PROTOCOL_ID_FC:
862                 printf("   FCP-2 ");
863                 if (0 != fdesc->trnptid.format_code)
864                         printf(" [Unexpected format code: %d]\n",
865                                         fdesc->trnptid.format_code);
866                 dumpHex((const char *)fdesc->trnptid.n_port_name, 8, 0);
867                 break;
868         case MPATH_PROTOCOL_ID_ISCSI:
869                 printf("   iSCSI ");
870                 if (0 == fdesc->trnptid.format_code) {
871                         printf("name: %.*s\n", (int)sizeof(fdesc->trnptid.iscsi_name),
872                                 fdesc->trnptid.iscsi_name);
873                 }else if (1 == fdesc->trnptid.format_code){
874                         printf("world wide unique port id: %.*s\n",
875                                         (int)sizeof(fdesc->trnptid.iscsi_name),
876                                         fdesc->trnptid.iscsi_name);
877                 }else {
878                         printf("  [Unexpected format code: %d]\n", fdesc->trnptid.format_code);
879                         dumpHex((const char *)fdesc->trnptid.iscsi_name,
880                                  (int)sizeof(fdesc->trnptid.iscsi_name), 0);
881                 }
882                 break;
883         case MPATH_PROTOCOL_ID_SAS:
884                 printf("   SAS ");
885                 if (0 != fdesc->trnptid.format_code)
886                         printf(" [Unexpected format code: %d]\n",
887                                         fdesc->trnptid.format_code);
888                 dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
889                 break;
890         default:
891                 return;
892         }
893 }
894
895 int
896 construct_transportid(const char * lcp, struct transportid transid[], int num_transportids)
897 {
898         int k = 0;
899         int j, n, b, c, len, alen;
900         const char * ecp;
901         const char * isip;
902
903         if ((0 == memcmp("fcp,", lcp, 4)) ||
904                         (0 == memcmp("FCP,", lcp, 4))) {
905                 lcp += 4;
906                 k = strspn(lcp, "0123456789aAbBcCdDeEfF");
907
908                 len = strlen(lcp);
909                 if (len != k) {
910                         fprintf(stderr, "badly formed symbolic FCP TransportID: %s\n",
911                                         lcp);
912                         return 1;
913                 }
914                 transid[num_transportids].format_code = MPATH_PROTOCOL_ID_FC;
915                 transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
916                 for (k = 0, j = 0, b = 0; k < 16; ++k) {
917                         c = lcp[k];
918                         if (isdigit(c))
919                                 n = c - 0x30;
920                         else if (isupper(c))
921                                 n = c - 0x37;
922                         else
923                                 n = c - 0x57;
924                         if (k & 1) {
925                                 transid[num_transportids].n_port_name[j] = b | n;
926                                 ++j;
927                         } else
928                                 b = n << 4;
929                 }
930                 goto my_cont_b;
931         }
932         if ((0 == memcmp("sas,", lcp, 4)) || (0 == memcmp("SAS,", lcp, 4))) {
933                 lcp += 4;
934                 k = strspn(lcp, "0123456789aAbBcCdDeEfF");
935                 len =strlen(lcp);
936                 if (len != k) {
937                         fprintf(stderr, "badly formed symbolic SAS TransportID: %s\n",
938                                         lcp);
939                         return 1;
940                 }
941                 transid[num_transportids].format_code = MPATH_PROTOCOL_ID_SAS;
942                 transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
943                 memcpy(&transid[num_transportids].sas_address, lcp, 8);
944
945                 goto my_cont_b;
946         }
947         if (0 == memcmp("iqn.", lcp, 4)) {
948                 ecp = strpbrk(lcp, " \t");
949                 isip = strstr(lcp, ",i,0x");
950                 if (ecp && (isip > ecp))
951                         isip = NULL;
952                 len = ecp ? (ecp - lcp) : (int)strlen(lcp);
953                 transid[num_transportids].format_code = (isip ? MPATH_WWUI_PORT_IDENTIFIER:MPATH_WWUI_DEVICE_NAME);
954                 transid[num_transportids].protocol_id = MPATH_PROTOCOL_ID_ISCSI;
955                 alen = len + 1; /* at least one trailing null */
956                 if (alen < 20)
957                         alen = 20;
958                 else if (0 != (alen % 4))
959                         alen = ((alen / 4) + 1) * 4;
960                 if (alen > 241) { /* sam5r02.pdf A.2 (Annex) */
961                         fprintf(stderr, "iSCSI name too long, alen=%d\n", alen);
962                         return 0;
963                 }
964                 transid[num_transportids].iscsi_name[1] = alen & 0xff;
965                 memcpy(&transid[num_transportids].iscsi_name[2], lcp, len);
966                 goto my_cont_b;
967         }
968 my_cont_b:
969         if (k >= MPATH_MAX_PARAM_LEN) {
970                 fprintf(stderr, "build_transportid: array length exceeded\n");
971                 return 1;
972         }
973         return 0;
974 }