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