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