multipath-tools: add patchwork info to README
[multipath-tools/.git] / libmpathpersist / mpath_pr_ioctl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <scsi/sg.h>
8 #include <scsi/scsi.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <sys/ioctl.h>
12 #include <unistd.h>
13 #include <libudev.h>
14 #include "mpath_pr_ioctl.h"
15 #include <mpath_persist.h>
16
17 #include <debug.h>
18
19 #define FILE_NAME_SIZE          256
20
21 #define TIMEOUT 2000
22 #define MAXRETRY 5
23
24 int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp *resp, int noisy);
25 void mpath_format_readkeys(struct prin_resp *pr_buff, int len , int noisy);
26 void mpath_format_readfullstatus(struct prin_resp *pr_buff, int len, int noisy);
27 int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr, SenseData_t Sensedata, int noisy);
28 void dumpHex(const char* str, int len, int no_ascii);
29 int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
30                 unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
31 uint32_t  format_transportids(struct prout_param_descriptor *paramp);
32 void mpath_reverse_uint32_byteorder(uint32_t *num);
33 void mpath_reverse_uint16_byteorder(uint16_t *num);
34 void decode_transport_id(struct prin_fulldescr *fdesc, unsigned char * p, int length);
35 int get_prin_length(int rq_servact);
36 int mpath_isLittleEndian(void);
37
38 extern unsigned int mpath_mx_alloc_len;
39
40 int prout_do_scsi_ioctl(char * dev, int rq_servact, int rq_scope,
41                 unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy)
42 {
43
44         int status, paramlen = 24, ret = 0;
45         uint32_t translen=0;
46         int retry = MAXRETRY;
47         SenseData_t Sensedata;
48         struct sg_io_hdr io_hdr;
49         char devname[FILE_NAME_SIZE];
50         int fd = -1;
51
52         snprintf(devname, FILE_NAME_SIZE, "/dev/%s",dev);
53         fd = open(devname, O_WRONLY);
54         if(fd < 0){
55                 condlog (1, "%s: unable to open device.", dev);
56                 return MPATH_PR_FILE_ERROR;
57         }
58
59         unsigned char cdb[MPATH_PROUT_CMDLEN] =
60         {MPATH_PROUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
61
62
63         if (paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)
64         {
65                 translen = format_transportids(paramp);
66                 paramlen = 24 + translen;
67         }
68         else
69                 paramlen = 24;
70
71         if ( rq_servact > 0)
72                 cdb[1] = (unsigned char)(rq_servact & 0x1f);
73         cdb[2] = (((rq_scope & 0xf) << 4) | (rq_type & 0xf));
74         cdb[7] = (unsigned char)((paramlen >> 8) & 0xff);
75         cdb[8] = (unsigned char)(paramlen & 0xff);
76
77 retry :
78         condlog(3, "%s: rq_servact = %d", dev, rq_servact);
79         condlog(3, "%s: rq_scope = %d ", dev, rq_scope);
80         condlog(3, "%s: rq_type = %d ", dev, rq_type);
81         condlog(3, "%s: paramlen = %d", dev, paramlen);
82
83         if (noisy)
84         {
85                 condlog(3, "%s: Persistent Reservation OUT parameter:", dev);
86                 dumpHex((const char *)paramp, paramlen,1);
87         }
88
89         memset(&Sensedata, 0, sizeof(SenseData_t));
90         memset(&io_hdr,0 , sizeof( struct sg_io_hdr));
91         io_hdr.interface_id = 'S';
92         io_hdr.cmd_len = MPATH_PROUT_CMDLEN;
93         io_hdr.cmdp = cdb;
94         io_hdr.sbp = (void *)&Sensedata;
95         io_hdr.mx_sb_len = sizeof (SenseData_t);
96         io_hdr.timeout = TIMEOUT;
97
98         if (paramlen > 0) {
99                 io_hdr.dxferp = (void *)paramp;
100                 io_hdr.dxfer_len = paramlen;
101                 io_hdr.dxfer_direction = SG_DXFER_TO_DEV ;
102         }
103         else {
104                 io_hdr.dxfer_direction = SG_DXFER_NONE;
105         }
106         ret = ioctl(fd, SG_IO, &io_hdr);
107         if (ret < 0)
108         {
109                 condlog(0, "%s: ioctl failed %d", dev, ret);
110                 close(fd);
111                 return ret;
112         }
113
114         condlog(2, "%s: Duration=%u (ms)", dev, io_hdr.duration);
115
116         status = mpath_translate_response(dev, io_hdr, Sensedata, noisy);
117         condlog(3, "%s: status = %d", dev, status);
118
119         if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
120         {
121                 --retry;
122                 condlog(2, "%s: retrying for Unit Attention. Remaining retries = %d",
123                         dev, retry);
124                 goto retry;
125         }
126
127         if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
128                                 (Sensedata.ASCQ == 0x07))&& (retry > 0))
129         {
130                 usleep(1000);
131                 --retry;
132                 condlog(2, "%s: retrying for sense 02/04/07."
133                         " Remaining retries = %d", dev, retry);
134                 goto retry;
135         }
136
137         close(fd);
138         return status;
139 }
140
141 uint32_t  format_transportids(struct prout_param_descriptor *paramp)
142 {
143         int i = 0, len;
144         uint32_t buff_offset = 4;
145         memset(paramp->private_buffer, 0, MPATH_MAX_PARAM_LEN);
146         for (i=0; i < paramp->num_transportid; i++ )
147         {
148                 paramp->private_buffer[buff_offset] = (uint8_t)((paramp->trnptid_list[i]->format_code & 0xff)|
149                                                         (paramp->trnptid_list[i]->protocol_id & 0xff));
150                 buff_offset += 1;
151                 switch(paramp->trnptid_list[i]->protocol_id)
152                 {
153                         case MPATH_PROTOCOL_ID_FC:
154                                 buff_offset += 7;
155                                 memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->n_port_name, 8);
156                                 buff_offset +=8 ;
157                                 buff_offset +=8 ;
158                                 break;
159                         case MPATH_PROTOCOL_ID_SAS:
160                                 buff_offset += 3;
161                                 memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->sas_address, 8);
162                                 buff_offset += 12;
163                                 break;
164                         case MPATH_PROTOCOL_ID_ISCSI:
165                                 buff_offset += 1;
166                                 len = (paramp->trnptid_list[i]->iscsi_name[1] & 0xff)+2;
167                                 memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->iscsi_name,len);
168                                 buff_offset += len ;
169                                 break;
170                 }
171
172         }
173         buff_offset -= 4;
174         paramp->private_buffer[0] = (unsigned char)((buff_offset >> 24) & 0xff);
175         paramp->private_buffer[1] = (unsigned char)((buff_offset >> 16) & 0xff);
176         paramp->private_buffer[2] = (unsigned char)((buff_offset >> 8) & 0xff);
177         paramp->private_buffer[3] = (unsigned char)(buff_offset & 0xff);
178         buff_offset += 4;
179         return buff_offset;
180 }
181
182 void mpath_format_readkeys( struct prin_resp *pr_buff, int len, int noisy)
183 {
184         mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
185         mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
186 }
187
188 void mpath_format_readresv(struct prin_resp *pr_buff, int len, int noisy)
189 {
190
191         mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
192         mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
193
194         return;
195 }
196
197 void mpath_format_reportcapabilities(struct prin_resp *pr_buff, int len, int noisy)
198 {
199         mpath_reverse_uint16_byteorder(&pr_buff->prin_descriptor.prin_readcap.length);
200         mpath_reverse_uint16_byteorder(&pr_buff->prin_descriptor.prin_readcap.pr_type_mask);
201
202         return;
203 }
204
205 void mpath_format_readfullstatus(struct prin_resp *pr_buff, int len, int noisy)
206 {
207         int num, k, tid_len_len=0;
208         uint32_t fdesc_count=0;
209         unsigned char *p;
210         char  *ppbuff;
211         uint32_t additional_length;
212
213
214         mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readfd.prgeneration);
215         mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readfd.number_of_descriptor);
216
217         if (0 == pr_buff->prin_descriptor.prin_readfd.number_of_descriptor)
218         {
219                 return ;
220         }
221
222
223         if (pr_buff->prin_descriptor.prin_readfd.number_of_descriptor == 0)
224         {
225                 condlog(2, "No registration or resrvation found.");
226                 return;
227         }
228
229         additional_length = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
230
231         char tempbuff[MPATH_MAX_PARAM_LEN];
232         struct prin_fulldescr fdesc;
233         memset(&fdesc, 0, sizeof(struct prin_fulldescr));
234
235         memcpy( tempbuff, pr_buff->prin_descriptor.prin_readfd.private_buffer,MPATH_MAX_PARAM_LEN );
236         memset(&pr_buff->prin_descriptor.prin_readfd.private_buffer, 0, MPATH_MAX_PARAM_LEN);
237
238         p =(unsigned char *)tempbuff;
239         ppbuff = (char *)pr_buff->prin_descriptor.prin_readfd.private_buffer;
240
241         for (k = 0; k < additional_length; k += num, p += num) {
242                 memcpy(&fdesc.key, p, 8 );
243                 fdesc.flag = p[12];
244                 fdesc.scope_type =  p[13];
245                 fdesc.rtpi = ((p[18] << 8) | p[19]);
246
247                 tid_len_len = ((p[20] << 24) | (p[21] << 16) |
248                                 (p[22] << 8) | p[23]);
249
250                 if (tid_len_len > 0)
251                         decode_transport_id( &fdesc, &p[24], tid_len_len);
252
253                 num = 24 + tid_len_len;
254                 memcpy(ppbuff, &fdesc, sizeof(struct prin_fulldescr));
255                 pr_buff->prin_descriptor.prin_readfd.descriptors[fdesc_count]= (struct prin_fulldescr *)ppbuff;
256                 ppbuff += sizeof(struct prin_fulldescr);
257                 ++fdesc_count;
258         }
259
260         pr_buff->prin_descriptor.prin_readfd.number_of_descriptor = fdesc_count;
261
262         return;
263 }
264
265 void
266 decode_transport_id(struct prin_fulldescr *fdesc, unsigned char * p, int length)
267 {
268         int num, k;
269         int jump;
270         for (k = 0, jump = 24; k < length; k += jump, p += jump) {
271                 fdesc->trnptid.format_code = ((p[0] >> 6) & 0x3);
272                 fdesc->trnptid.protocol_id = (p[0] & 0xf);
273                 switch (fdesc->trnptid.protocol_id) {
274                         case MPATH_PROTOCOL_ID_FC:
275                                 memcpy(&fdesc->trnptid.n_port_name, &p[8], 8);
276                                 jump = 24;
277                                 break;
278                         case MPATH_PROTOCOL_ID_ISCSI:
279                                 num = ((p[2] << 8) | p[3]);
280                                 memcpy(&fdesc->trnptid.iscsi_name, &p[4], num);
281                                 jump = (((num + 4) < 24) ? 24 : num + 4);
282                                 break;
283                         case MPATH_PROTOCOL_ID_SAS:
284                                 memcpy(&fdesc->trnptid.sas_address, &p[4], 8);
285                                 jump = 24;
286                                 break;
287                         default:
288                                 jump = 24;
289                                 break;
290                 }
291         }
292 }
293
294 int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy)
295 {
296
297         int ret, status, got, fd;
298         int mx_resp_len;
299         SenseData_t Sensedata;
300         int retry = MAXRETRY;
301         struct sg_io_hdr io_hdr;
302         char devname[FILE_NAME_SIZE];
303         unsigned char cdb[MPATH_PRIN_CMDLEN] =
304         {MPATH_PRIN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
305
306         snprintf(devname, FILE_NAME_SIZE, "/dev/%s",dev);
307         fd = open(devname, O_WRONLY);
308         if(fd < 0){
309                 condlog(0, "%s: Unable to open device ", dev);
310                 return MPATH_PR_FILE_ERROR;
311          }
312
313         if (mpath_mx_alloc_len)
314                 mx_resp_len = mpath_mx_alloc_len;
315         else
316                 mx_resp_len = get_prin_length(rq_servact);
317
318         if (mx_resp_len == 0) {
319                 status = MPATH_PR_SYNTAX_ERROR;
320                 goto out;
321         }
322
323         cdb[1] = (unsigned char)(rq_servact & 0x1f);
324         cdb[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
325         cdb[8] = (unsigned char)(mx_resp_len & 0xff);
326
327 retry :
328         memset(&Sensedata, 0, sizeof(SenseData_t));
329         memset(&io_hdr,0 , sizeof( struct sg_io_hdr));
330
331         io_hdr.interface_id = 'S';
332         io_hdr.cmd_len = MPATH_PRIN_CMDLEN;
333         io_hdr.mx_sb_len = sizeof (SenseData_t);
334         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
335         io_hdr.cmdp = cdb;
336         io_hdr.sbp = (void *)&Sensedata;
337         io_hdr.timeout = TIMEOUT;
338
339
340
341         io_hdr.dxfer_len = mx_resp_len;
342         io_hdr.dxferp = (void *)resp;
343
344         ret =ioctl(fd, SG_IO, &io_hdr);
345         if (ret < 0){
346                 condlog(0, "%s: IOCTL failed %d", dev, ret);
347                 status = MPATH_PR_OTHER;
348                 goto out;
349         }
350
351         got = mx_resp_len - io_hdr.resid;
352
353         condlog(2, "%s: duration = %u (ms)", dev, io_hdr.duration);
354         condlog(2, "%s: persistent reservation in: requested %d bytes but got %d bytes)", dev, mx_resp_len, got);
355
356         status = mpath_translate_response(dev, io_hdr, Sensedata, noisy);
357
358         if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
359         {
360                 --retry;
361                 condlog(2, "%s: retrying for Unit Attention. Remaining retries = %d", dev, retry);
362                 goto retry;
363         }
364
365         if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
366                                 (Sensedata.ASCQ == 0x07))&& (retry > 0))
367         {
368                 usleep(1000);
369                 --retry;
370                 condlog(2, "%s: retrying for 02/04/07. Remaining retries = %d", dev, retry);
371                 goto retry;
372         }
373
374         if (status != MPATH_PR_SUCCESS)
375                 goto out;
376
377         if (noisy)
378                 dumpHex((const char *)resp, got , 1);
379
380
381         switch (rq_servact)
382         {
383                 case MPATH_PRIN_RKEY_SA :
384                         mpath_format_readkeys(resp, got, noisy);
385                         break;
386                 case MPATH_PRIN_RRES_SA :
387                         mpath_format_readresv(resp, got, noisy);
388                         break;
389                 case MPATH_PRIN_RCAP_SA :
390                         mpath_format_reportcapabilities(resp, got, noisy);
391                         break;
392                 case MPATH_PRIN_RFSTAT_SA :
393                         mpath_format_readfullstatus(resp, got, noisy);
394         }
395
396 out:
397         close(fd);
398         return status;
399 }
400
401 int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr, SenseData_t Sensedata, int noisy)
402 {
403         condlog(3, "%s: status driver:%02x host:%02x scsi:%02x", dev,
404                         io_hdr.driver_status, io_hdr.host_status ,io_hdr.status);
405         io_hdr.status &= 0x7e;
406         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
407                         (0 == io_hdr.driver_status))
408         {
409                 return MPATH_PR_SUCCESS;
410         }
411
412         switch(io_hdr.status)
413         {
414                 case SAM_STAT_GOOD:
415                         break;
416                 case SAM_STAT_CHECK_CONDITION:
417                         condlog(2, "%s: Sense_Key=%02x, ASC=%02x ASCQ=%02x", dev,
418                                         Sensedata.Sense_Key, Sensedata.ASC, Sensedata.ASCQ);
419                         switch(Sensedata.Sense_Key)
420                         {
421                                 case NO_SENSE:
422                                         return MPATH_PR_NO_SENSE;
423                                 case RECOVERED_ERROR:
424                                         return MPATH_PR_SUCCESS;
425                                 case NOT_READY:
426                                         return MPATH_PR_SENSE_NOT_READY;
427                                 case MEDIUM_ERROR:
428                                         return MPATH_PR_SENSE_MEDIUM_ERROR;
429                                 case BLANK_CHECK:
430                                         return MPATH_PR_OTHER;
431                                 case HARDWARE_ERROR:
432                                         return MPATH_PR_SENSE_HARDWARE_ERROR;
433                                 case ILLEGAL_REQUEST:
434                                         return MPATH_PR_ILLEGAL_REQ;
435                                 case UNIT_ATTENTION:
436                                         return MPATH_PR_SENSE_UNIT_ATTENTION;
437                                 case DATA_PROTECT:
438                                 case COPY_ABORTED:
439                                         return MPATH_PR_OTHER;
440                                 case ABORTED_COMMAND:
441                                         return MPATH_PR_SENSE_ABORTED_COMMAND;
442
443                                 default :
444                                         return MPATH_PR_OTHER;
445                         }
446                 case SAM_STAT_RESERVATION_CONFLICT:
447                         return MPATH_PR_RESERV_CONFLICT;
448
449                 default :
450                         return  MPATH_PR_OTHER;
451         }
452
453         switch(io_hdr.host_status)
454         {
455                 case DID_OK :
456                         break;
457                 default :
458                         return MPATH_PR_OTHER;
459         }
460         switch(io_hdr.driver_status)
461         {
462                 case DRIVER_OK:
463                         break;
464                 default :
465                         return MPATH_PR_OTHER;
466         }
467         return MPATH_PR_SUCCESS;
468 }
469
470 int mpath_isLittleEndian()
471 {
472         int num = 1;
473         if(*(char *)&num == 1)
474         {
475                 condlog(2, "Little-Endian");
476         }
477         else
478         {
479                 condlog(2, "Big-Endian");
480         }
481         return 0;
482 }
483
484 void mpath_reverse_uint16_byteorder(uint16_t *num)
485 {
486         uint16_t byte0, byte1;
487
488         byte0 = (*num & 0x000000FF) >>  0 ;
489         byte1 = (*num & 0x0000FF00) >>  8 ;
490
491         *num = ((byte0 << 8) | (byte1 << 0));
492 }
493
494 void mpath_reverse_uint32_byteorder(uint32_t *num)
495 {
496         uint32_t byte0, byte1, byte2, byte3;
497
498         byte0 = (*num & 0x000000FF) >>  0 ;
499         byte1 = (*num & 0x0000FF00) >>  8 ;
500         byte2 = (*num & 0x00FF0000) >> 16 ;
501         byte3 = (*num & 0xFF000000) >> 24 ;
502
503         *num = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | (byte3 << 0));
504 }
505
506 void mpath_reverse_8bytes_order(char * var)
507 {
508         char byte[8];
509
510         int i;
511         for(i=0 ; i < 8 ; i++ )
512         {
513                 byte[i] = var[i];
514         }
515         for(i=0 ; i < 8 ; i++ )
516         {
517                 var[7 - i] = byte[i];
518         }
519 }
520
521 void
522 dumpHex(const char* str, int len, int log)
523 {
524         const char * p = str;
525         unsigned char c;
526         char buff[82];
527         const int bpstart = 5;
528         int bpos = bpstart;
529         int  k;
530
531         if (len <= 0)
532                 return;
533         memset(buff, ' ', 80);
534         buff[80] = '\0';
535         for (k = 0; k < len; k++) {
536                 c = *p++;
537                 bpos += 3;
538                 if (bpos == (bpstart + (9 * 3)))
539                         bpos++;
540                 sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
541                 buff[bpos + 2] = ' ';
542                 if ((k > 0) && (0 == ((k + 1) % 16))) {
543                         if (log)
544                                 condlog(0, "%.76s" , buff);
545                         else
546                                 printf("%.76s" , buff);
547                         bpos = bpstart;
548                         memset(buff, ' ', 80);
549                 }
550         }
551         if (bpos > bpstart) {
552                 buff[bpos + 2] = '\0';
553                 if (log)
554                         condlog(0, "%s", buff);
555                 else
556                         printf("%s\n" , buff);
557         }
558         return;
559 }
560
561 int get_prin_length(int rq_servact)
562 {
563         int mx_resp_len;
564         switch (rq_servact)
565         {
566                 case MPATH_PRIN_RKEY_SA:
567                         mx_resp_len =  sizeof(struct prin_readdescr);
568                         break;
569                 case MPATH_PRIN_RRES_SA :
570                         mx_resp_len =  sizeof(struct prin_resvdescr);
571                         break;
572                 case MPATH_PRIN_RCAP_SA :
573                         mx_resp_len = sizeof(struct prin_capdescr);
574                         break;
575                 case MPATH_PRIN_RFSTAT_SA:
576                         mx_resp_len = sizeof(struct print_fulldescr_list) + sizeof(struct prin_fulldescr *)*32;
577                         break;
578                 default:
579                         condlog(0, "invalid service action, %d", rq_servact);
580                         mx_resp_len = 0;
581                         break;
582         }
583         return mx_resp_len;
584 }