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