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