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