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