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