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