2 * Copyright 2005 Network Appliance, Inc., All Rights Reserved
3 * Author: David Wysochanski available at davidw@netapp.com
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License v2 for more details.
18 #include <sys/ioctl.h>
21 #include "sg_include.h"
26 #define INQUIRY_CMD 0x12
27 #define INQUIRY_CMDLEN 6
28 #define DEFAULT_PRIOVAL 10
29 #define RESULTS_MAX 256
30 #define SG_TIMEOUT 60000
32 #define pp_ontap_log(prio, fmt, args...) \
33 condlog(prio, "%s: ontap prio: " fmt, dev, ##args)
35 static void dump_cdb(unsigned char *cdb, int size)
41 condlog(0, "- SCSI CDB: ");
42 for (i=0; i<size; i++) {
43 p += snprintf(p, 10*(size-i), "0x%02x ", cdb[i]);
45 condlog(0, "%s", buf);
48 static void process_sg_error(struct sg_io_hdr *io_hdr)
54 condlog(0, "- masked_status=0x%02x, host_status=0x%02x, "
55 "driver_status=0x%02x", io_hdr->masked_status,
56 io_hdr->host_status, io_hdr->driver_status);
57 if (io_hdr->sb_len_wr > 0) {
58 condlog(0, "- SCSI sense data: ");
59 for (i=0; i<io_hdr->sb_len_wr; i++) {
60 p += snprintf(p, 128*(io_hdr->sb_len_wr-i), "0x%02x ",
63 condlog(0, "%s", buf);
69 * -1: error, errno set
72 static int send_gva(const char *dev, int fd, unsigned char pg,
73 unsigned char *results, int *results_size,
76 unsigned char sb[128];
77 unsigned char cdb[10] = {0xc0, 0, 0x1, 0xa, 0x98, 0xa,
78 pg, sizeof(sb), 0, 0};
79 struct sg_io_hdr io_hdr;
82 memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
83 memset(results, 0, *results_size);
84 io_hdr.interface_id = 'S';
85 io_hdr.cmd_len = sizeof (cdb);
86 io_hdr.mx_sb_len = sizeof (sb);
87 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
88 io_hdr.dxfer_len = *results_size;
89 io_hdr.dxferp = results;
92 io_hdr.timeout = get_prio_timeout(timeout, SG_TIMEOUT);
94 if (ioctl(fd, SG_IO, &io_hdr) < 0) {
95 pp_ontap_log(0, "SG_IO ioctl failed, errno=%d", errno);
96 dump_cdb(cdb, sizeof(cdb));
99 if (io_hdr.info & SG_INFO_OK_MASK) {
100 pp_ontap_log(0, "SCSI error");
101 dump_cdb(cdb, sizeof(cdb));
102 process_sg_error(&io_hdr);
106 if (results[4] != 0x0a || results[5] != 0x98 ||
107 results[6] != 0x0a ||results[7] != 0x01) {
108 dump_cdb(cdb, sizeof(cdb));
109 pp_ontap_log(0, "GVA return wrong format ");
110 pp_ontap_log(0, "results[4-7] = 0x%02x 0x%02x 0x%02x 0x%02x",
111 results[4], results[5], results[6], results[7]);
121 * -1: Unable to obtain proxy info
122 * 0: Device _not_ proxy path
123 * 1: Device _is_ proxy path
125 static int get_proxy(const char *dev, int fd, unsigned int timeout)
127 unsigned char results[256];
128 unsigned char sb[128];
129 unsigned char cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xc1, 0,
131 struct sg_io_hdr io_hdr;
134 memset(&results, 0, sizeof (results));
135 memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
136 io_hdr.interface_id = 'S';
137 io_hdr.cmd_len = sizeof (cdb);
138 io_hdr.mx_sb_len = sizeof (sb);
139 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
140 io_hdr.dxfer_len = sizeof (results);
141 io_hdr.dxferp = results;
144 io_hdr.timeout = get_prio_timeout(timeout, SG_TIMEOUT);
146 if (ioctl(fd, SG_IO, &io_hdr) < 0) {
147 pp_ontap_log(0, "ioctl sending inquiry command failed, "
149 dump_cdb(cdb, sizeof(cdb));
152 if (io_hdr.info & SG_INFO_OK_MASK) {
153 pp_ontap_log(0, "SCSI error");
154 dump_cdb(cdb, sizeof(cdb));
155 process_sg_error(&io_hdr);
159 if (results[1] != 0xc1 || results[8] != 0x0a ||
160 results[9] != 0x98 || results[10] != 0x0a ||
161 results[11] != 0x0 || results[12] != 0xc1 ||
162 results[13] != 0x0) {
163 pp_ontap_log(0,"proxy info page in unknown format - ");
164 pp_ontap_log(0,"results[8-13]=0x%02x 0x%02x 0x%02x 0x%02x "
166 results[8], results[9], results[10],
167 results[11], results[12], results[13]);
168 dump_cdb(cdb, sizeof(cdb));
171 ret = (results[19] & 0x02) >> 1;
178 * Returns priority of device based on device info.
180 * 4: FCP non-proxy, FCP proxy unknown, or unable to determine protocol
185 static int ontap_prio(const char *dev, int fd, unsigned int timeout)
187 unsigned char results[RESULTS_MAX];
188 int results_size=RESULTS_MAX;
191 int is_iscsi_software;
192 int is_iscsi_hardware;
195 is_iscsi_software = is_iscsi_hardware = is_proxy = 0;
197 memset(&results, 0, sizeof (results));
198 rc = send_gva(dev, fd, 0x41, results, &results_size, timeout);
200 tot_len = results[0] << 24 | results[1] << 16 |
201 results[2] << 8 | results[3];
205 if (results[8] != 0x41) {
206 pp_ontap_log(0, "GVA page 0x41 error - "
207 "results[8] = 0x%x", results[8]);
210 if ((strncmp((char *)&results[12], "ism_sw", 6) == 0) ||
211 (strncmp((char *)&results[12], "iswt", 4) == 0)) {
212 is_iscsi_software = 1;
215 else if (strncmp((char *)&results[12], "ism_sn", 6) == 0) {
216 is_iscsi_hardware = 1;
224 rc = get_proxy(dev, fd, timeout);
230 if (is_iscsi_hardware) {
232 } else if (is_iscsi_software) {
238 /* Either non-proxy, or couldn't get proxy info */
244 int getprio (struct path * pp, char * args, unsigned int timeout)
246 return ontap_prio(pp->dev, pp->fd, timeout);