10 #include <mpath_persist.h>
16 static const char * pr_type_strs[] = {
22 "Write Exclusive, registrants only",
23 "Exclusive Access, registrants only",
24 "Write Exclusive, all registrants",
25 "Exclusive Access, all registrants",
26 "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
27 "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
30 int get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids);
31 void mpath_print_buf_readcap(struct prin_resp *pr_buff);
32 void mpath_print_buf_readfullstat(struct prin_resp *pr_buff);
33 void mpath_print_buf_readresv(struct prin_resp *pr_buff);
34 void mpath_print_buf_readkeys(struct prin_resp *pr_buff);
35 void dumpHex(const char* str, int len, int no_ascii);
36 void * mpath_alloc_prin_response(int prin_sa);
37 void mpath_print_transport_id(struct prin_fulldescr *fdesc);
38 int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
41 unsigned int mpath_mx_alloc_len;
43 int main (int argc, char * argv[])
46 const char *device_name = NULL;
49 int num_prout_param = 0;
54 uint64_t param_sark = 0;
55 unsigned int prout_type = 0;
56 int param_alltgpt = 0;
58 uint64_t param_rk = 0;
59 unsigned int param_rtp = 0;
60 int num_transportids = 0;
61 struct transportid transportids[MPATH_MX_TIDS];
71 struct transportid * tmp;
76 fprintf (stderr, "No parameter used\n");
83 fprintf (stderr, "need to be root\n");
89 memset(transportids,0,MPATH_MX_TIDS);
95 c = getopt_long (argc, argv, "v:Cd:hHioZK:S:PAT:skrGILcRX:l:",
96 long_options, &option_index);
103 if (1 != sscanf (optarg, "%d", &loglevel))
105 fprintf (stderr, "bad argument to '--verbose'\n");
106 return MPATH_PR_SYNTAX_ERROR;
111 prout_sa = MPATH_PROUT_CLEAR_SA;
116 device_name = optarg;
140 if (1 != sscanf (optarg, "%" SCNx64 "", ¶m_rk))
142 fprintf (stderr, "bad argument to '--param-rk'\n");
143 return MPATH_PR_SYNTAX_ERROR;
149 if (1 != sscanf (optarg, "%" SCNx64 "", ¶m_sark))
151 fprintf (stderr, "bad argument to '--param-sark'\n");
152 return MPATH_PR_SYNTAX_ERROR;
158 prout_sa = MPATH_PROUT_PREE_SA;
163 prout_sa = MPATH_PROUT_PREE_AB_SA;
168 if (1 != sscanf (optarg, "%x", &prout_type))
170 fprintf (stderr, "bad argument to '--prout-type'\n");
171 return MPATH_PR_SYNTAX_ERROR;
177 prin_sa = MPATH_PRIN_RFSTAT_SA;
182 prin_sa = MPATH_PRIN_RKEY_SA;
187 prin_sa = MPATH_PRIN_RRES_SA;
192 prout_sa = MPATH_PROUT_REG_SA;
197 prout_sa = MPATH_PROUT_REG_IGN_SA;
202 prout_sa = MPATH_PROUT_REL_SA;
207 prin_sa = MPATH_PRIN_RCAP_SA;
212 prout_sa = MPATH_PROUT_RES_SA;
217 if (0 != construct_transportid(optarg, transportids, num_transport)) {
218 fprintf(stderr, "bad argument to '--transport-id'\n");
219 return MPATH_PR_SYNTAX_ERROR;
226 if (1 != sscanf(optarg, "%u", &mpath_mx_alloc_len)) {
227 fprintf(stderr, "bad argument to '--alloc-length'\n");
228 return MPATH_PR_SYNTAX_ERROR;
229 } else if (MPATH_MAX_PARAM_LEN < mpath_mx_alloc_len) {
230 fprintf(stderr, "'--alloc-length' argument exceeds maximum"
231 " limit(%d)\n", MPATH_MAX_PARAM_LEN);
232 return MPATH_PR_SYNTAX_ERROR;
237 fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c);
239 ret = MPATH_PR_SYNTAX_ERROR;
247 if (NULL == device_name)
249 device_name = argv[optind];
254 for (; optind < argc; ++optind)
255 fprintf (stderr, "Unexpected extra argument: %s\n", argv[optind]);
257 ret = MPATH_PR_SYNTAX_ERROR;
263 noisy = (loglevel >= 3) ? 1 : hex;
264 verbose = (loglevel >= 3)? 3: loglevel;
266 if ((prout_flag + prin_flag) == 0)
268 fprintf (stderr, "choose either '--in' or '--out' \n");
270 ret = MPATH_PR_SYNTAX_ERROR;
273 if ((prout_flag + prin_flag) > 1)
275 fprintf (stderr, "choose either '--in' or '--out' \n");
277 ret = MPATH_PR_SYNTAX_ERROR;
281 { /* syntax check on PROUT arguments */
283 if ((1 != num_prout_sa) || (0 != num_prin_sa))
285 fprintf (stderr, " For Persistent Reserve Out only one "
286 "appropriate\n service action must be "
288 ret = MPATH_PR_SYNTAX_ERROR;
293 { /* syntax check on PRIN arguments */
295 if (num_prout_sa > 0)
297 fprintf (stderr, " When a service action for Persistent "
298 "Reserve Out is chosen the\n"
299 " '--out' option must be given \n");
300 ret = MPATH_PR_SYNTAX_ERROR;
303 if (0 == num_prin_sa)
306 " No service action given for Persistent Reserve IN\n");
308 ret = MPATH_PR_SYNTAX_ERROR;
310 else if (num_prin_sa > 1)
312 fprintf (stderr, " Too many service actions given; choose "
315 ret = MPATH_PR_SYNTAX_ERROR;
321 ret = MPATH_PR_SYNTAX_ERROR;
325 if ((param_rtp) && (MPATH_PROUT_REG_MOV_SA != prout_sa))
327 fprintf (stderr, " --relative-target-port"
328 " only useful with --register-move\n");
330 ret = MPATH_PR_SYNTAX_ERROR;
334 if (((MPATH_PROUT_RES_SA == prout_sa) ||
335 (MPATH_PROUT_REL_SA == prout_sa) ||
336 (MPATH_PROUT_PREE_SA == prout_sa) ||
337 (MPATH_PROUT_PREE_AB_SA == prout_sa)) &&
339 fprintf(stderr, "Warning: --prout-type probably needs to be "
342 if ((verbose > 2) && num_transportids)
344 fprintf (stderr, "number of tranport-ids decoded from "
345 "command line : %d\n", num_transportids);
348 if (device_name == NULL)
350 fprintf (stderr, "No device name given \n");
352 ret = MPATH_PR_SYNTAX_ERROR;
357 if ((fd = open (device_name, O_WRONLY)) < 0)
359 fprintf (stderr, "%s: error opening file (rw) fd=%d\n",
361 ret = MPATH_PR_FILE_ERROR;
368 resp = mpath_alloc_prin_response(prin_sa);
371 fprintf (stderr, "failed to allocate PRIN response buffer\n");
372 ret = MPATH_PR_OTHER;
376 ret = mpath_persistent_reserve_in (fd, prin_sa, resp, noisy, verbose);
377 if (ret != MPATH_PR_SUCCESS )
379 fprintf (stderr, "Persistent Reserve IN command failed\n");
385 case MPATH_PRIN_RKEY_SA:
386 mpath_print_buf_readkeys(resp);
388 case MPATH_PRIN_RRES_SA:
389 mpath_print_buf_readresv(resp);
391 case MPATH_PRIN_RCAP_SA:
392 mpath_print_buf_readcap(resp);
394 case MPATH_PRIN_RFSTAT_SA:
395 mpath_print_buf_readfullstat(resp);
404 struct prout_param_descriptor *paramp;
405 t_arr_len = MPATH_MX_TID_LEN * num_transport;
407 paramp= malloc(sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS )));
409 memset(paramp, 0, sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS)));
411 for (j = 7; j >= 0; --j) {
412 paramp->key[j] = (param_rk & 0xff);
416 for (j = 7; j >= 0; --j) {
417 paramp->sa_key[j] = (param_sark & 0xff);
422 paramp->sa_flags |= 0x4;
424 paramp->sa_flags |= 0x1;
428 paramp->sa_flags |= MPATH_F_SPEC_I_PT_MASK;
429 paramp->num_transportid = num_transport;
430 for (j = 0 ; j < num_transport; j++)
432 paramp->trnptid_list[j] = (struct transportid *)malloc(sizeof(struct transportid));
433 memcpy(paramp->trnptid_list[j], &transportids[j],sizeof(struct transportid));
437 /* PROUT commands other than 'register and move' */
438 ret = mpath_persistent_reserve_out (fd, prout_sa, 0, prout_type,
439 paramp, noisy, verbose);
440 for (j = 0 ; j < num_transport; j++)
442 tmp = paramp->trnptid_list[j];
448 if (ret != MPATH_PR_SUCCESS)
452 case MPATH_PR_SENSE_UNIT_ATTENTION:
453 printf("persistent reserve out: scsi status: Unit Attention\n");
455 case MPATH_PR_RESERV_CONFLICT:
456 printf("persistent reserve out: scsi status: Reservation Conflict\n");
459 printf("PR out: command failed\n");
466 return MPATH_PR_FILE_ERROR;
472 return (ret >= 0) ? ret : MPATH_PR_OTHER;
476 get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids)
479 unsigned char * ucp = transportid_arr;
480 int k, off, protocol_id, len;
481 for (k = 0, off = 0; ((k < num_transportids) && (k < max_transportid));
482 ++k, off += MPATH_MX_TID_LEN) {
483 protocol_id = ucp[off] & 0xf;
484 if (5 == protocol_id) {
485 len = (ucp[off + 2] << 8) + ucp[off + 3] + 4;
488 if (off > compact_len)
489 memmove(ucp + compact_len, ucp + off, len);
493 if (off > compact_len)
494 memmove(ucp + compact_len, ucp + off, 24);
502 void mpath_print_buf_readkeys( struct prin_resp *pr_buff)
507 printf(" PR generation=0x%x, ", pr_buff->prin_descriptor.prin_readkeys.prgeneration);
509 num = pr_buff->prin_descriptor.prin_readkeys.additional_length / 8;
511 printf(" 0 registered reservation key.\n");
515 printf(" 1 registered reservation key follows:\n");
517 printf(" %d registered reservation keys follow:\n", num);
520 keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
521 for (i = 0; i < num ; i++)
524 for (j = 0; j < 8; ++j) {
530 printf(" 0x%" PRIx64 "\n", prkey);
532 keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[k];
536 void mpath_print_buf_readresv( struct prin_resp *pr_buff)
538 int j, num, scope=0, type=0;
542 num = pr_buff->prin_descriptor.prin_readresv.additional_length / 8;
545 printf(" PR generation=0x%x, there is NO reservation held \n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
549 printf(" PR generation=0x%x, Reservation follows:\n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
550 keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
552 for (j = 0; j < 8; ++j) {
558 printf(" Key = 0x%" PRIx64 "\n", prkey);
560 scope = (pr_buff->prin_descriptor.prin_readresv.scope_type >> 4) & 0x0f;
561 type = pr_buff->prin_descriptor.prin_readresv.scope_type & 0x0f;
564 printf(" scope = LU_SCOPE, type = %s", pr_type_strs[type]);
566 printf(" scope = %d, type = %s", scope, pr_type_strs[type]);
572 void mpath_print_buf_readcap( struct prin_resp *pr_buff)
574 if ( pr_buff->prin_descriptor.prin_readcap.length <= 2 ) {
575 fprintf(stderr, "Unexpected response for PRIN Report "
580 printf("Report capabilities response:\n");
582 printf(" Compatible Reservation Handling(CRH): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10));
583 printf(" Specify Initiator Ports Capable(SIP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8));
584 printf(" All Target Ports Capable(ATP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4 ));
585 printf(" Persist Through Power Loss Capable(PTPL_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0]));
586 printf(" Type Mask Valid(TMV): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80));
587 printf(" Allow Commands: %d\n", !!(( pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7));
588 printf(" Persist Through Power Loss Active(PTPL_A): %d\n",
589 !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1));
591 if(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80)
593 printf(" Support indicated in Type mask:\n");
595 printf(" %s: %d\n", pr_type_strs[7], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x80);
596 printf(" %s: %d\n", pr_type_strs[6], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x40);
597 printf(" %s: %d\n", pr_type_strs[5], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x20);
598 printf(" %s: %d\n", pr_type_strs[3], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x8);
599 printf(" %s: %d\n", pr_type_strs[1], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x2);
600 printf(" %s: %d\n", pr_type_strs[8], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x100);
604 void mpath_print_buf_readfullstat( struct prin_resp *pr_buff)
609 uint16_t rel_pt_addr;
610 unsigned char * keyp;
612 num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
615 printf(" PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
619 printf(" PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
621 for (i = 0 ; i < num; i++)
623 keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key;
626 for (j = 0; j < 8; ++j) {
632 printf(" Key = 0x%" PRIx64 "\n", prkey);
634 if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x02)
635 printf(" All target ports bit set\n");
637 printf(" All target ports bit clear\n");
639 rel_pt_addr = pr_buff->prin_descriptor.prin_readfd.descriptors[i]->rtpi;
640 printf(" Relative port address: 0x%x\n",
644 if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x1) {
645 printf(" << Reservation holder >>\n");
646 j = ((pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type>> 4) & 0xf);
648 printf(" scope: LU_SCOPE, ");
650 printf(" scope: %d ", j);
651 j = (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type & 0xf);
652 printf(" type: %s\n", pr_type_strs[j]);
654 printf(" not reservation holder\n");
655 mpath_print_transport_id(pr_buff->prin_descriptor.prin_readfd.descriptors[i]);
662 "Usage: mpathpersist [OPTIONS] [DEVICE]\n"
664 " --verbose|-v level verbosity level\n"
665 " 0 Critical messages\n"
666 " 1 Error messages\n"
667 " 2 Warning messages\n"
668 " 3 Informational messages\n"
669 " 4 Informational messages with trace enabled\n"
670 " --clear|-C PR Out: Clear\n"
671 " --device=DEVICE|-d DEVICE query or change DEVICE\n"
672 " --help|-h output this usage message\n"
673 " --hex|-H output response in hex\n"
674 " --in|-i request PR In command \n"
675 " --out|-o request PR Out command\n"
676 " --param-aptpl|-Z PR Out parameter 'APTPL'\n"
677 " --read-keys|-k PR In: Read Keys\n"
678 " --param-sark=SARK|-S SARK PR Out parameter service "
680 " reservation key (SARK is in "
682 " --preempt|-P PR Out: Preempt\n"
683 " --preempt-abort|-A PR Out: Preempt and Abort\n"
684 " --prout-type=TYPE|-T TYPE PR Out command type\n"
685 " --read-full-status|-s PR In: Read Full Status\n"
686 " --read-keys|-k PR In: Read Keys\n"
687 " --read-reservation|-r PR In: Read Reservation\n"
688 " --register|-G PR Out: Register\n"
689 " --register-ignore|-I PR Out: Register and Ignore\n"
690 " --release|-L PR Out: Release\n"
691 " --report-capabilities|-c PR In: Report Capabilities\n"
692 " --reserve|-R PR Out: Reserve\n"
693 " --transport-id=TIDS|-X TIDS TransportIDs can be mentioned \n"
694 " in several forms\n"
696 " mpathpersist --out --register --param-sark=123abc --prout-type=5 /dev/mapper/mpath9\n"
697 " mpathpersist -i -k /dev/mapper/mpath9\n" );
701 mpath_print_transport_id(struct prin_fulldescr *fdesc)
703 switch (fdesc->trnptid.protocol_id) {
704 case MPATH_PROTOCOL_ID_FC:
706 if (0 != fdesc->trnptid.format_code)
707 printf(" [Unexpected format code: %d]\n",
708 fdesc->trnptid.format_code);
709 dumpHex((const char *)fdesc->trnptid.n_port_name, 8, 0);
711 case MPATH_PROTOCOL_ID_ISCSI:
713 if (0 == fdesc->trnptid.format_code) {
714 printf("name: %.*s\n", (int)sizeof(fdesc->trnptid.iscsi_name),
715 fdesc->trnptid.iscsi_name);
716 }else if (1 == fdesc->trnptid.format_code){
717 printf("world wide unique port id: %.*s\n",
718 (int)sizeof(fdesc->trnptid.iscsi_name),
719 fdesc->trnptid.iscsi_name);
721 printf(" [Unexpected format code: %d]\n", fdesc->trnptid.format_code);
722 dumpHex((const char *)fdesc->trnptid.iscsi_name,
723 (int)sizeof(fdesc->trnptid.iscsi_name), 0);
726 case MPATH_PROTOCOL_ID_SAS:
728 if (0 != fdesc->trnptid.format_code)
729 printf(" [Unexpected format code: %d]\n",
730 fdesc->trnptid.format_code);
731 dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
739 construct_transportid(const char * lcp, struct transportid transid[], int num_transportids)
741 unsigned char * tidp;
743 int j, n, b, c, len, alen;
747 if ((0 == memcmp("fcp,", lcp, 4)) ||
748 (0 == memcmp("FCP,", lcp, 4))) {
750 k = strspn(lcp, "0123456789aAbBcCdDeEfF");
754 fprintf(stderr, "badly formed symbolic FCP TransportID: %s\n",
758 transid[num_transportids].format_code = MPATH_PROTOCOL_ID_FC;
759 transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
760 for (k = 0, j = 0, b = 0; k < 16; ++k) {
769 transid[num_transportids].n_port_name[j] = b | n;
776 if ((0 == memcmp("sas,", lcp, 4)) || (0 == memcmp("SAS,", lcp, 4))) {
778 k = strspn(lcp, "0123456789aAbBcCdDeEfF");
781 fprintf(stderr, "badly formed symbolic SAS TransportID: %s\n",
785 transid[num_transportids].format_code = MPATH_PROTOCOL_ID_SAS;
786 transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
787 memcpy(&transid[num_transportids].sas_address, lcp, 8);
791 if (0 == memcmp("iqn.", lcp, 4)) {
792 ecp = strpbrk(lcp, " \t");
793 isip = strstr(lcp, ",i,0x");
794 if (ecp && (isip > ecp))
796 len = ecp ? (ecp - lcp) : (int)strlen(lcp);
797 memset(&tidp, 0, 24);
798 transid[num_transportids].format_code = (isip ? MPATH_WWUI_PORT_IDENTIFIER:MPATH_WWUI_DEVICE_NAME);
799 transid[num_transportids].protocol_id = MPATH_PROTOCOL_ID_ISCSI;
800 alen = len + 1; /* at least one trailing null */
803 else if (0 != (alen % 4))
804 alen = ((alen / 4) + 1) * 4;
805 if (alen > 241) { /* sam5r02.pdf A.2 (Annex) */
806 fprintf(stderr, "iSCSI name too long, alen=%d\n", alen);
809 transid[num_transportids].iscsi_name[1] = alen & 0xff;
810 memcpy(&transid[num_transportids].iscsi_name[2], lcp, len);
814 if (k >= MPATH_MAX_PARAM_LEN) {
815 fprintf(stderr, "build_transportid: array length exceeded\n");