1 | /*
|
---|
2 | * Copyright (C) 2011 Hewlett-Packard Development Company, L.P.
|
---|
3 | *
|
---|
4 | * This file is part of hpsa_obdr_mode.
|
---|
5 | *
|
---|
6 | * hpsa_obdr_mode is free software; you can redistribute it and/or modify
|
---|
7 | * it under the terms of the GNU General Public License as published by
|
---|
8 | * the Free Software Foundation; either version 2 of the License, or
|
---|
9 | * (at your option) any later version.
|
---|
10 | *
|
---|
11 | * hpsa_obdr_mode is distributed in the hope that it will be useful,
|
---|
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | * GNU General Public License for more details.
|
---|
15 | *
|
---|
16 | * You should have received a copy of the GNU General Public License
|
---|
17 | * along with hpsa_obdr_mode; if not, write to the Free Software
|
---|
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
---|
19 | *
|
---|
20 | * Author: Stephen M. Cameron <scameron@beardog.cce.hp.com>
|
---|
21 | *
|
---|
22 | */
|
---|
23 |
|
---|
24 | /* Some versions of the hpsa driver do not properly
|
---|
25 | * detect OBDR devices.
|
---|
26 | *
|
---|
27 | * Thus, when in OBDR mode, when the disaster recovery
|
---|
28 | * software tries to change the tape drive out of OBDR
|
---|
29 | * mode, it is unable to talk to it because the driver
|
---|
30 | * didn't find it.
|
---|
31 | *
|
---|
32 | * This program hunts down hpsa controlled smart arrays,
|
---|
33 | * then for each smart array, does a report physical luns.
|
---|
34 | * Then for each cd-rom/tape drive, it does
|
---|
35 | * an inquiry to determine if it's an OBDR device.
|
---|
36 | *
|
---|
37 | * Then, it sends a mode select to take it out of or
|
---|
38 | * put it in of OBDR mode.
|
---|
39 | *
|
---|
40 | * So running this program with parameters -m tape /dev/sg*
|
---|
41 | * will find all the OBDR devices that the buggy hpsa
|
---|
42 | * driver missed, and flip them out of or into OBDR mode.
|
---|
43 | *
|
---|
44 | * Then, via echo 1 > /sys/bus/scsi/....hostn/rescan,
|
---|
45 | * the tape drives can be brought on-line.
|
---|
46 | *
|
---|
47 | */
|
---|
48 |
|
---|
49 | #include <stdio.h>
|
---|
50 | #include <unistd.h>
|
---|
51 | #include <stdlib.h>
|
---|
52 | #include <sys/types.h>
|
---|
53 | #include <sys/stat.h>
|
---|
54 | #include <fcntl.h>
|
---|
55 | #include <sys/ioctl.h>
|
---|
56 | #include <string.h>
|
---|
57 | #include <stdint.h>
|
---|
58 | #include <arpa/inet.h> /* for htonl, etc. */
|
---|
59 | #include <errno.h>
|
---|
60 | #include <getopt.h>
|
---|
61 | #include <scsi/sg.h>
|
---|
62 | #include <scsi/scsi_ioctl.h>
|
---|
63 |
|
---|
64 | /* Some old versions of kernel headers don't arrange to have __user,
|
---|
65 | * which appears in cciss_ioctl.h, handled correctly by userland
|
---|
66 | * programs. So we handle it here.
|
---|
67 | */
|
---|
68 | #define __user
|
---|
69 | #include <linux/cciss_ioctl.h>
|
---|
70 |
|
---|
71 | static int debug = 0;
|
---|
72 | static char *progname = NULL;
|
---|
73 |
|
---|
74 | #define QUERY 0
|
---|
75 | #define TAPEMODE 1
|
---|
76 | #define CDMODE 2
|
---|
77 |
|
---|
78 | #ifndef VERSION
|
---|
79 | #warning VERSION not defined, using 'unknown'
|
---|
80 | #define VERSION "unknown"
|
---|
81 | #endif
|
---|
82 |
|
---|
83 | static unsigned char *CTLR_LUNID = (unsigned char *) "\0\0\0\0\0\0\0\0";
|
---|
84 |
|
---|
85 | #define HPSA_MAX_LUN 1024
|
---|
86 | #define REPORT_PHYSICAL 0xc3
|
---|
87 |
|
---|
88 | #pragma pack(1)
|
---|
89 | struct ReportLUNdata {
|
---|
90 | uint8_t LUNListLength[4];
|
---|
91 | uint8_t reserved[4];
|
---|
92 | uint8_t LUN[8 * HPSA_MAX_LUN];
|
---|
93 | };
|
---|
94 | #pragma pack()
|
---|
95 |
|
---|
96 | static void setup_sgio(sg_io_hdr_t *sgio,
|
---|
97 | unsigned char *cdb, unsigned char cdblen,
|
---|
98 | unsigned char *databuffer, unsigned int databufferlen,
|
---|
99 | unsigned char *sensebuffer, unsigned char sensebufferlen,
|
---|
100 | int direction
|
---|
101 | )
|
---|
102 | {
|
---|
103 | memset(sgio, 0, sizeof(*sgio));
|
---|
104 | sgio->interface_id = 'S';
|
---|
105 | sgio->dxfer_direction = direction;
|
---|
106 | sgio->cmd_len = cdblen;
|
---|
107 | sgio->mx_sb_len = sensebufferlen;
|
---|
108 | sgio->iovec_count = 0;
|
---|
109 | sgio->dxfer_len = databufferlen;
|
---|
110 | sgio->dxferp = databuffer;
|
---|
111 | sgio->cmdp = cdb;
|
---|
112 | sgio->sbp = sensebuffer;
|
---|
113 | /* sgio->timeout = 0xffffffff; // no timeout */
|
---|
114 | sgio->timeout = 0x0fffffff; /* At least one mptlinux controller doesn't like */
|
---|
115 | /* timeout of 0xffffffff, 1st drive, ok, 2nd, 3rd, etc */
|
---|
116 | /* sort of pretend to timeout instantly and abort cmds */
|
---|
117 | /* but oddly, return data, for inquiries anyhow. */
|
---|
118 | /* timeout of 0x0fffffff seems to make it happy. */
|
---|
119 | sgio->flags = 0;
|
---|
120 | sgio->pack_id = 0;
|
---|
121 | sgio->usr_ptr = NULL;
|
---|
122 | sgio->status = 0;
|
---|
123 | sgio->masked_status = 0;
|
---|
124 | sgio->msg_status = 0;
|
---|
125 | sgio->sb_len_wr = 0;
|
---|
126 | sgio->host_status = 0;
|
---|
127 | sgio->driver_status = 0;
|
---|
128 | sgio->resid = 0;
|
---|
129 | sgio->duration = 0;
|
---|
130 | sgio->info = 0;
|
---|
131 | }
|
---|
132 |
|
---|
133 | static int debug_sgio()
|
---|
134 | {
|
---|
135 | return 0;
|
---|
136 | }
|
---|
137 |
|
---|
138 | static int do_sg_io(int fd, unsigned char *cdb, unsigned char cdblen,
|
---|
139 | unsigned char *buffer, unsigned char buf_size, int direction)
|
---|
140 | {
|
---|
141 | int status;
|
---|
142 | sg_io_hdr_t sgio;
|
---|
143 | unsigned char sensebuffer[64];
|
---|
144 |
|
---|
145 | memset(buffer, 0, buf_size);
|
---|
146 | memset(&sgio, 0, sizeof(sgio));
|
---|
147 |
|
---|
148 | setup_sgio(&sgio, (unsigned char *) cdb, cdblen, buffer,
|
---|
149 | buf_size, sensebuffer, sizeof(sensebuffer), direction);
|
---|
150 |
|
---|
151 | status = ioctl(fd, SG_IO, &sgio);
|
---|
152 |
|
---|
153 | if (status == 0 && sgio.host_status == 0 && sgio.driver_status == 0) { /* cmd succeeded */
|
---|
154 | if (sgio.status == 0 || (sgio.status == 2 &&
|
---|
155 | (((sensebuffer[2] & 0x0f) == 0x00) || /* no error */
|
---|
156 | ((sensebuffer[2] & 0x0f) == 0x01)))) {
|
---|
157 | return 0;
|
---|
158 | }
|
---|
159 | if (debug_sgio())
|
---|
160 | fprintf(stderr, "sgio cmd 0x%02x check condition, sense key = %d\n",
|
---|
161 | cdb[0], sensebuffer[2] & 0x0f);
|
---|
162 | return -1;
|
---|
163 | }
|
---|
164 | if (debug_sgio())
|
---|
165 | fprintf(stderr, "sgio ioctl: %d, cdb[0]=0x%02x, "
|
---|
166 | "status host/driver/scsi/sensekey = %d/%d/%d/0x%02x\n",
|
---|
167 | status, cdb[0], sgio.host_status, sgio.driver_status,
|
---|
168 | sgio.status, sensebuffer[2]);
|
---|
169 | return -1;
|
---|
170 | }
|
---|
171 |
|
---|
172 | static int sgio_do_inquiry(int fd,
|
---|
173 | unsigned char inquiry_page,
|
---|
174 | unsigned char* inquiry_buf,
|
---|
175 | unsigned char buf_size)
|
---|
176 | {
|
---|
177 | unsigned char cdb[6];
|
---|
178 |
|
---|
179 | memset(inquiry_buf, 0, buf_size);
|
---|
180 | memset(cdb, 0, sizeof(cdb));
|
---|
181 | cdb[0] = 0x12;
|
---|
182 | if (inquiry_page != 0) /* EVPD? */
|
---|
183 | cdb[1] = 1;
|
---|
184 | else
|
---|
185 | cdb[1] = 0;
|
---|
186 | cdb[2] = inquiry_page;
|
---|
187 | cdb[4] = buf_size;
|
---|
188 |
|
---|
189 | return do_sg_io(fd, cdb, 6, inquiry_buf, buf_size, SG_DXFER_FROM_DEV);
|
---|
190 | }
|
---|
191 |
|
---|
192 | static int is_smartarray(int fd)
|
---|
193 | {
|
---|
194 | int rc;
|
---|
195 | struct _cciss_pci_info_struct pciinfo;
|
---|
196 | unsigned char inqbuf[36];
|
---|
197 |
|
---|
198 | /* test if it's a smart array (that driver supports this ioctl.) */
|
---|
199 | rc = ioctl(fd, CCISS_GETPCIINFO, &pciinfo);
|
---|
200 | if (rc) {
|
---|
201 | if (debug)
|
---|
202 | fprintf(stderr, "Not a smart array\n");
|
---|
203 | return 0;
|
---|
204 | }
|
---|
205 |
|
---|
206 | /* test if it's a smart array *controller* (and not logical drive,
|
---|
207 | * tape drive, etc.)
|
---|
208 | */
|
---|
209 |
|
---|
210 | rc = sgio_do_inquiry(fd, 0, inqbuf, sizeof(inqbuf));
|
---|
211 | if (rc) {
|
---|
212 | if (debug)
|
---|
213 | fprintf(stderr, "SG_IO inquiry failed.\n");
|
---|
214 | return 0;
|
---|
215 | }
|
---|
216 |
|
---|
217 | if (debug)
|
---|
218 | fprintf(stderr, "Device is %sa RAID controller device\n",
|
---|
219 | ((inqbuf[0] & 0x1f) == 0x0C) ? "" : "not ");
|
---|
220 | /* See if it's a RAID controller (device type 0x0C) */
|
---|
221 | return ((inqbuf[0] & 0x1f) == 0x0C);
|
---|
222 | }
|
---|
223 |
|
---|
224 | static void setup_for_ioctl(BIG_IOCTL_Command_struct *cmd,
|
---|
225 | unsigned char *lunid,
|
---|
226 | unsigned char *cdb, int cdblen,
|
---|
227 | int write_direction,
|
---|
228 | unsigned char *buf,
|
---|
229 | int bufsize)
|
---|
230 | {
|
---|
231 | memset(cmd, 0, sizeof(*cmd));
|
---|
232 | memcpy(cmd->LUN_info.LunAddrBytes, lunid, 8);
|
---|
233 | cmd->Request.CDBLen = cdblen;
|
---|
234 | cmd->Request.Type.Type = TYPE_CMD;
|
---|
235 | cmd->Request.Type.Attribute = ATTR_SIMPLE;
|
---|
236 | cmd->Request.Type.Direction = (write_direction) ? XFER_WRITE : XFER_READ;
|
---|
237 | cmd->Request.Timeout = 0;
|
---|
238 | memcpy(cmd->Request.CDB, cdb, cdblen);
|
---|
239 | cmd->buf_size = bufsize;
|
---|
240 | cmd->buf = buf;
|
---|
241 | cmd->malloc_size = 10000;
|
---|
242 | }
|
---|
243 |
|
---|
244 | static int check_ioctl(char *filename, char *command,
|
---|
245 | int rc, BIG_IOCTL_Command_struct *cmd)
|
---|
246 | {
|
---|
247 | if (debug) {
|
---|
248 | printf("CHK: %s: CommandStatus=%d\n", command,
|
---|
249 | cmd->error_info.CommandStatus);
|
---|
250 | if (cmd->error_info.CommandStatus == 1) {
|
---|
251 | printf("CHK: ScsiStatus = %d\n", cmd->error_info.ScsiStatus);
|
---|
252 | }
|
---|
253 | }
|
---|
254 |
|
---|
255 | if (rc != 0) {
|
---|
256 | fprintf(stderr, "%s: %s, %s ioctl failed, %s\n", progname,
|
---|
257 | filename, command, strerror(errno));
|
---|
258 | return -1;
|
---|
259 | }
|
---|
260 | if (cmd->error_info.CommandStatus != 0 &&
|
---|
261 | cmd->error_info.CommandStatus != 2) {
|
---|
262 | fprintf(stderr, "%s: %s%s, ioctl has Command Status=%d\n",
|
---|
263 | progname, filename, command,
|
---|
264 | cmd->error_info.CommandStatus);
|
---|
265 | return -1;
|
---|
266 | }
|
---|
267 | return 0;
|
---|
268 | }
|
---|
269 |
|
---|
270 | /* do cciss report physical luns to get list of physical device LUNIDs */
|
---|
271 | static int do_report_luns(char *filename, int fd,
|
---|
272 | struct ReportLUNdata *lun, int *count)
|
---|
273 | {
|
---|
274 | BIG_IOCTL_Command_struct cmd;
|
---|
275 | int rc;
|
---|
276 | unsigned char cdb[16];
|
---|
277 | unsigned int bufsize;
|
---|
278 |
|
---|
279 | int *becount = (int *) lun;
|
---|
280 |
|
---|
281 | memset(lun, 0, sizeof(*lun));
|
---|
282 | bufsize = htonl(sizeof(*lun));
|
---|
283 | memset(cdb, 0, 16);
|
---|
284 | cdb[0] = REPORT_PHYSICAL; /* report physical LUNs */
|
---|
285 | memcpy(&cdb[6], &bufsize, 4);
|
---|
286 |
|
---|
287 | setup_for_ioctl(&cmd, CTLR_LUNID, cdb, 12, 0, (unsigned char *) lun, sizeof(*lun));
|
---|
288 | rc = ioctl(fd, CCISS_BIG_PASSTHRU, &cmd);
|
---|
289 | if (check_ioctl(filename, "report phys luns", rc, &cmd))
|
---|
290 | return -1;
|
---|
291 | *count = ntohl(*becount) / 8;
|
---|
292 | return rc;
|
---|
293 | }
|
---|
294 |
|
---|
295 | /* Send an inquiry for specified page to specified LUNID */
|
---|
296 | static int bmic_inquiry(char *filename, int fd, uint8_t *lunaddrbytes,
|
---|
297 | uint8_t inquiry_page, uint8_t *buffer, uint8_t buffersize)
|
---|
298 | {
|
---|
299 | int rc;
|
---|
300 | unsigned char cdb[6];
|
---|
301 | BIG_IOCTL_Command_struct bmic_command;
|
---|
302 |
|
---|
303 | memset(cdb, 0, sizeof(cdb));
|
---|
304 | cdb[0] = 0x12;
|
---|
305 | cdb[1] = inquiry_page ? 0x01 : 0x00;
|
---|
306 | cdb[2] = inquiry_page;
|
---|
307 | cdb[4] = buffersize;
|
---|
308 |
|
---|
309 | setup_for_ioctl(&bmic_command, lunaddrbytes, cdb, sizeof(cdb),
|
---|
310 | 0, buffer, buffersize);
|
---|
311 | rc = ioctl(fd, CCISS_BIG_PASSTHRU, &bmic_command);
|
---|
312 | if (check_ioctl(filename, "inquiry", rc, &bmic_command))
|
---|
313 | return -1;
|
---|
314 |
|
---|
315 | return 0;
|
---|
316 | }
|
---|
317 |
|
---|
318 | /* Check if device is suitable for changing to the specified mode
|
---|
319 | *
|
---|
320 | * If we are requesting OBDR mode, the device must be a tape drive
|
---|
321 | * and must be from HP.
|
---|
322 | *
|
---|
323 | * If we are requesting to leave OBDR mode, the device must be
|
---|
324 | * an OBDR device (have "$DR-10" at offset 43 in inquiry data
|
---|
325 | */
|
---|
326 | static int is_suitable_device(char *filename, int fd, uint8_t *lunid, int mode)
|
---|
327 | {
|
---|
328 | int rc;
|
---|
329 |
|
---|
330 | #define OBDR_SIG_OFFSET 43
|
---|
331 | #define OBDR_SIGNATURE "$DR-10"
|
---|
332 | #define OBDR_SIG_LEN (sizeof(OBDR_SIGNATURE))
|
---|
333 | #define OBDR_TAPE_INQ_SIZE (OBDR_SIG_OFFSET + OBDR_SIG_LEN)
|
---|
334 |
|
---|
335 | unsigned char inqbuf[OBDR_TAPE_INQ_SIZE];
|
---|
336 | unsigned char device_type;
|
---|
337 | int is_obdr;
|
---|
338 |
|
---|
339 | /* Send inquiry to device. */
|
---|
340 | rc = bmic_inquiry(filename, fd, lunid, 0, inqbuf, sizeof(inqbuf));
|
---|
341 | if (rc) {
|
---|
342 | if (debug)
|
---|
343 | fprintf(stderr, "BMIC inquiry failed.\n");
|
---|
344 | return 0;
|
---|
345 | }
|
---|
346 |
|
---|
347 | #define CD_DEVICE_TYPE 0x05
|
---|
348 | #define TAPE_DEVICE_TYPE 0x01
|
---|
349 | #define DEVICE_TYPE_MASK 0x1f
|
---|
350 | #define GET_DEVICE_TYPE(inquiry_data) ((inquiry_data)[0] & DEVICE_TYPE_MASK)
|
---|
351 |
|
---|
352 | /* Check for the "$DR-10" OBDR signature. */
|
---|
353 | is_obdr = (strncmp((char *) &inqbuf[OBDR_SIG_OFFSET], OBDR_SIGNATURE, OBDR_SIG_LEN) == 0);
|
---|
354 | if ((debug) || (mode == QUERY))
|
---|
355 | fprintf(stderr, "Device at lunid "
|
---|
356 | "0x%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
|
---|
357 | " is%s an OBDR device.\n",
|
---|
358 | lunid[0], lunid[1], lunid[2], lunid[3],
|
---|
359 | lunid[4], lunid[5], lunid[6], lunid[7],
|
---|
360 | is_obdr ? "" : " not");
|
---|
361 | if (!is_obdr)
|
---|
362 | return 0;
|
---|
363 |
|
---|
364 | device_type = GET_DEVICE_TYPE(inqbuf);
|
---|
365 |
|
---|
366 | if ((debug) || (mode == QUERY)) {
|
---|
367 | if (device_type == CD_DEVICE_TYPE) {
|
---|
368 | fprintf(stderr, "Device at lunid "
|
---|
369 | "0x%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
|
---|
370 | " is in CD-ROM mode (%02x).\n",
|
---|
371 | lunid[0], lunid[1], lunid[2], lunid[3],
|
---|
372 | lunid[4], lunid[5], lunid[6], lunid[7],
|
---|
373 | device_type);
|
---|
374 | } else if (device_type == TAPE_DEVICE_TYPE) {
|
---|
375 | fprintf(stderr, "Device at lunid "
|
---|
376 | "0x%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
|
---|
377 | " is in Sequential mode (%02x).\n",
|
---|
378 | lunid[0], lunid[1], lunid[2], lunid[3],
|
---|
379 | lunid[4], lunid[5], lunid[6], lunid[7],
|
---|
380 | device_type);
|
---|
381 | } else {
|
---|
382 | fprintf(stderr, "Device at lunid "
|
---|
383 | "0x%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
|
---|
384 | " is in an UNKNOWN mode (%02x).\n",
|
---|
385 | lunid[0], lunid[1], lunid[2], lunid[3],
|
---|
386 | lunid[4], lunid[5], lunid[6], lunid[7],
|
---|
387 | device_type);
|
---|
388 | }
|
---|
389 | if (mode == QUERY) /* don't exit if just debug... */
|
---|
390 | return 0;
|
---|
391 | }
|
---|
392 |
|
---|
393 | /* If we are requesting leave OBDR, check if "$DR-10" is at offset 43 */
|
---|
394 | if (mode == TAPEMODE) {
|
---|
395 | if (device_type != CD_DEVICE_TYPE)
|
---|
396 | return 0;
|
---|
397 | return 1;
|
---|
398 | }
|
---|
399 | /* else mode must be requesting CDMODE */
|
---|
400 |
|
---|
401 | /* if the device is not a tape drive, bail... */
|
---|
402 | if (device_type != TAPE_DEVICE_TYPE)
|
---|
403 | return 0;
|
---|
404 |
|
---|
405 | /* else device is an HP tape drive. Proceed. */
|
---|
406 | return 1;
|
---|
407 | }
|
---|
408 |
|
---|
409 | /* Send mode select to device to switch it into OBDR mode */
|
---|
410 | static int set_obdr_mode(char *filename, int fd, uint8_t *lunid, int mode)
|
---|
411 | {
|
---|
412 |
|
---|
413 | BIG_IOCTL_Command_struct bmic_command;
|
---|
414 | unsigned char cdb[] = {0x15, 0x10, 0x00, 0x00, 0x08, 0x00};
|
---|
415 | unsigned char enter_obdr_data[] = { 0x00, 0x00, 0x10, 0x00, 0x3e, 0x02, 0x01, 0x00 };
|
---|
416 | unsigned char leave_obdr_data[] = { 0x00, 0x00, 0x00, 0x00, 0x3e, 0x02, 0x00, 0x00 };
|
---|
417 | unsigned char *data;
|
---|
418 | int rc;
|
---|
419 |
|
---|
420 | if (mode == QUERY)
|
---|
421 | return 0;
|
---|
422 |
|
---|
423 | data = (mode == TAPEMODE) ? leave_obdr_data : enter_obdr_data;
|
---|
424 |
|
---|
425 | if (debug)
|
---|
426 | fprintf(stderr, "Setting device to %s mode.\n", mode == TAPEMODE ? "tape" : "cd");
|
---|
427 |
|
---|
428 | setup_for_ioctl(&bmic_command, lunid, cdb, sizeof(cdb), 1,
|
---|
429 | data, sizeof(enter_obdr_data));
|
---|
430 | rc = ioctl(fd, CCISS_BIG_PASSTHRU, &bmic_command);
|
---|
431 | if (check_ioctl(filename, "mode select", rc, &bmic_command))
|
---|
432 | return -1;
|
---|
433 |
|
---|
434 | if (debug)
|
---|
435 | fprintf(stderr, "Set mode to %s successfully\n", mode == TAPEMODE ? "tape" : "cd");
|
---|
436 | return 0;
|
---|
437 | }
|
---|
438 |
|
---|
439 | static int set_obdr_devices_mode(char *filename, int fd, int mode, char *mylunid)
|
---|
440 | {
|
---|
441 | struct ReportLUNdata lun;
|
---|
442 | int rc, i, count;
|
---|
443 | uint8_t *lunid;
|
---|
444 | char *foundlunid = NULL;
|
---|
445 |
|
---|
446 | /* Get a list of lunids for all physical devices on this smart array */
|
---|
447 | count = sizeof(lun);
|
---|
448 | rc = do_report_luns(filename, fd, &lun, &count);
|
---|
449 | if (rc != 0) {
|
---|
450 | if (debug)
|
---|
451 | fprintf(stderr, "Report LUNs failed.\n");
|
---|
452 | return rc;
|
---|
453 | }
|
---|
454 |
|
---|
455 | if (debug)
|
---|
456 | fprintf(stderr, "%d physical luns found.\n", count);
|
---|
457 | /* For each physical device on this smart array ... */
|
---|
458 | for (i = 0; i < count; i++) {
|
---|
459 | lunid = &lun.LUN[i * 8];
|
---|
460 | asprintf(&foundlunid, "0x%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
|
---|
461 | lunid[0], lunid[1], lunid[2], lunid[3],
|
---|
462 | lunid[4], lunid[5], lunid[6], lunid[7]);
|
---|
463 | /* I passed a lunid and will only act for this one, so skip others */
|
---|
464 | if ((mylunid) && (strcmp(mylunid, foundlunid) != 0)) {
|
---|
465 | continue;
|
---|
466 | }
|
---|
467 | if (debug)
|
---|
468 | fprintf(stderr, "Querying device at lunid %s\n", foundlunid);
|
---|
469 | if (is_suitable_device(filename, fd, lunid, mode))
|
---|
470 | set_obdr_mode(filename, fd, lunid, mode);
|
---|
471 | free(foundlunid);
|
---|
472 | }
|
---|
473 | return 0;
|
---|
474 | }
|
---|
475 |
|
---|
476 | static void usage(void)
|
---|
477 | {
|
---|
478 | fprintf(stderr, "usage: %s [-vV] -m [tape|cd|query] [-l lunid] smart_array_device ...\n", progname);
|
---|
479 | fprintf(stderr, "example: %s -m tape /dev/cciss/c1d0 ... to put the OBDR tape drive attached\n"
|
---|
480 | " to the second controller in tape mode\n", progname);
|
---|
481 | exit(1);
|
---|
482 | }
|
---|
483 |
|
---|
484 | int main(int argc, char *argv[])
|
---|
485 | {
|
---|
486 | int i = 0, fd, mode = QUERY, opt;
|
---|
487 | char *mylunid = NULL;
|
---|
488 | static struct option long_options[] = {
|
---|
489 | {"verbose", 0, 0, 'v'},
|
---|
490 | {"lunid", 1, 0, 'l'},
|
---|
491 | {"mode", 1, 0, 'm'},
|
---|
492 | {"version", 0, 0, 'V'},
|
---|
493 | {0, 0, 0, 0},
|
---|
494 | };
|
---|
495 |
|
---|
496 |
|
---|
497 | progname = argv[0];
|
---|
498 |
|
---|
499 | if (argc < 2)
|
---|
500 | usage();
|
---|
501 |
|
---|
502 | while ((opt = getopt_long(argc, argv, "Vvl:m:", long_options, NULL)) != -1) {
|
---|
503 | i++;
|
---|
504 | switch (opt) {
|
---|
505 | case 'v':
|
---|
506 | debug = 1;
|
---|
507 | break;
|
---|
508 | case 'l':
|
---|
509 | asprintf(&mylunid, "%s", optarg);
|
---|
510 | break;
|
---|
511 | case 'm':
|
---|
512 | if (strcmp(optarg, "tape") == 0)
|
---|
513 | mode = TAPEMODE;
|
---|
514 | else if (strcmp(optarg, "query") == 0)
|
---|
515 | mode = QUERY;
|
---|
516 | else if (strcmp(optarg, "cd") == 0)
|
---|
517 | mode = CDMODE;
|
---|
518 | else
|
---|
519 | usage();
|
---|
520 | break;
|
---|
521 | case 'V':
|
---|
522 | printf("%s version %s\n", argv[0], VERSION);
|
---|
523 | exit(0);
|
---|
524 | default: /* '?' */
|
---|
525 | usage();
|
---|
526 | }
|
---|
527 | }
|
---|
528 |
|
---|
529 | if (optind >= argc) {
|
---|
530 | fprintf(stderr, "Expected argument after options\n");
|
---|
531 | usage();
|
---|
532 | }
|
---|
533 |
|
---|
534 | for (i = optind ; i < argc; i++) {
|
---|
535 | if (debug)
|
---|
536 | fprintf(stderr, "%s:\n", argv[i]);
|
---|
537 | fd = open(argv[i], O_RDWR);
|
---|
538 | if (fd < 0) {
|
---|
539 | fprintf(stderr, "%s: Can't open '%s': %s\n",
|
---|
540 | progname, argv[i], strerror(errno));
|
---|
541 | continue;
|
---|
542 | }
|
---|
543 | if (!is_smartarray(fd)) {
|
---|
544 | close(fd);
|
---|
545 | continue;
|
---|
546 | }
|
---|
547 | set_obdr_devices_mode(argv[i], fd, mode, mylunid);
|
---|
548 | close(fd);
|
---|
549 | }
|
---|
550 | free(mylunid);
|
---|
551 | return 0;
|
---|
552 | }
|
---|