2d4d968308641e41e82d5db81a35dc6361716381
[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         cdb[1] = (unsigned char)(rq_servact & 0x1f);
318         cdb[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
319         cdb[8] = (unsigned char)(mx_resp_len & 0xff);
320
321 retry :
322         memset(&Sensedata, 0, sizeof(SenseData_t));
323         memset(&io_hdr,0 , sizeof( struct sg_io_hdr));
324
325         io_hdr.interface_id = 'S';
326         io_hdr.cmd_len = MPATH_PRIN_CMDLEN;
327         io_hdr.mx_sb_len = sizeof (SenseData_t);
328         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
329         io_hdr.cmdp = cdb;
330         io_hdr.sbp = (void *)&Sensedata;
331         io_hdr.timeout = TIMEOUT;
332
333
334
335         io_hdr.dxfer_len = mx_resp_len;
336         io_hdr.dxferp = (void *)resp;
337
338         ret =ioctl(fd, SG_IO, &io_hdr);
339         if (ret < 0){
340                 condlog(0, "%s: IOCTL failed %d", dev, ret);
341                 status = MPATH_PR_OTHER;
342                 goto out;
343         }
344
345         got = mx_resp_len - io_hdr.resid;
346
347         condlog(2, "%s: duration = %u (ms)", dev, io_hdr.duration);
348         condlog(2, "%s: persistent reservation in: requested %d bytes but got %d bytes)", dev, mx_resp_len, got);
349
350         status = mpath_translate_response(dev, io_hdr, Sensedata, noisy);
351
352         if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
353         {
354                 --retry;
355                 condlog(2, "%s: retrying for Unit Attention. Remaining retries = %d", dev, retry);
356                 goto retry;
357         }
358
359         if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
360                                 (Sensedata.ASCQ == 0x07))&& (retry > 0))
361         {
362                 usleep(1000);
363                 --retry;
364                 condlog(2, "%s: retrying for 02/04/07. Remaining retries = %d", dev, retry);
365                 goto retry;
366         }
367
368         if (status != MPATH_PR_SUCCESS)
369                 goto out;
370
371         if (noisy)
372                 dumpHex((const char *)resp, got , 1);
373
374
375         switch (rq_servact)
376         {
377                 case MPATH_PRIN_RKEY_SA :
378                         mpath_format_readkeys(resp, got, noisy);
379                         break;
380                 case MPATH_PRIN_RRES_SA :
381                         mpath_format_readresv(resp, got, noisy);
382                         break;
383                 case MPATH_PRIN_RCAP_SA :
384                         mpath_format_reportcapabilities(resp, got, noisy);
385                         break;
386                 case MPATH_PRIN_RFSTAT_SA :
387                         mpath_format_readfullstatus(resp, got, noisy);
388         }
389
390 out:
391         close(fd);
392         return status;
393 }
394
395 int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr, SenseData_t Sensedata, int noisy)
396 {
397         condlog(3, "%s: status driver:%02x host:%02x scsi:%02x", dev, 
398                         io_hdr.driver_status, io_hdr.host_status ,io_hdr.status);
399         io_hdr.status &= 0x7e;
400         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
401                         (0 == io_hdr.driver_status))
402         {
403                 return MPATH_PR_SUCCESS;
404         }
405
406         switch(io_hdr.status)
407         {
408                 case SAM_STAT_GOOD:
409                         break;
410                 case SAM_STAT_CHECK_CONDITION:
411                         condlog(2, "%s: Sense_Key=%02x, ASC=%02x ASCQ=%02x", dev,
412                                         Sensedata.Sense_Key, Sensedata.ASC, Sensedata.ASCQ);
413                         switch(Sensedata.Sense_Key)
414                         {
415                                 case NO_SENSE:
416                                         return MPATH_PR_NO_SENSE;
417                                 case RECOVERED_ERROR:
418                                         return MPATH_PR_SUCCESS;
419                                 case NOT_READY:
420                                         return MPATH_PR_SENSE_NOT_READY;
421                                 case MEDIUM_ERROR:
422                                         return MPATH_PR_SENSE_MEDIUM_ERROR;
423                                 case BLANK_CHECK:
424                                         return MPATH_PR_OTHER;
425                                 case HARDWARE_ERROR:
426                                         return MPATH_PR_SENSE_HARDWARE_ERROR;
427                                 case ILLEGAL_REQUEST:
428                                         return MPATH_PR_ILLEGAL_REQ;
429                                 case UNIT_ATTENTION:
430                                         return MPATH_PR_SENSE_UNIT_ATTENTION;
431                                 case DATA_PROTECT:
432                                 case COPY_ABORTED:
433                                         return MPATH_PR_OTHER;
434                                 case ABORTED_COMMAND:
435                                         return MPATH_PR_SENSE_ABORTED_COMMAND;
436
437                                 default :
438                                         return MPATH_PR_OTHER;
439                         }
440                 case SAM_STAT_RESERVATION_CONFLICT:
441                         return MPATH_PR_RESERV_CONFLICT;
442
443                 default :
444                         return  MPATH_PR_OTHER;
445         }
446
447         switch(io_hdr.host_status)
448         {
449                 case DID_OK :
450                         break;
451                 default :
452                         return MPATH_PR_OTHER;
453         }
454         switch(io_hdr.driver_status)
455         {
456                 case DRIVER_OK:
457                         break;
458                 default :
459                         return MPATH_PR_OTHER;
460         }
461         return MPATH_PR_SUCCESS;
462 }
463
464 int mpath_isLittleEndian()
465 {
466         int num = 1;
467         if(*(char *)&num == 1)
468         {
469                 condlog(2, "Little-Endian");
470         }
471         else
472         {
473                 condlog(2, "Big-Endian");
474         }
475         return 0;
476 }
477
478 void mpath_reverse_uint16_byteorder(uint16_t *num)
479 {
480         uint16_t byte0, byte1;
481
482         byte0 = (*num & 0x000000FF) >>  0 ;
483         byte1 = (*num & 0x0000FF00) >>  8 ;
484
485         *num = ((byte0 << 8) | (byte1 << 0));
486 }
487
488 void mpath_reverse_uint32_byteorder(uint32_t *num)
489 {
490         uint32_t byte0, byte1, byte2, byte3;
491
492         byte0 = (*num & 0x000000FF) >>  0 ;
493         byte1 = (*num & 0x0000FF00) >>  8 ;
494         byte2 = (*num & 0x00FF0000) >> 16 ;
495         byte3 = (*num & 0xFF000000) >> 24 ;
496
497         *num = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | (byte3 << 0));
498 }
499
500 void mpath_reverse_8bytes_order(char * var)
501 {
502         char byte[8];
503
504         int i;
505         for(i=0 ; i < 8 ; i++ )
506         {
507                 byte[i] = var[i];
508         }
509         for(i=0 ; i < 8 ; i++ )
510         {
511                 var[7 - i] = byte[i];
512         }
513 }
514
515 void
516 dumpHex(const char* str, int len, int log)
517 {
518         const char * p = str;
519         unsigned char c;
520         char buff[82];
521         const int bpstart = 5;
522         int bpos = bpstart;
523         int  k;
524
525         if (len <= 0)
526                 return;
527         memset(buff, ' ', 80);
528         buff[80] = '\0';
529         for (k = 0; k < len; k++) {
530                 c = *p++;
531                 bpos += 3;
532                 if (bpos == (bpstart + (9 * 3)))
533                         bpos++;
534                 sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
535                 buff[bpos + 2] = ' ';
536                 if ((k > 0) && (0 == ((k + 1) % 16))) {
537                         if (log)
538                                 condlog(0, "%.76s" , buff);
539                         else
540                                 printf("%.76s" , buff);
541                         bpos = bpstart;
542                         memset(buff, ' ', 80);
543                 }
544         }
545         if (bpos > bpstart) {
546                 buff[bpos + 2] = '\0';
547                 if (log)
548                         condlog(0, "%s", buff);
549                 else
550                         printf("%s\n" , buff);
551         }
552         return;
553 }
554
555 int get_prin_length(int rq_servact)
556 {
557         int mx_resp_len;
558         switch (rq_servact)
559         {
560                 case MPATH_PRIN_RKEY_SA:
561                         mx_resp_len =  sizeof(struct prin_readdescr);
562                         break;
563                 case MPATH_PRIN_RRES_SA :
564                         mx_resp_len =  sizeof(struct prin_resvdescr);
565                         break;
566                 case MPATH_PRIN_RCAP_SA :
567                         mx_resp_len = sizeof(struct prin_capdescr);
568                         break;
569                 case MPATH_PRIN_RFSTAT_SA:
570                         mx_resp_len = sizeof(struct print_fulldescr_list) + sizeof(struct prin_fulldescr *)*32;
571                         break;
572         }
573         return mx_resp_len;
574 }