61818e08e3cb9140e111a86fa74a119fae6ddc39
[multipath-tools/.git] / libmpathpersist / mpath_persist.c
1 #include <libdevmapper.h>
2 #include "defaults.h"
3 #include <sys/stat.h>
4 #include <sys/types.h>
5 #include <fcntl.h>
6 #include "vector.h"
7 #include "checkers.h"
8 #include "structs.h"
9 #include "structs_vec.h"
10 #include <libudev.h>
11
12 #include "prio.h"
13 #include <unistd.h>
14 #include "devmapper.h"
15 #include "debug.h"
16 #include "config.h"
17 #include "switchgroup.h"
18 #include "discovery.h"
19 #include "dmparser.h"
20 #include <ctype.h>
21 #include "propsel.h"
22 #include "util.h"
23
24 #include "mpath_persist.h"
25 #include "mpathpr.h"
26 #include "mpath_pr_ioctl.h"
27
28 #include <pthread.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/resource.h>
34
35 #define __STDC_FORMAT_MACROS 1
36
37 extern struct udev *udev;
38
39 struct config *
40 mpath_lib_init (void)
41 {
42         struct config *conf;
43
44         conf = load_config(DEFAULT_CONFIGFILE);
45         if (!conf) {
46                 condlog(0, "Failed to initialize multipath config.");
47                 return NULL;
48         }
49
50         if (conf->max_fds) {
51                 struct rlimit fd_limit;
52
53                 fd_limit.rlim_cur = conf->max_fds;
54                 fd_limit.rlim_max = conf->max_fds;
55                 if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
56                         condlog(0, "can't set open fds limit to %d : %s",
57                                    conf->max_fds, strerror(errno));
58         }
59
60         return conf;
61 }
62
63 int
64 mpath_lib_exit (struct config *conf)
65 {
66         dm_lib_release();
67         dm_lib_exit();
68         cleanup_prio();
69         cleanup_checkers();
70         free_config(conf);
71         conf = NULL;
72         return 0;
73 }
74
75 static int
76 updatepaths (struct multipath * mpp)
77 {
78         int i, j;
79         struct pathgroup * pgp;
80         struct path * pp;
81         struct config *conf;
82
83         if (!mpp->pg)
84                 return 0;
85
86         vector_foreach_slot (mpp->pg, pgp, i){
87                 if (!pgp->paths)
88                         continue;
89
90                 vector_foreach_slot (pgp->paths, pp, j){
91                         if (!strlen(pp->dev)){
92                                 if (devt2devname(pp->dev, FILE_NAME_SIZE,
93                                                  pp->dev_t)){
94                                         /*
95                                          * path is not in sysfs anymore
96                                          */
97                                         pp->state = PATH_DOWN;
98                                         continue;
99                                 }
100                                 pp->mpp = mpp;
101                                 conf = get_multipath_config();
102                                 pathinfo(pp, conf, DI_ALL);
103                                 put_multipath_config(conf);
104                                 continue;
105                         }
106                         pp->mpp = mpp;
107                         if (pp->state == PATH_UNCHECKED ||
108                                         pp->state == PATH_WILD) {
109                                 conf = get_multipath_config();
110                                 pathinfo(pp, conf, DI_CHECKER);
111                                 put_multipath_config(conf);
112                         }
113
114                         if (pp->priority == PRIO_UNDEF) {
115                                 conf = get_multipath_config();
116                                 pathinfo(pp, conf, DI_PRIO);
117                                 put_multipath_config(conf);
118                         }
119                 }
120         }
121         return 0;
122 }
123
124 int
125 mpath_prin_activepath (struct multipath *mpp, int rq_servact,
126         struct prin_resp * resp, int noisy)
127 {
128         int i,j, ret = MPATH_PR_DMMP_ERROR;
129         struct pathgroup *pgp = NULL;
130         struct path *pp = NULL;
131
132         vector_foreach_slot (mpp->pg, pgp, j){
133                 vector_foreach_slot (pgp->paths, pp, i){
134                         if (!((pp->state == PATH_UP) ||
135                               (pp->state == PATH_GHOST))){
136                                 condlog(2, "%s: %s not available. Skip.",
137                                         mpp->wwid, pp->dev);
138                                 condlog(3, "%s: status = %d.",
139                                         mpp->wwid, pp->state);
140                                 continue;
141                         }
142
143                         condlog(3, "%s: sending pr in command to %s ",
144                                 mpp->wwid, pp->dev);
145                         ret = mpath_send_prin_activepath(pp->dev, rq_servact,
146                                                          resp, noisy);
147                         switch(ret)
148                         {
149                                 case MPATH_PR_SUCCESS:
150                                 case MPATH_PR_SENSE_INVALID_OP:
151                                         return ret;
152                                 default:
153                                         continue;
154                         }
155                 }
156         }
157         return ret;
158 }
159
160 int mpath_persistent_reserve_in (int fd, int rq_servact,
161         struct prin_resp *resp, int noisy, int verbose)
162 {
163         struct stat info;
164         vector curmp = NULL;
165         vector pathvec = NULL;
166         char * alias;
167         struct multipath * mpp;
168         int map_present;
169         int major, minor;
170         int ret;
171         struct config *conf;
172
173         conf = get_multipath_config();
174         conf->verbosity = verbose;
175         put_multipath_config(conf);
176
177         if (fstat( fd, &info) != 0){
178                 condlog(0, "stat error %d", fd);
179                 return MPATH_PR_FILE_ERROR;
180         }
181         if(!S_ISBLK(info.st_mode)){
182                 condlog(0, "Failed to get major:minor. fd = %d", fd);
183                 return MPATH_PR_FILE_ERROR;
184         }
185
186         major = major(info.st_rdev);
187         minor = minor(info.st_rdev);
188         condlog(4, "Device %d:%d:  ", major, minor);
189
190         /* get alias from major:minor*/
191         alias = dm_mapname(major, minor);
192         if (!alias){
193                 condlog(0, "%d:%d failed to get device alias.", major, minor);
194                 return MPATH_PR_DMMP_ERROR;
195         }
196
197         condlog(3, "alias = %s", alias);
198         map_present = dm_map_present(alias);
199         if (map_present && !dm_is_mpath(alias)){
200                 condlog( 0, "%s: not a multipath device.", alias);
201                 ret = MPATH_PR_DMMP_ERROR;
202                 goto out;
203         }
204
205         /*
206          * allocate core vectors to store paths and multipaths
207          */
208         curmp = vector_alloc ();
209         pathvec = vector_alloc ();
210
211         if (!curmp || !pathvec){
212                 condlog (0, "%s: vector allocation failed.", alias);
213                 ret = MPATH_PR_DMMP_ERROR;
214                 if (curmp)
215                         vector_free(curmp);
216                 if (pathvec)
217                         vector_free(pathvec);
218                 goto out;
219         }
220
221         if (path_discovery(pathvec, DI_SYSFS | DI_CHECKER) < 0) {
222                 ret = MPATH_PR_DMMP_ERROR;
223                 goto out1;
224         }
225
226         /* get info of all paths from the dm device     */
227         if (get_mpvec (curmp, pathvec, alias)){
228                 condlog(0, "%s: failed to get device info.", alias);
229                 ret = MPATH_PR_DMMP_ERROR;
230                 goto out1;
231         }
232
233         mpp = find_mp_by_alias(curmp, alias);
234         if (!mpp){
235                 condlog(0, "%s: devmap not registered.", alias);
236                 ret = MPATH_PR_DMMP_ERROR;
237                 goto out1;
238         }
239
240         ret = mpath_prin_activepath(mpp, rq_servact, resp, noisy);
241
242 out1:
243         free_multipathvec(curmp, KEEP_PATHS);
244         free_pathvec(pathvec, FREE_PATHS);
245 out:
246         FREE(alias);
247         return ret;
248 }
249
250 int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
251         unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose)
252 {
253
254         struct stat info;
255
256         vector curmp = NULL;
257         vector pathvec = NULL;
258
259         char * alias;
260         struct multipath * mpp;
261         int map_present;
262         int major, minor;
263         int ret;
264         uint64_t prkey;
265         struct config *conf;
266
267         conf = get_multipath_config();
268         conf->verbosity = verbose;
269         put_multipath_config(conf);
270
271         if (fstat( fd, &info) != 0){
272                 condlog(0, "stat error fd=%d", fd);
273                 return MPATH_PR_FILE_ERROR;
274         }
275
276         if(!S_ISBLK(info.st_mode)){
277                 condlog(3, "Failed to get major:minor. fd=%d", fd);
278                 return MPATH_PR_FILE_ERROR;
279         }
280
281         major = major(info.st_rdev);
282         minor = minor(info.st_rdev);
283         condlog(4, "Device  %d:%d", major, minor);
284
285         /* get WWN of the device from major:minor*/
286         alias = dm_mapname(major, minor);
287         if (!alias){
288                 return MPATH_PR_DMMP_ERROR;
289         }
290
291         condlog(3, "alias = %s", alias);
292         map_present = dm_map_present(alias);
293
294         if (map_present && !dm_is_mpath(alias)){
295                 condlog(3, "%s: not a multipath device.", alias);
296                 ret = MPATH_PR_DMMP_ERROR;
297                 goto out;
298         }
299
300         /*
301          * allocate core vectors to store paths and multipaths
302          */
303         curmp = vector_alloc ();
304         pathvec = vector_alloc ();
305
306         if (!curmp || !pathvec){
307                 condlog (0, "%s: vector allocation failed.", alias);
308                 ret = MPATH_PR_DMMP_ERROR;
309                 if (curmp)
310                         vector_free(curmp);
311                 if (pathvec)
312                         vector_free(pathvec);
313                 goto out;
314         }
315
316         if (path_discovery(pathvec, DI_SYSFS | DI_CHECKER) < 0) {
317                 ret = MPATH_PR_DMMP_ERROR;
318                 goto out1;
319         }
320
321         /* get info of all paths from the dm device     */
322         if (get_mpvec(curmp, pathvec, alias)){
323                 condlog(0, "%s: failed to get device info.", alias);
324                 ret = MPATH_PR_DMMP_ERROR;
325                 goto out1;
326         }
327
328         mpp = find_mp_by_alias(curmp, alias);
329
330         if (!mpp) {
331                 condlog(0, "%s: devmap not registered.", alias);
332                 ret = MPATH_PR_DMMP_ERROR;
333                 goto out1;
334         }
335
336         conf = get_multipath_config();
337         select_reservation_key(conf, mpp);
338         select_all_tg_pt(conf, mpp);
339         put_multipath_config(conf);
340
341         memcpy(&prkey, paramp->sa_key, 8);
342         if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
343             ((!get_be64(mpp->reservation_key) &&
344               rq_servact == MPATH_PROUT_REG_SA) ||
345              rq_servact == MPATH_PROUT_REG_IGN_SA)) {
346                 memcpy(&mpp->reservation_key, paramp->sa_key, 8);
347                 if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
348                                        paramp->sa_flags)) {
349                         condlog(0, "%s: failed to set prkey for multipathd.",
350                                 alias);
351                         ret = MPATH_PR_DMMP_ERROR;
352                         goto out1;
353                 }
354         }
355
356         if (memcmp(paramp->key, &mpp->reservation_key, 8) &&
357             memcmp(paramp->sa_key, &mpp->reservation_key, 8)) {
358                 condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key));
359                 ret = MPATH_PR_SYNTAX_ERROR;
360                 goto out1;
361         }
362
363         switch(rq_servact)
364         {
365         case MPATH_PROUT_REG_SA:
366         case MPATH_PROUT_REG_IGN_SA:
367                 ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
368                 break;
369         case MPATH_PROUT_RES_SA :
370         case MPATH_PROUT_PREE_SA :
371         case MPATH_PROUT_PREE_AB_SA :
372         case MPATH_PROUT_CLEAR_SA:
373                 ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
374                 break;
375         case MPATH_PROUT_REL_SA:
376                 ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
377                 break;
378         default:
379                 ret = MPATH_PR_OTHER;
380                 goto out1;
381         }
382
383         if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
384                                 (rq_servact ==  MPATH_PROUT_REG_IGN_SA)))
385         {
386                 if (prkey == 0) {
387                         update_prflag(alias, 0);
388                         update_prkey(alias, 0);
389                 } else
390                         update_prflag(alias, 1);
391         } else if ((ret == MPATH_PR_SUCCESS) && (rq_servact == MPATH_PROUT_CLEAR_SA)) {
392                 update_prflag(alias, 0);
393                 update_prkey(alias, 0);
394         }
395 out1:
396         free_multipathvec(curmp, KEEP_PATHS);
397         free_pathvec(pathvec, FREE_PATHS);
398
399 out:
400         FREE(alias);
401         return ret;
402 }
403
404 int
405 get_mpvec (vector curmp, vector pathvec, char * refwwid)
406 {
407         int i;
408         struct multipath *mpp;
409         char params[PARAMS_SIZE], status[PARAMS_SIZE];
410
411         if (dm_get_maps (curmp)){
412                 return 1;
413         }
414
415         vector_foreach_slot (curmp, mpp, i){
416                 /*
417                  * discard out of scope maps
418                  */
419                 if (mpp->alias && refwwid &&
420                     strncmp (mpp->alias, refwwid, WWID_SIZE - 1)){
421                         free_multipath (mpp, KEEP_PATHS);
422                         vector_del_slot (curmp, i);
423                         i--;
424                         continue;
425                 }
426
427                 dm_get_map(mpp->alias, &mpp->size, params);
428                 condlog(3, "params = %s", params);
429                 dm_get_status(mpp->alias, status);
430                 condlog(3, "status = %s", status);
431                 disassemble_map (pathvec, params, mpp, 0);
432
433                 /*
434                  * disassemble_map() can add new paths to pathvec.
435                  * If not in "fast list mode", we need to fetch information
436                  * about them
437                  */
438                 updatepaths(mpp);
439                 mpp->bestpg = select_path_group (mpp);
440                 disassemble_status (status, mpp);
441
442         }
443         return MPATH_PR_SUCCESS ;
444 }
445
446 int mpath_send_prin_activepath (char * dev, int rq_servact,
447                                 struct prin_resp * resp, int noisy)
448 {
449
450         int rc;
451
452         rc = prin_do_scsi_ioctl(dev, rq_servact, resp,  noisy);
453
454         return (rc);
455 }
456
457 int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
458         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
459 {
460
461         int i, j, k;
462         struct pathgroup *pgp = NULL;
463         struct path *pp = NULL;
464         int rollback = 0;
465         int active_pathcount=0;
466         int rc;
467         int count=0;
468         int status = MPATH_PR_SUCCESS;
469         int all_tg_pt;
470         uint64_t sa_key = 0;
471
472         if (!mpp)
473                 return MPATH_PR_DMMP_ERROR;
474
475         all_tg_pt = (mpp->all_tg_pt == ALL_TG_PT_ON ||
476                      paramp->sa_flags & MPATH_F_ALL_TG_PT_MASK);
477         active_pathcount = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
478
479         if (active_pathcount == 0) {
480                 condlog (0, "%s: no path available", mpp->wwid);
481                 return MPATH_PR_DMMP_ERROR;
482         }
483
484         struct threadinfo thread[active_pathcount];
485         int hosts[active_pathcount];
486
487         memset(thread, 0, sizeof(thread));
488
489         /* init thread parameter */
490         for (i =0; i< active_pathcount; i++){
491                 hosts[i] = -1;
492                 thread[i].param.rq_servact = rq_servact;
493                 thread[i].param.rq_scope = rq_scope;
494                 thread[i].param.rq_type = rq_type;
495                 thread[i].param.paramp = paramp;
496                 thread[i].param.noisy = noisy;
497                 thread[i].param.status = MPATH_PR_SKIP;
498
499                 condlog (3, "THREAD ID [%d] INFO]", i);
500                 condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
501                 condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
502                 condlog (3, "rq_type=%d ", thread[i].param.rq_type);
503                 condlog (3, "rkey=");
504                 condlog (3, "paramp->sa_flags =%02x ",
505                          thread[i].param.paramp->sa_flags);
506                 condlog (3, "noisy=%d ", thread[i].param.noisy);
507                 condlog (3, "status=%d ", thread[i].param.status);
508         }
509
510         pthread_attr_t attr;
511         pthread_attr_init(&attr);
512         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
513
514         vector_foreach_slot (mpp->pg, pgp, j){
515                 vector_foreach_slot (pgp->paths, pp, i){
516                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
517                                 condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev);
518                                 continue;
519                         }
520                         if (all_tg_pt && pp->sg_id.host_no != -1) {
521                                 for (k = 0; k < count; k++) {
522                                         if (pp->sg_id.host_no == hosts[k]) {
523                                                 condlog(3, "%s: %s host %d matches skip.", pp->wwid, pp->dev, pp->sg_id.host_no);
524                                                 break;
525                                         }
526                                 }
527                                 if (k < count)
528                                         continue;
529                         }
530                         strncpy(thread[count].param.dev, pp->dev,
531                                 FILE_NAME_SIZE - 1);
532
533                         if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){
534                                 /*
535                                  * Clearing SPEC_I_PT as transportids are already registered by now.
536                                  */
537                                 thread[count].param.paramp->sa_flags &= (~MPATH_F_SPEC_I_PT_MASK);
538                         }
539
540                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
541
542                         rc = pthread_create(&thread[count].id, &attr, mpath_prout_pthread_fn, (void *)(&thread[count].param));
543                         if (rc){
544                                 condlog (0, "%s: failed to create thread %d", mpp->wwid, rc);
545                                 thread[count].param.status = MPATH_PR_THREAD_ERROR;
546                         }
547                         else
548                                 hosts[count] = pp->sg_id.host_no;
549                         count = count + 1;
550                 }
551         }
552         for( i=0; i < count ; i++){
553                 if (thread[i].param.status != MPATH_PR_THREAD_ERROR) {
554                         rc = pthread_join(thread[i].id, NULL);
555                         if (rc){
556                                 condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
557                         }
558                 }
559                 if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){
560                         rollback = 1;
561                         sa_key = 0;
562                         for (i = 0; i < 8; ++i){
563                                 if (i > 0)
564                                         sa_key <<= 8;
565                                 sa_key |= paramp->sa_key[i];
566                         }
567                         status = MPATH_PR_RESERV_CONFLICT ;
568                 }
569                 if (!rollback && (status == MPATH_PR_SUCCESS)){
570                         status = thread[i].param.status;
571                 }
572         }
573         if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
574                 condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
575                 for( i=0 ; i < count ; i++){
576                         if(thread[i].param.status == MPATH_PR_SUCCESS) {
577                                 memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8);
578                                 memset(&thread[i].param.paramp->sa_key, 0, 8);
579                                 thread[i].param.status = MPATH_PR_SUCCESS;
580                                 rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn,
581                                                 (void *)(&thread[i].param));
582                                 if (rc){
583                                         condlog (0, "%s: failed to create thread for rollback. %d",  mpp->wwid, rc);
584                                         thread[i].param.status = MPATH_PR_THREAD_ERROR;
585                                 }
586                         } else
587                                 thread[i].param.status = MPATH_PR_SKIP;
588                 }
589                 for(i=0; i < count ; i++){
590                         if (thread[i].param.status != MPATH_PR_SKIP &&
591                             thread[i].param.status != MPATH_PR_THREAD_ERROR) {
592                                 rc = pthread_join(thread[i].id, NULL);
593                                 if (rc){
594                                         condlog (3, "%s: failed to join thread while rolling back %d",
595                                                  mpp->wwid, i);
596                                 }
597                         }
598                 }
599         }
600
601         pthread_attr_destroy(&attr);
602         return (status);
603 }
604
605 void * mpath_prout_pthread_fn(void *p)
606 {
607         int ret;
608         struct prout_param * param = (struct prout_param *)p;
609
610         ret = prout_do_scsi_ioctl( param->dev,param->rq_servact, param->rq_scope,
611                         param->rq_type, param->paramp, param->noisy);
612         param->status = ret;
613         pthread_exit(NULL);
614 }
615
616 int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
617         unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy)
618 {
619         int i,j, ret;
620         struct pathgroup *pgp = NULL;
621         struct path *pp = NULL;
622
623         vector_foreach_slot (mpp->pg, pgp, j){
624                 vector_foreach_slot (pgp->paths, pp, i){
625                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
626                                 condlog (1, "%s: %s path not up. Skip",
627                                          mpp->wwid, pp->dev);
628                                 continue;
629                         }
630
631                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
632                         ret = send_prout_activepath(pp->dev, rq_servact,
633                                                     rq_scope, rq_type,
634                                                     paramp, noisy);
635                         return ret ;
636                 }
637         }
638         return MPATH_PR_SUCCESS;
639 }
640
641 int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
642         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
643 {
644         struct prout_param param;
645         param.rq_servact = rq_servact;
646         param.rq_scope  = rq_scope;
647         param.rq_type   = rq_type;
648         param.paramp    = paramp;
649         param.noisy = noisy;
650         param.status = -1;
651
652         pthread_t thread;
653         pthread_attr_t attr;
654         int rc;
655
656         memset(&thread, 0, sizeof(thread));
657         strncpy(param.dev, dev, FILE_NAME_SIZE - 1);
658         /* Initialize and set thread joinable attribute */
659         pthread_attr_init(&attr);
660         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
661
662         rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(&param));
663         if (rc){
664                 condlog (3, "%s: failed to create thread %d", dev, rc);
665                 return MPATH_PR_THREAD_ERROR;
666         }
667         /* Free attribute and wait for the other threads */
668         pthread_attr_destroy(&attr);
669         rc = pthread_join(thread, NULL);
670
671         return (param.status);
672 }
673
674 int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
675         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
676 {
677         int i, j;
678         int num = 0;
679         struct pathgroup *pgp = NULL;
680         struct path *pp = NULL;
681         int active_pathcount = 0;
682         pthread_attr_t attr;
683         int rc, found = 0;
684         int count = 0;
685         int status = MPATH_PR_SUCCESS;
686         struct prin_resp resp;
687         struct prout_param_descriptor *pamp;
688         struct prin_resp *pr_buff;
689         int length;
690         struct transportid *pptr;
691
692         if (!mpp)
693                 return MPATH_PR_DMMP_ERROR;
694
695         active_pathcount = pathcount (mpp, PATH_UP) + pathcount (mpp, PATH_GHOST);
696
697         struct threadinfo thread[active_pathcount];
698         memset(thread, 0, sizeof(thread));
699         for (i = 0; i < active_pathcount; i++){
700                 thread[i].param.rq_servact = rq_servact;
701                 thread[i].param.rq_scope = rq_scope;
702                 thread[i].param.rq_type = rq_type;
703                 thread[i].param.paramp = paramp;
704                 thread[i].param.noisy = noisy;
705                 thread[i].param.status = MPATH_PR_SKIP;
706
707                 condlog (3, " path count = %d", i);
708                 condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
709                 condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
710                 condlog (3, "rq_type=%d ", thread[i].param.rq_type);
711                 condlog (3, "noisy=%d ", thread[i].param.noisy);
712                 condlog (3, "status=%d ", thread[i].param.status);
713         }
714
715         pthread_attr_init (&attr);
716         pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
717
718         vector_foreach_slot (mpp->pg, pgp, j){
719                 vector_foreach_slot (pgp->paths, pp, i){
720                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
721                                 condlog (1, "%s: %s path not up.", mpp->wwid, pp->dev);
722                                 continue;
723                         }
724
725                         strncpy(thread[count].param.dev, pp->dev,
726                                 FILE_NAME_SIZE - 1);
727                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
728                         rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn,
729                                         (void *) (&thread[count].param));
730                         if (rc) {
731                                 condlog (0, "%s: failed to create thread. %d",  mpp->wwid, rc);
732                                 thread[count].param.status = MPATH_PR_THREAD_ERROR;
733                         }
734                         count = count + 1;
735                 }
736         }
737         pthread_attr_destroy (&attr);
738         for (i = 0; i < count; i++){
739                 if (thread[i].param.status != MPATH_PR_THREAD_ERROR) {
740                         rc = pthread_join (thread[i].id, NULL);
741                         if (rc){
742                                 condlog (1, "%s: failed to join thread.  %d",  mpp->wwid,  rc);
743                         }
744                 }
745         }
746
747         for (i = 0; i < count; i++){
748                 /*  check thread status here and return the status */
749
750                 if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
751                         status = MPATH_PR_RESERV_CONFLICT;
752                 else if (status == MPATH_PR_SUCCESS
753                                 && thread[i].param.status != MPATH_PR_RESERV_CONFLICT)
754                         status = thread[i].param.status;
755         }
756
757         status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
758         if (status != MPATH_PR_SUCCESS){
759                 condlog (0, "%s: pr in read reservation command failed.", mpp->wwid);
760                 return MPATH_PR_OTHER;
761         }
762
763         num = resp.prin_descriptor.prin_readresv.additional_length / 8;
764         if (num == 0){
765                 condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
766                 return MPATH_PR_SUCCESS;
767         }
768         condlog (2, "%s: Path holding reservation is not avialable.", mpp->wwid);
769
770         pr_buff =  mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
771         if (!pr_buff){
772                 condlog (0, "%s: failed to  alloc pr in response buffer.", mpp->wwid);
773                 return MPATH_PR_OTHER;
774         }
775
776         status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
777
778         if (status != MPATH_PR_SUCCESS){
779                 condlog (0,  "%s: pr in read full status command failed.",  mpp->wwid);
780                 goto out;
781         }
782
783         num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
784         if (0 == num){
785                 goto out;
786         }
787         length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *));
788
789         pamp = (struct prout_param_descriptor *)malloc (length);
790         if (!pamp){
791                 condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
792                 goto out1;
793         }
794
795         memset(pamp, 0, length);
796
797         pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid));
798         if (!pamp->trnptid_list[0]){
799                 condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
800                 goto out1;
801         }
802
803         if (get_be64(mpp->reservation_key)){
804                 memcpy (pamp->key, &mpp->reservation_key, 8);
805                 condlog (3, "%s: reservation key set.", mpp->wwid);
806         }
807
808         status = mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA,
809                                      rq_scope, rq_type, pamp, noisy);
810
811         if (status) {
812                 condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
813                 goto out1;
814         }
815
816         pamp->num_transportid = 1;
817         pptr=pamp->trnptid_list[0];
818
819         for (i = 0; i < num; i++){
820                 if (get_be64(mpp->reservation_key) &&
821                         memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
822                                &mpp->reservation_key, 8)){
823                         /*register with tarnsport id*/
824                         memset(pamp, 0, length);
825                         pamp->trnptid_list[0] = pptr;
826                         memset (pamp->trnptid_list[0], 0, sizeof (struct transportid));
827                         memcpy (pamp->sa_key,
828                                         pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
829                         pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK;
830                         pamp->num_transportid = 1;
831
832                         memcpy (pamp->trnptid_list[0],
833                                         &pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid,
834                                         sizeof (struct transportid));
835                         status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
836                                         pamp, noisy);
837
838                         pamp->sa_flags = 0;
839                         memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
840                         memset (pamp->sa_key, 0, 8);
841                         pamp->num_transportid = 0;
842                         status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
843                                         pamp, noisy);
844                 }
845                 else
846                 {
847                         if (get_be64(mpp->reservation_key))
848                                 found = 1;
849                 }
850
851
852         }
853
854         if (found){
855                 memset (pamp, 0, length);
856                 memcpy (pamp->sa_key, &mpp->reservation_key, 8);
857                 memset (pamp->key, 0, 8);
858                 status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
859         }
860
861
862         free(pptr);
863 out1:
864         free (pamp);
865 out:
866         free (pr_buff);
867         return (status);
868 }
869
870 void * mpath_alloc_prin_response(int prin_sa)
871 {
872         void * ptr = NULL;
873         int size=0;
874         switch (prin_sa)
875         {
876                 case MPATH_PRIN_RKEY_SA:
877                         size = sizeof(struct prin_readdescr);
878                         break;
879                 case MPATH_PRIN_RRES_SA:
880                         size = sizeof(struct prin_resvdescr);
881                         break;
882                 case MPATH_PRIN_RCAP_SA:
883                         size=sizeof(struct prin_capdescr);
884                         break;
885                 case MPATH_PRIN_RFSTAT_SA:
886                         size = sizeof(struct print_fulldescr_list) +
887                                 sizeof(struct prin_fulldescr *)*MPATH_MX_TIDS;
888                         break;
889         }
890         if (size > 0)
891         {
892                 ptr = calloc(size, 1);
893         }
894         return ptr;
895 }
896
897 int update_map_pr(struct multipath *mpp)
898 {
899         int noisy=0;
900         struct prin_resp *resp;
901         int i, ret, isFound;
902
903         if (!get_be64(mpp->reservation_key))
904         {
905                 /* Nothing to do. Assuming pr mgmt feature is disabled*/
906                 condlog(3, "%s: reservation_key not set in multipath.conf", mpp->alias);
907                 return MPATH_PR_SUCCESS;
908         }
909
910         resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
911         if (!resp)
912         {
913                 condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
914                 return MPATH_PR_OTHER;
915         }
916         ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
917
918         if (ret != MPATH_PR_SUCCESS )
919         {
920                 condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
921                 free(resp);
922                 return  ret;
923         }
924
925         if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
926         {
927                 condlog(3,"%s: No key found. Device may not be registered. ", mpp->alias);
928                 free(resp);
929                 return MPATH_PR_SUCCESS;
930         }
931
932         condlog(2, "%s: Multipath  reservation_key: 0x%" PRIx64 " ", mpp->alias,
933                 get_be64(mpp->reservation_key));
934
935         isFound =0;
936         for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
937         {
938                 condlog(2, "%s: PR IN READKEYS[%d]  reservation key:", mpp->alias, i);
939                 dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1);
940
941                 if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
942                 {
943                         condlog(2, "%s: reservation key found in pr in readkeys response", mpp->alias);
944                         isFound =1;
945                 }
946         }
947
948         if (isFound)
949         {
950                 mpp->prflag = 1;
951                 condlog(2, "%s: prflag flag set.", mpp->alias );
952         }
953
954         free(resp);
955         return MPATH_PR_SUCCESS;
956 }