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