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