Specify checker_timeout in seconds
[multipath-tools/.git] / libmultipath / checkers / libsg.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  */
4 #include <string.h>
5 #include <sys/ioctl.h>
6 #include <errno.h>
7 #include <sys/stat.h>
8
9 #include "checkers.h"
10 #include "libsg.h"
11 #include "../libmultipath/sg_include.h"
12
13 int
14 sg_read (int sg_fd, unsigned char * buff, int buff_len,
15          unsigned char * sense, int sense_len, unsigned int timeout)
16 {
17         /* defaults */
18         int blocks;
19         long long start_block = 0;
20         int bs = 512;
21         int cdbsz = 10;
22         int * diop = NULL;
23
24         unsigned char rdCmd[cdbsz];
25         unsigned char *sbb = sense;
26         struct sg_io_hdr io_hdr;
27         int res;
28         int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
29         int sz_ind;
30         struct stat filestatus;
31         int retry_count = 3;
32
33         if (fstat(sg_fd, &filestatus) != 0)
34                 return PATH_DOWN;
35         bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize;
36         blocks = buff_len / bs;
37         memset(rdCmd, 0, cdbsz);
38         sz_ind = 1;
39         rdCmd[0] = rd_opcode[sz_ind];
40         rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
41         rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
42         rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
43         rdCmd[5] = (unsigned char)(start_block & 0xff);
44         rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
45         rdCmd[8] = (unsigned char)(blocks & 0xff);
46
47         memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
48         io_hdr.interface_id = 'S';
49         io_hdr.cmd_len = cdbsz;
50         io_hdr.cmdp = rdCmd;
51         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
52         io_hdr.dxfer_len = bs * blocks;
53         io_hdr.dxferp = buff;
54         io_hdr.mx_sb_len = sense_len;
55         io_hdr.sbp = sense;
56         io_hdr.timeout = timeout * 1000;
57         io_hdr.pack_id = (int)start_block;
58         if (diop && *diop)
59         io_hdr.flags |= SG_FLAG_DIRECT_IO;
60
61 retry:
62         memset(sense, 0, sense_len);
63         while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
64
65         if (res < 0) {
66                 if (ENOMEM == errno) {
67                         return PATH_UP;
68                 }
69                 return PATH_DOWN;
70         }
71
72         if ((0 == io_hdr.status) &&
73             (0 == io_hdr.host_status) &&
74             (0 == io_hdr.driver_status)) {
75                 return PATH_UP;
76         } else {
77                 int key = 0;
78
79                 if (io_hdr.sb_len_wr > 3) {
80                         if (sbb[0] == 0x72 || sbb[0] == 0x73)
81                                 key = sbb[1] & 0x0f;
82                         else if (io_hdr.sb_len_wr > 13 &&
83                                  ((sbb[0] & 0x7f) == 0x70 ||
84                                   (sbb[0] & 0x7f) == 0x71))
85                                 key = sbb[2] & 0x0f;
86                 }
87
88                 /*
89                  * Retry if UNIT_ATTENTION check condition.
90                  */
91                 if (key == 0x6) {
92                         if (--retry_count)
93                                 goto retry;
94                 }
95                 return PATH_DOWN;
96         }
97 }