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