]>
Commit | Line | Data |
---|---|---|
832b75ed GG |
1 | /* |
2 | * os_freebsd.c | |
3 | * | |
4 | * Home page of code is: http://smartmontools.sourceforge.net | |
5 | * | |
6 | * Copyright (C) 2003-6 Eduard Martinescu <smartmontools-support@lists.sourceforge.net> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2, or (at your option) | |
11 | * any later version. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * (for example COPYING); if not, write to the Free | |
15 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
16 | */ | |
17 | ||
18 | #include <stdio.h> | |
19 | #include <sys/types.h> | |
20 | #include <dirent.h> | |
21 | #include <fcntl.h> | |
22 | #include <err.h> | |
23 | #include <camlib.h> | |
24 | #include <cam/scsi/scsi_message.h> | |
25 | #include <sys/ata.h> | |
26 | #include <sys/stat.h> | |
27 | #include <unistd.h> | |
28 | #include <fcntl.h> | |
29 | #include <glob.h> | |
30 | #include <fcntl.h> | |
31 | #include <stddef.h> | |
32 | ||
33 | ||
34 | #include "config.h" | |
35 | #include "int64.h" | |
36 | #include "atacmds.h" | |
37 | #include "scsicmds.h" | |
a37e7145 | 38 | #include "cciss.h" |
832b75ed | 39 | #include "utility.h" |
a37e7145 | 40 | #include "extern.h" |
832b75ed GG |
41 | #include "os_freebsd.h" |
42 | ||
a37e7145 | 43 | static const char *filenameandversion="$Id: os_freebsd.cpp,v 1.54 2007/09/06 08:48:55 ballen4705 Exp $"; |
832b75ed | 44 | |
a37e7145 | 45 | const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp,v 1.54 2007/09/06 08:48:55 ballen4705 Exp $" \ |
832b75ed GG |
46 | ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; |
47 | ||
48 | // to hold onto exit code for atexit routine | |
49 | extern int exitstatus; | |
50 | ||
a37e7145 GG |
51 | extern smartmonctrl * con; |
52 | ||
832b75ed GG |
53 | // Private table of open devices: guaranteed zero on startup since |
54 | // part of static data. | |
55 | struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV]; | |
56 | ||
57 | // forward declaration | |
58 | static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *ch); | |
59 | ||
60 | // print examples for smartctl | |
61 | void print_smartctl_examples(){ | |
62 | printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); | |
63 | #ifdef HAVE_GETOPT_LONG | |
64 | printf( | |
65 | " smartctl -a /dev/ad0 (Prints all SMART information)\n\n" | |
66 | " smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n" | |
67 | " (Enables SMART on first disk)\n\n" | |
68 | " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n\n" | |
69 | " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n" | |
70 | " (Prints Self-Test & Attribute errors)\n" | |
71 | " (Prints Self-Test & Attribute errors)\n\n" | |
72 | " smartctl -a --device=3ware,2 /dev/twa0\n" | |
73 | " smartctl -a --device=3ware,2 /dev/twe0\n" | |
74 | " (Prints all SMART information for ATA disk on\n" | |
75 | " third port of first 3ware RAID controller)\n" | |
76 | ); | |
77 | #else | |
78 | printf( | |
79 | " smartctl -a /dev/ad0 (Prints all SMART information)\n" | |
80 | " smartctl -s on -o on -S on /dev/ad0 (Enables SMART on first disk)\n" | |
81 | " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n" | |
82 | " smartctl -A -l selftest -q errorsonly /dev/ad0\n" | |
83 | " (Prints Self-Test & Attribute errors)\n" | |
84 | " smartctl -a -d 3ware,2 /dev/twa0\n" | |
85 | " smartctl -a -d 3ware,2 /dev/twe0\n" | |
86 | ); | |
87 | #endif | |
88 | return; | |
89 | } | |
90 | ||
91 | // Like open(). Return positive integer handle, used by functions below only. mode=="ATA" or "SCSI". | |
a37e7145 | 92 | int deviceopen (const char* dev, __unused char* mode) { |
832b75ed GG |
93 | struct freebsd_dev_channel *fdchan; |
94 | int parse_ok, i; | |
95 | ||
96 | // Search table for a free entry | |
97 | for (i=0; i<FREEBSD_MAXDEV; i++) | |
98 | if (!devicetable[i]) | |
99 | break; | |
100 | ||
101 | // If no free entry found, return error. We have max allowed number | |
102 | // of "file descriptors" already allocated. | |
103 | if (i==FREEBSD_MAXDEV) { | |
104 | errno=EMFILE; | |
105 | return -1; | |
106 | } | |
107 | ||
4d59bff9 | 108 | fdchan = (struct freebsd_dev_channel *)calloc(1,sizeof(struct freebsd_dev_channel)); |
832b75ed GG |
109 | if (fdchan == NULL) { |
110 | // errno already set by call to malloc() | |
111 | return -1; | |
112 | } | |
113 | ||
114 | parse_ok = parse_ata_chan_dev (dev,fdchan); | |
115 | if (parse_ok == CONTROLLER_UNKNOWN) { | |
116 | free(fdchan); | |
117 | errno = ENOTTY; | |
118 | return -1; // can't handle what we don't know | |
119 | } | |
120 | ||
121 | if (parse_ok == CONTROLLER_ATA) { | |
122 | #ifdef IOCATAREQUEST | |
123 | if ((fdchan->device = open(dev,O_RDONLY))<0) { | |
124 | #else | |
125 | if ((fdchan->atacommand = open("/dev/ata",O_RDWR))<0) { | |
126 | #endif | |
127 | int myerror = errno; //preserve across free call | |
128 | free (fdchan); | |
129 | errno = myerror; | |
130 | return -1; | |
131 | } | |
132 | } | |
133 | ||
134 | if (parse_ok == CONTROLLER_3WARE_678K_CHAR) { | |
135 | char buf[512]; | |
136 | sprintf(buf,"/dev/twe%d",fdchan->device); | |
137 | #ifdef IOCATAREQUEST | |
138 | if ((fdchan->device = open(buf,O_RDWR))<0) { | |
139 | #else | |
140 | if ((fdchan->atacommand = open(buf,O_RDWR))<0) { | |
141 | #endif | |
142 | int myerror = errno; // preserver across free call | |
143 | free(fdchan); | |
144 | errno=myerror; | |
145 | return -1; | |
146 | } | |
147 | } | |
148 | ||
149 | if (parse_ok == CONTROLLER_3WARE_9000_CHAR) { | |
150 | char buf[512]; | |
151 | sprintf(buf,"/dev/twa%d",fdchan->device); | |
152 | #ifdef IOCATAREQUEST | |
153 | if ((fdchan->device = open(buf,O_RDWR))<0) { | |
154 | #else | |
155 | if ((fdchan->atacommand = open(buf,O_RDWR))<0) { | |
156 | #endif | |
157 | int myerror = errno; // preserver across free call | |
158 | free(fdchan); | |
159 | errno=myerror; | |
160 | return -1; | |
161 | } | |
162 | } | |
163 | ||
a37e7145 GG |
164 | if (parse_ok == CONTROLLER_CCISS) { |
165 | if ((fdchan->device = open(dev,O_RDWR))<0) { | |
166 | int myerror = errno; // preserver across free call | |
167 | free(fdchan); | |
168 | errno=myerror; | |
169 | return -1; | |
170 | } | |
171 | } | |
172 | ||
832b75ed GG |
173 | if (parse_ok == CONTROLLER_SCSI) { |
174 | // this is really a NO-OP, as the parse takes care | |
175 | // of filling in correct details | |
176 | } | |
177 | ||
178 | // return pointer to "file descriptor" table entry, properly offset. | |
179 | devicetable[i]=fdchan; | |
180 | return i+FREEBSD_FDOFFSET; | |
181 | } | |
182 | ||
183 | // Returns 1 if device not available/open/found else 0. Also shifts fd into valid range. | |
184 | static int isnotopen(int *fd, struct freebsd_dev_channel** fdchan) { | |
185 | // put valid "file descriptor" into range 0...FREEBSD_MAXDEV-1 | |
186 | *fd -= FREEBSD_FDOFFSET; | |
187 | ||
188 | // check for validity of "file descriptor". | |
189 | if (*fd<0 || *fd>=FREEBSD_MAXDEV || !((*fdchan)=devicetable[*fd])) { | |
190 | errno = ENODEV; | |
191 | return 1; | |
192 | } | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | // Like close(). Acts on handles returned by above function. | |
198 | int deviceclose (int fd) { | |
199 | struct freebsd_dev_channel *fdchan; | |
200 | int failed = 0; | |
201 | ||
202 | // check for valid file descriptor | |
203 | if (isnotopen(&fd, &fdchan)) | |
204 | return -1; | |
205 | ||
206 | ||
207 | // did we allocate a SCSI device name? | |
208 | if (fdchan->devname) | |
209 | free(fdchan->devname); | |
210 | ||
211 | // close device, if open | |
212 | #ifdef IOCATAREQUEST | |
213 | if (fdchan->device) | |
214 | failed=close(fdchan->device); | |
215 | #else | |
216 | if (fdchan->atacommand) | |
217 | failed=close(fdchan->atacommand); | |
218 | #endif | |
219 | ||
220 | if (fdchan->scsicontrol) | |
221 | failed=close(fdchan->scsicontrol); | |
222 | ||
223 | // if close succeeded, then remove from device list | |
224 | // Eduard, should we also remove it from list if close() fails? I'm | |
225 | // not sure. Here I only remove it from list if close() worked. | |
226 | if (!failed) { | |
227 | free(fdchan); | |
228 | devicetable[fd]=NULL; | |
229 | } | |
230 | ||
231 | return failed; | |
232 | } | |
233 | ||
234 | #define NO_RETURN 0 | |
235 | #define BAD_SMART 1 | |
236 | #define NO_DISK_3WARE 2 | |
237 | #define BAD_KERNEL 3 | |
238 | #define MAX_MSG 3 | |
239 | ||
240 | // Utility function for printing warnings | |
241 | void printwarning(int msgNo, const char* extra) { | |
242 | static int printed[] = {0,0,0,0}; | |
243 | static const char* message[]={ | |
244 | "The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n can not be retrieved with this version of ATAng, please do not rely on this value\nYou should update to at least 5.2\n", | |
245 | ||
246 | "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n", | |
247 | ||
248 | "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n", | |
249 | ||
250 | "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n" | |
251 | }; | |
252 | ||
253 | if (msgNo >= 0 && msgNo <= MAX_MSG) { | |
254 | if (!printed[msgNo]) { | |
255 | printed[msgNo] = 1; | |
256 | pout("%s", message[msgNo]); | |
257 | if (extra) | |
258 | pout("%s",extra); | |
259 | } | |
260 | } | |
261 | return; | |
262 | } | |
263 | ||
832b75ed | 264 | // Interface to ATA devices. See os_linux.c |
a37e7145 GG |
265 | |
266 | int marvell_command_interface(__unused int fd, __unused smart_command_set command, __unused int select, __unused char *data) { | |
267 | return -1; | |
832b75ed GG |
268 | } |
269 | ||
a37e7145 | 270 | int highpoint_command_interface(__unused int fd, __unused smart_command_set command, __unused int select, __unused char *data) { |
4d59bff9 GG |
271 | { |
272 | return -1; | |
273 | } | |
274 | ||
832b75ed GG |
275 | int ata_command_interface(int fd, smart_command_set command, int select, char *data) { |
276 | #if !defined(ATAREQUEST) && !defined(IOCATAREQUEST) | |
277 | // sorry, but without ATAng, we can't do anything here | |
278 | printwarning(BAD_KERNEL,NULL); | |
279 | errno = ENOSYS; | |
280 | return -1; | |
281 | #else | |
282 | struct freebsd_dev_channel* con; | |
283 | int retval, copydata=0; | |
284 | #ifdef IOCATAREQUEST | |
285 | struct ata_ioc_request request; | |
286 | #else | |
287 | struct ata_cmd iocmd; | |
288 | #endif | |
289 | unsigned char buff[512]; | |
290 | ||
291 | // check that "file descriptor" is valid | |
292 | if (isnotopen(&fd,&con)) | |
293 | return -1; | |
294 | ||
295 | bzero(buff,512); | |
296 | ||
297 | #ifdef IOCATAREQUEST | |
298 | bzero(&request,sizeof(struct ata_ioc_request)); | |
299 | #else | |
300 | bzero(&iocmd,sizeof(struct ata_cmd)); | |
301 | #endif | |
302 | bzero(buff,512); | |
303 | ||
304 | #ifndef IOCATAREQUEST | |
305 | iocmd.cmd=ATAREQUEST; | |
306 | iocmd.channel=con->channel; | |
307 | iocmd.device=con->device; | |
308 | #define request iocmd.u.request | |
309 | #endif | |
310 | ||
311 | request.u.ata.command=ATA_SMART_CMD; | |
312 | request.timeout=600; | |
313 | switch (command){ | |
314 | case READ_VALUES: | |
315 | request.u.ata.feature=ATA_SMART_READ_VALUES; | |
316 | request.u.ata.lba=0xc24f<<8; | |
317 | request.flags=ATA_CMD_READ; | |
4d59bff9 | 318 | request.data=(char *)buff; |
832b75ed GG |
319 | request.count=512; |
320 | copydata=1; | |
321 | break; | |
322 | case READ_THRESHOLDS: | |
323 | request.u.ata.feature=ATA_SMART_READ_THRESHOLDS; | |
324 | request.u.ata.count=1; | |
325 | request.u.ata.lba=1|(0xc24f<<8); | |
326 | request.flags=ATA_CMD_READ; | |
4d59bff9 | 327 | request.data=(char *)buff; |
832b75ed GG |
328 | request.count=512; |
329 | copydata=1; | |
330 | break; | |
331 | case READ_LOG: | |
332 | request.u.ata.feature=ATA_SMART_READ_LOG_SECTOR; | |
333 | request.u.ata.lba=select|(0xc24f<<8); | |
334 | request.u.ata.count=1; | |
335 | request.flags=ATA_CMD_READ; | |
4d59bff9 | 336 | request.data=(char *)buff; |
832b75ed GG |
337 | request.count=512; |
338 | copydata=1; | |
339 | break; | |
340 | case IDENTIFY: | |
341 | request.u.ata.command=ATA_IDENTIFY_DEVICE; | |
342 | request.flags=ATA_CMD_READ; | |
4d59bff9 | 343 | request.data=(char *)buff; |
832b75ed GG |
344 | request.count=512; |
345 | copydata=1; | |
346 | break; | |
347 | case PIDENTIFY: | |
348 | request.u.ata.command=ATA_IDENTIFY_PACKET_DEVICE; | |
349 | request.flags=ATA_CMD_READ; | |
4d59bff9 | 350 | request.data=(char *)buff; |
832b75ed GG |
351 | request.count=512; |
352 | copydata=1; | |
353 | break; | |
354 | case ENABLE: | |
355 | request.u.ata.feature=ATA_SMART_ENABLE; | |
356 | request.u.ata.lba=0xc24f<<8; | |
357 | request.flags=ATA_CMD_CONTROL; | |
358 | break; | |
359 | case DISABLE: | |
360 | request.u.ata.feature=ATA_SMART_DISABLE; | |
361 | request.u.ata.lba=0xc24f<<8; | |
362 | request.flags=ATA_CMD_CONTROL; | |
363 | break; | |
364 | case AUTO_OFFLINE: | |
365 | // NOTE: According to ATAPI 4 and UP, this command is obsolete | |
366 | request.u.ata.feature=ATA_SMART_AUTO_OFFLINE; | |
367 | request.u.ata.lba=select|(0xc24f<<8); | |
368 | request.flags=ATA_CMD_CONTROL; | |
369 | break; | |
370 | case AUTOSAVE: | |
371 | request.u.ata.feature=ATA_SMART_AUTOSAVE; | |
372 | request.u.ata.count=0xf1; // to enable autosave | |
373 | request.u.ata.lba=0xc24f<<8; | |
374 | request.flags=ATA_CMD_CONTROL; | |
375 | break; | |
376 | case IMMEDIATE_OFFLINE: | |
377 | request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE; | |
378 | request.u.ata.lba = select|(0xc24f<<8); // put test in sector | |
379 | request.flags=ATA_CMD_CONTROL; | |
380 | break; | |
381 | case STATUS_CHECK: // same command, no HDIO in FreeBSD | |
382 | case STATUS: | |
383 | // this command only says if SMART is working. It could be | |
384 | // replaced with STATUS_CHECK below. | |
385 | request.u.ata.feature=ATA_SMART_STATUS; | |
386 | request.u.ata.lba=0xc24f<<8; | |
387 | request.flags=ATA_CMD_CONTROL; | |
388 | break; | |
389 | default: | |
390 | pout("Unrecognized command %d in ata_command_interface()\n" | |
391 | "Please contact " PACKAGE_BUGREPORT "\n", command); | |
392 | errno=ENOSYS; | |
393 | return -1; | |
394 | } | |
395 | ||
396 | if (command==STATUS_CHECK){ | |
397 | unsigned const char normal_lo=0x4f, normal_hi=0xc2; | |
398 | unsigned const char failed_lo=0xf4, failed_hi=0x2c; | |
399 | unsigned char low,high; | |
400 | ||
401 | #ifdef IOCATAREQUEST | |
402 | if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error) | |
403 | #else | |
404 | if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error) | |
405 | #endif | |
406 | return -1; | |
407 | ||
408 | #if __FreeBSD_version < 502000 | |
409 | printwarning(NO_RETURN,NULL); | |
410 | #endif | |
411 | ||
412 | high = (request.u.ata.lba >> 16) & 0xff; | |
413 | low = (request.u.ata.lba >> 8) & 0xff; | |
414 | ||
415 | // Cyl low and Cyl high unchanged means "Good SMART status" | |
416 | if (low==normal_lo && high==normal_hi) | |
417 | return 0; | |
418 | ||
419 | // These values mean "Bad SMART status" | |
420 | if (low==failed_lo && high==failed_hi) | |
421 | return 1; | |
422 | ||
423 | // We haven't gotten output that makes sense; print out some debugging info | |
424 | char buf[512]; | |
425 | sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", | |
426 | (int)request.u.ata.command, | |
427 | (int)request.u.ata.feature, | |
428 | (int)request.u.ata.count, | |
429 | (int)((request.u.ata.lba) & 0xff), | |
430 | (int)((request.u.ata.lba>>8) & 0xff), | |
431 | (int)((request.u.ata.lba>>16) & 0xff), | |
432 | (int)request.error); | |
433 | printwarning(BAD_SMART,buf); | |
434 | return 0; | |
435 | } | |
436 | ||
437 | #ifdef IOCATAREQUEST | |
438 | if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error) | |
439 | #else | |
440 | if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error) | |
441 | #endif | |
442 | { | |
443 | return -1; | |
444 | } | |
445 | // | |
446 | if (copydata) | |
447 | memcpy(data, buff, 512); | |
448 | ||
449 | return 0; | |
450 | #endif | |
451 | } | |
452 | ||
453 | ||
454 | // Interface to SCSI devices. See os_linux.c | |
a37e7145 | 455 | int do_normal_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) |
832b75ed GG |
456 | { |
457 | struct freebsd_dev_channel* con = NULL; | |
458 | struct cam_device* cam_dev = NULL; | |
459 | union ccb *ccb; | |
460 | ||
461 | ||
462 | if (report > 0) { | |
463 | unsigned int k; | |
464 | const unsigned char * ucp = iop->cmnd; | |
465 | const char * np; | |
466 | ||
467 | np = scsi_get_opcode_name(ucp[0]); | |
468 | pout(" [%s: ", np ? np : "<unknown opcode>"); | |
469 | for (k = 0; k < iop->cmnd_len; ++k) | |
470 | pout("%02x ", ucp[k]); | |
471 | if ((report > 1) && | |
472 | (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { | |
473 | int trunc = (iop->dxfer_len > 256) ? 1 : 0; | |
474 | ||
475 | pout("]\n Outgoing data, len=%d%s:\n", (int)iop->dxfer_len, | |
476 | (trunc ? " [only first 256 bytes shown]" : "")); | |
477 | dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); | |
478 | } | |
479 | else | |
480 | pout("]"); | |
481 | } | |
482 | ||
483 | // check that "file descriptor" is valid | |
484 | if (isnotopen(&fd,&con)) | |
485 | return -ENOTTY; | |
486 | ||
487 | ||
488 | if (!(cam_dev = cam_open_spec_device(con->devname,con->unitnum,O_RDWR,NULL))) { | |
489 | warnx("%s",cam_errbuf); | |
490 | return -1; | |
491 | } | |
492 | ||
493 | if (!(ccb = cam_getccb(cam_dev))) { | |
494 | warnx("error allocating ccb"); | |
495 | return -ENOMEM; | |
496 | } | |
497 | ||
498 | // clear out structure, except for header that was filled in for us | |
499 | bzero(&(&ccb->ccb_h)[1], | |
500 | sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); | |
501 | ||
502 | cam_fill_csio(&ccb->csio, | |
503 | /*retrires*/ 1, | |
504 | /*cbfcnp*/ NULL, | |
505 | /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)), | |
506 | /* tagaction */ MSG_SIMPLE_Q_TAG, | |
507 | /* dataptr */ iop->dxferp, | |
508 | /* datalen */ iop->dxfer_len, | |
509 | /* senselen */ iop->max_sense_len, | |
510 | /* cdblen */ iop->cmnd_len, | |
511 | /* timout (converted to seconds) */ iop->timeout*1000); | |
512 | memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len); | |
513 | ||
514 | if (cam_send_ccb(cam_dev,ccb) < 0) { | |
515 | warn("error sending SCSI ccb"); | |
516 | #if __FreeBSD_version > 500000 | |
517 | cam_error_print(cam_dev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); | |
518 | #endif | |
519 | cam_freeccb(ccb); | |
520 | return -1; | |
521 | } | |
522 | ||
523 | if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { | |
524 | #if __FreeBSD_version > 500000 | |
525 | cam_error_print(cam_dev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); | |
526 | #endif | |
527 | cam_freeccb(ccb); | |
528 | return -1; | |
529 | } | |
530 | ||
531 | if (iop->sensep) { | |
532 | memcpy(iop->sensep,&(ccb->csio.sense_data),sizeof(struct scsi_sense_data)); | |
533 | iop->resp_sense_len = sizeof(struct scsi_sense_data); | |
534 | } | |
535 | ||
536 | iop->scsi_status = ccb->csio.scsi_status; | |
537 | ||
538 | cam_freeccb(ccb); | |
539 | ||
540 | if (cam_dev) | |
541 | cam_close_device(cam_dev); | |
542 | ||
543 | if (report > 0) { | |
544 | int trunc; | |
545 | ||
546 | pout(" status=0\n"); | |
547 | trunc = (iop->dxfer_len > 256) ? 1 : 0; | |
548 | ||
549 | pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, | |
550 | (trunc ? " [only first 256 bytes shown]" : "")); | |
551 | dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); | |
552 | } | |
553 | return 0; | |
554 | } | |
555 | ||
a37e7145 GG |
556 | /* Check and call the right interface. Maybe when the do_generic_scsi_cmd_io interface is better |
557 | we can take off this crude way of calling the right interface */ | |
558 | int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report) | |
559 | { | |
560 | struct freebsd_dev_channel *fdchan; | |
561 | switch(con->controller_type) | |
562 | { | |
563 | case CONTROLLER_CCISS: | |
564 | // check that "file descriptor" is valid | |
565 | if (isnotopen(&dev_fd,&fdchan)) | |
566 | return -ENOTTY; | |
567 | #ifdef HAVE_DEV_CISS_CISSIO_H | |
568 | return cciss_io_interface(fdchan->device, con->controller_port-1, iop, report); | |
569 | #else | |
570 | { | |
571 | static int warned = 0; | |
572 | if (!warned) { | |
573 | pout("CCISS support is not available in this build of smartmontools,\n" | |
574 | "/usr/src/sys/dev/ciss/cissio.h was not available at build time.\n\n"); | |
575 | warned = 1; | |
576 | } | |
577 | } | |
578 | errno = ENOSYS; | |
579 | return -1; | |
580 | #endif | |
581 | // not reached | |
582 | break; | |
583 | default: | |
584 | return do_normal_scsi_cmnd_io(dev_fd, iop, report); | |
585 | // not reached | |
586 | break; | |
587 | } | |
588 | } | |
589 | ||
832b75ed GG |
590 | // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c |
591 | ||
592 | #define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520 | |
593 | #define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048 | |
594 | #define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) ) | |
595 | ||
596 | int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) { | |
597 | // to hold true file descriptor | |
598 | struct freebsd_dev_channel* con; | |
599 | ||
600 | // return value and buffer for ioctl() | |
601 | int ioctlreturn, readdata=0; | |
602 | struct twe_usercommand* cmd_twe = NULL; | |
603 | TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL; | |
604 | TWE_Command_ATA* ata = NULL; | |
605 | ||
606 | // Used by both the SCSI and char interfaces | |
607 | char ioctl_buffer[TW_IOCTL_BUFFER_SIZE]; | |
608 | ||
609 | if (disknum < 0) { | |
610 | printwarning(NO_DISK_3WARE,NULL); | |
611 | return -1; | |
612 | } | |
613 | ||
614 | // check that "file descriptor" is valid | |
615 | if (isnotopen(&fd,&con)) | |
616 | return -1; | |
617 | ||
618 | memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE); | |
619 | ||
620 | if (escalade_type==CONTROLLER_3WARE_9000_CHAR) { | |
621 | cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer; | |
622 | cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf; | |
623 | cmd_twa->driver_pkt.buffer_length = 512; | |
624 | ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k; | |
625 | } else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) { | |
626 | cmd_twe = (struct twe_usercommand*)ioctl_buffer; | |
627 | ata = &cmd_twe->tu_command.ata; | |
628 | } else { | |
629 | pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n" | |
630 | "Please contact " PACKAGE_BUGREPORT "\n", escalade_type, disknum); | |
631 | errno=ENOSYS; | |
632 | return -1; | |
633 | } | |
634 | ||
635 | ata->opcode = TWE_OP_ATA_PASSTHROUGH; | |
636 | ||
637 | // Same for (almost) all commands - but some reset below | |
638 | ata->request_id = 0xFF; | |
a37e7145 | 639 | ata->unit = disknum; |
832b75ed GG |
640 | ata->status = 0; |
641 | ata->flags = 0x1; | |
642 | ata->drive_head = 0x0; | |
643 | ata->sector_num = 0; | |
644 | ||
645 | // All SMART commands use this CL/CH signature. These are magic | |
646 | // values from the ATA specifications. | |
647 | ata->cylinder_lo = 0x4F; | |
648 | ata->cylinder_hi = 0xC2; | |
649 | ||
650 | // SMART ATA COMMAND REGISTER value | |
651 | ata->command = ATA_SMART_CMD; | |
652 | ||
653 | // Is this a command that reads or returns 512 bytes? | |
654 | // passthru->param values are: | |
655 | // 0x0 - non data command without TFR write check, | |
656 | // 0x8 - non data command with TFR write check, | |
657 | // 0xD - data command that returns data to host from device | |
658 | // 0xF - data command that writes data from host to device | |
659 | // passthru->size values are 0x5 for non-data and 0x07 for data | |
660 | if (command == READ_VALUES || | |
661 | command == READ_THRESHOLDS || | |
662 | command == READ_LOG || | |
663 | command == IDENTIFY || | |
664 | command == WRITE_LOG ) { | |
665 | readdata=1; | |
666 | if (escalade_type==CONTROLLER_3WARE_678K_CHAR) { | |
667 | cmd_twe->tu_data = data; | |
668 | cmd_twe->tu_size = 512; | |
669 | } | |
670 | ata->sgl_offset = 0x5; | |
671 | ata->size = 0x5; | |
672 | ata->param = 0xD; | |
673 | ata->sector_count = 0x1; | |
674 | // For 64-bit to work correctly, up the size of the command packet | |
675 | // in dwords by 1 to account for the 64-bit single sgl 'address' | |
676 | // field. Note that this doesn't agree with the typedefs but it's | |
677 | // right (agree with kernel driver behavior/typedefs). | |
678 | //if (sizeof(long)==8) | |
679 | // ata->size++; | |
680 | } | |
681 | else { | |
682 | // Non data command -- but doesn't use large sector | |
683 | // count register values. | |
684 | ata->sgl_offset = 0x0; | |
685 | ata->size = 0x5; | |
686 | ata->param = 0x8; | |
687 | ata->sector_count = 0x0; | |
688 | } | |
689 | ||
690 | // Now set ATA registers depending upon command | |
691 | switch (command){ | |
692 | case CHECK_POWER_MODE: | |
693 | ata->command = ATA_CHECK_POWER_MODE; | |
694 | ata->features = 0; | |
695 | ata->cylinder_lo = 0; | |
696 | ata->cylinder_hi = 0; | |
697 | break; | |
698 | case READ_VALUES: | |
699 | ata->features = ATA_SMART_READ_VALUES; | |
700 | break; | |
701 | case READ_THRESHOLDS: | |
702 | ata->features = ATA_SMART_READ_THRESHOLDS; | |
703 | break; | |
704 | case READ_LOG: | |
705 | ata->features = ATA_SMART_READ_LOG_SECTOR; | |
706 | // log number to return | |
707 | ata->sector_num = select; | |
708 | break; | |
709 | case WRITE_LOG: | |
710 | readdata=0; | |
711 | ata->features = ATA_SMART_WRITE_LOG_SECTOR; | |
712 | ata->sector_count = 1; | |
713 | ata->sector_num = select; | |
714 | ata->param = 0xF; // PIO data write | |
715 | break; | |
716 | case IDENTIFY: | |
717 | // ATA IDENTIFY DEVICE | |
718 | ata->command = ATA_IDENTIFY_DEVICE; | |
719 | ata->features = 0; | |
720 | ata->cylinder_lo = 0; | |
721 | ata->cylinder_hi = 0; | |
722 | break; | |
723 | case PIDENTIFY: | |
724 | // 3WARE controller can NOT have packet device internally | |
725 | pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", disknum); | |
726 | errno=ENODEV; | |
727 | return -1; | |
728 | case ENABLE: | |
729 | ata->features = ATA_SMART_ENABLE; | |
730 | break; | |
731 | case DISABLE: | |
732 | ata->features = ATA_SMART_DISABLE; | |
733 | break; | |
734 | case AUTO_OFFLINE: | |
735 | ata->features = ATA_SMART_AUTO_OFFLINE; | |
736 | // Enable or disable? | |
737 | ata->sector_count = select; | |
738 | break; | |
739 | case AUTOSAVE: | |
740 | ata->features = ATA_SMART_AUTOSAVE; | |
741 | // Enable or disable? | |
742 | ata->sector_count = select; | |
743 | break; | |
744 | case IMMEDIATE_OFFLINE: | |
745 | ata->features = ATA_SMART_IMMEDIATE_OFFLINE; | |
746 | // What test type to run? | |
747 | ata->sector_num = select; | |
748 | break; | |
749 | case STATUS_CHECK: | |
750 | ata->features = ATA_SMART_STATUS; | |
751 | break; | |
752 | case STATUS: | |
753 | // This is JUST to see if SMART is enabled, by giving SMART status | |
754 | // command. But it doesn't say if status was good, or failing. | |
755 | // See below for the difference. | |
756 | ata->features = ATA_SMART_STATUS; | |
757 | break; | |
758 | default: | |
759 | pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n" | |
760 | "Please contact " PACKAGE_BUGREPORT "\n", command, disknum); | |
761 | errno=ENOSYS; | |
762 | return -1; | |
763 | } | |
764 | ||
765 | // Now send the command down through an ioctl() | |
766 | if (escalade_type==CONTROLLER_3WARE_9000_CHAR) { | |
767 | #ifdef IOCATAREQUEST | |
768 | ioctlreturn=ioctl(con->device,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa); | |
769 | #else | |
770 | ioctlreturn=ioctl(con->atacommand,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa); | |
771 | #endif | |
772 | } else { | |
773 | #ifdef IOCATAREQUEST | |
774 | ioctlreturn=ioctl(con->device,TWEIO_COMMAND,cmd_twe); | |
775 | #else | |
776 | ioctlreturn=ioctl(con->atacommand,TWEIO_COMMAND,cmd_twe); | |
777 | #endif | |
778 | } | |
779 | ||
780 | // Deal with the different error cases | |
781 | if (ioctlreturn) { | |
782 | if (!errno) | |
783 | errno=EIO; | |
784 | return -1; | |
785 | } | |
786 | ||
787 | // See if the ATA command failed. Now that we have returned from | |
788 | // the ioctl() call, if passthru is valid, then: | |
789 | // - ata->status contains the 3ware controller STATUS | |
790 | // - ata->command contains the ATA STATUS register | |
791 | // - ata->features contains the ATA ERROR register | |
792 | // | |
793 | // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS | |
794 | // If bit 0 (error bit) is set, then ATA ERROR register is valid. | |
795 | // While we *might* decode the ATA ERROR register, at the moment it | |
796 | // doesn't make much sense: we don't care in detail why the error | |
797 | // happened. | |
798 | ||
799 | if (ata->status || (ata->command & 0x21)) { | |
800 | pout("Command failed, ata.status=(0x%2.2x), ata.command=(0x%2.2x), ata.flags=(0x%2.2x)\n",ata->status,ata->command,ata->flags); | |
801 | errno=EIO; | |
802 | return -1; | |
803 | } | |
804 | ||
805 | // If this is a read data command, copy data to output buffer | |
806 | if (readdata) { | |
807 | if (escalade_type==CONTROLLER_3WARE_9000_CHAR) | |
808 | memcpy(data, cmd_twa->pdata, 512); | |
809 | } | |
810 | ||
811 | // For STATUS_CHECK, we need to check register values | |
812 | if (command==STATUS_CHECK) { | |
813 | ||
814 | // To find out if the SMART RETURN STATUS is good or failing, we | |
815 | // need to examine the values of the Cylinder Low and Cylinder | |
816 | // High Registers. | |
817 | ||
818 | unsigned short cyl_lo=ata->cylinder_lo; | |
819 | unsigned short cyl_hi=ata->cylinder_hi; | |
820 | ||
821 | // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good. | |
822 | if (cyl_lo==0x4F && cyl_hi==0xC2) | |
823 | return 0; | |
824 | ||
825 | // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL | |
826 | if (cyl_lo==0xF4 && cyl_hi==0x2C) | |
827 | return 1; | |
828 | ||
829 | errno=EIO; | |
830 | return -1; | |
831 | } | |
832 | ||
833 | // copy sector count register (one byte!) to return data | |
834 | if (command==CHECK_POWER_MODE) | |
835 | *data=*(char *)&(ata->sector_count); | |
836 | ||
837 | // look for nonexistent devices/ports | |
838 | if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) { | |
839 | errno=ENODEV; | |
840 | return -1; | |
841 | } | |
842 | ||
843 | return 0; | |
844 | } | |
845 | ||
846 | static int get_tw_channel_unit (const char* name, int* unit, int* dev) { | |
847 | const char *p; | |
848 | ||
849 | /* device node sanity check */ | |
850 | for (p = name + 3; *p; p++) | |
851 | if (*p < '0' || *p > '9') | |
852 | return -1; | |
853 | if (strlen(name) > 4 && *(name + 3) == '0') | |
854 | return -1; | |
855 | ||
856 | if (dev != NULL) | |
857 | *dev=atoi(name + 3); | |
858 | ||
859 | /* no need for unit number */ | |
860 | if (unit != NULL) | |
861 | *unit=0; | |
862 | return 0; | |
863 | } | |
864 | ||
865 | ||
866 | #ifndef IOCATAREQUEST | |
867 | static int get_ata_channel_unit ( const char* name, int* unit, int* dev) { | |
868 | #ifndef ATAREQUEST | |
869 | *dev=0; | |
870 | *unit=0; | |
871 | return 0; | |
872 | #else | |
873 | // there is no direct correlation between name 'ad0, ad1, ...' and | |
874 | // channel/unit number. So we need to iterate through the possible | |
875 | // channels and check each unit to see if we match names | |
876 | struct ata_cmd iocmd; | |
877 | int fd,maxunit; | |
878 | ||
879 | bzero(&iocmd, sizeof(struct ata_cmd)); | |
880 | ||
881 | if ((fd = open("/dev/ata", O_RDWR)) < 0) | |
882 | return -errno; | |
883 | ||
884 | iocmd.cmd = ATAGMAXCHANNEL; | |
885 | if (ioctl(fd, IOCATA, &iocmd) < 0) { | |
886 | return -errno; | |
887 | close(fd); | |
888 | } | |
889 | maxunit = iocmd.u.maxchan; | |
890 | for (*unit = 0; *unit < maxunit; (*unit)++) { | |
891 | iocmd.channel = *unit; | |
892 | iocmd.device = -1; | |
893 | iocmd.cmd = ATAGPARM; | |
894 | if (ioctl(fd, IOCATA, &iocmd) < 0) { | |
895 | close(fd); | |
896 | return -errno; | |
897 | } | |
898 | if (iocmd.u.param.type[0] && !strcmp(name,iocmd.u.param.name[0])) { | |
899 | *dev = 0; | |
900 | break; | |
901 | } | |
902 | if (iocmd.u.param.type[1] && !strcmp(name,iocmd.u.param.name[1])) { | |
903 | *dev = 1; | |
904 | break; | |
905 | } | |
906 | } | |
907 | close(fd); | |
908 | if (*unit == maxunit) | |
909 | return -1; | |
910 | else | |
911 | return 0; | |
912 | #endif | |
913 | } | |
914 | #endif | |
915 | ||
916 | // Guess device type (ata or scsi) based on device name (FreeBSD | |
917 | // specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst, | |
918 | // osst, nosst and sg. | |
919 | static const char * fbsd_dev_prefix = "/dev/"; | |
920 | static const char * fbsd_dev_ata_disk_prefix = "ad"; | |
921 | static const char * fbsd_dev_scsi_disk_plus = "da"; | |
922 | static const char * fbsd_dev_scsi_tape1 = "sa"; | |
923 | static const char * fbsd_dev_scsi_tape2 = "nsa"; | |
924 | static const char * fbsd_dev_scsi_tape3 = "esa"; | |
925 | static const char * fbsd_dev_twe_ctrl = "twe"; | |
926 | static const char * fbsd_dev_twa_ctrl = "twa"; | |
a37e7145 | 927 | static const char * fbsd_dev_cciss = "ciss"; |
832b75ed GG |
928 | |
929 | static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan) { | |
930 | int len; | |
931 | int dev_prefix_len = strlen(fbsd_dev_prefix); | |
932 | ||
933 | // if dev_name null, or string length zero | |
934 | if (!dev_name || !(len = strlen(dev_name))) | |
935 | return CONTROLLER_UNKNOWN; | |
936 | ||
937 | // Remove the leading /dev/... if it's there | |
938 | if (!strncmp(fbsd_dev_prefix, dev_name, dev_prefix_len)) { | |
939 | if (len <= dev_prefix_len) | |
940 | // if nothing else in the string, unrecognized | |
941 | return CONTROLLER_UNKNOWN; | |
942 | // else advance pointer to following characters | |
943 | dev_name += dev_prefix_len; | |
944 | } | |
945 | // form /dev/ad* or ad* | |
946 | if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name, | |
947 | strlen(fbsd_dev_ata_disk_prefix))) { | |
948 | #ifndef IOCATAREQUEST | |
949 | if (chan != NULL) { | |
950 | if (get_ata_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { | |
951 | return CONTROLLER_UNKNOWN; | |
952 | } | |
953 | } | |
954 | #endif | |
955 | return CONTROLLER_ATA; | |
956 | } | |
957 | ||
958 | // form /dev/da* or da* | |
959 | if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name, | |
960 | strlen(fbsd_dev_scsi_disk_plus))) | |
961 | goto handlescsi; | |
962 | ||
963 | // form /dev/sa* or sa* | |
964 | if (!strncmp(fbsd_dev_scsi_tape1, dev_name, | |
965 | strlen(fbsd_dev_scsi_tape1))) | |
966 | goto handlescsi; | |
967 | ||
968 | // form /dev/nsa* or nsa* | |
969 | if (!strncmp(fbsd_dev_scsi_tape2, dev_name, | |
970 | strlen(fbsd_dev_scsi_tape2))) | |
971 | goto handlescsi; | |
972 | ||
973 | // form /dev/esa* or esa* | |
974 | if (!strncmp(fbsd_dev_scsi_tape3, dev_name, | |
975 | strlen(fbsd_dev_scsi_tape3))) | |
976 | goto handlescsi; | |
977 | ||
978 | if (!strncmp(fbsd_dev_twa_ctrl,dev_name, | |
979 | strlen(fbsd_dev_twa_ctrl))) { | |
980 | if (chan != NULL) { | |
981 | if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { | |
982 | return CONTROLLER_UNKNOWN; | |
983 | } | |
984 | } | |
985 | else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) { | |
986 | return CONTROLLER_UNKNOWN; | |
987 | } | |
988 | return CONTROLLER_3WARE_9000_CHAR; | |
989 | } | |
990 | ||
991 | if (!strncmp(fbsd_dev_twe_ctrl,dev_name, | |
992 | strlen(fbsd_dev_twe_ctrl))) { | |
993 | if (chan != NULL) { | |
994 | if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { | |
995 | return CONTROLLER_UNKNOWN; | |
996 | } | |
997 | } | |
998 | else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) { | |
999 | return CONTROLLER_UNKNOWN; | |
1000 | } | |
1001 | return CONTROLLER_3WARE_678K_CHAR; | |
1002 | } | |
a37e7145 GG |
1003 | // form /dev/ciss* |
1004 | if (!strncmp(fbsd_dev_cciss, dev_name, | |
1005 | strlen(fbsd_dev_cciss))) | |
1006 | return CONTROLLER_CCISS; | |
832b75ed GG |
1007 | |
1008 | // we failed to recognize any of the forms | |
1009 | return CONTROLLER_UNKNOWN; | |
1010 | ||
1011 | handlescsi: | |
1012 | if (chan != NULL) { | |
4d59bff9 | 1013 | if (!(chan->devname = (char *)calloc(1,DEV_IDLEN+1))) |
832b75ed GG |
1014 | return CONTROLLER_UNKNOWN; |
1015 | ||
1016 | if (cam_get_device(dev_name,chan->devname,DEV_IDLEN,&(chan->unitnum)) == -1) | |
1017 | return CONTROLLER_UNKNOWN; | |
1018 | } | |
1019 | return CONTROLLER_SCSI; | |
1020 | ||
1021 | } | |
1022 | ||
1023 | int guess_device_type (const char* dev_name) { | |
1024 | return parse_ata_chan_dev(dev_name,NULL); | |
1025 | } | |
1026 | ||
1027 | // global variable holding byte count of allocated memory | |
1028 | extern long long bytes; | |
1029 | ||
1030 | // we are going to take advantage of the fact that FreeBSD's devfs will only | |
1031 | // have device entries for devices that exist. So if we get the equivilent of | |
1032 | // ls /dev/ad?, we have all the ATA devices on the system | |
1033 | // | |
1034 | // If any errors occur, leave errno set as it was returned by the | |
1035 | // system call, and return <0. | |
1036 | ||
1037 | // Return values: | |
1038 | // -1 out of memory | |
1039 | // -2 to -5 errors in glob | |
1040 | ||
1041 | int get_dev_names(char*** names, const char* prefix) { | |
1042 | int n = 0; | |
1043 | char** mp; | |
1044 | int retglob,lim; | |
1045 | glob_t globbuf; | |
1046 | int i; | |
1047 | char pattern1[128],pattern2[128]; | |
1048 | ||
1049 | bzero(&globbuf,sizeof(globbuf)); | |
1050 | // in case of non-clean exit | |
1051 | *names=NULL; | |
1052 | ||
1053 | // handle 0-99 possible devices, will still be limited by MAX_NUM_DEV | |
1054 | sprintf(pattern1,"/dev/%s[0-9]",prefix); | |
1055 | sprintf(pattern2,"/dev/%s[0-9][0-9]",prefix); | |
1056 | ||
1057 | // Use glob to look for any directory entries matching the patterns | |
1058 | // first call inits with first pattern match, second call appends | |
a37e7145 GG |
1059 | // to first list. GLOB_NOCHECK results in no error if no more matches |
1060 | // found, however it does append the actual pattern to the list of | |
1061 | // paths.... | |
1062 | if ((retglob=glob(pattern1, GLOB_ERR|GLOB_NOCHECK, NULL, &globbuf)) || | |
832b75ed GG |
1063 | (retglob=glob(pattern2, GLOB_ERR|GLOB_APPEND|GLOB_NOCHECK,NULL,&globbuf))) { |
1064 | int retval = -1; | |
1065 | // glob failed | |
1066 | if (retglob==GLOB_NOSPACE) | |
1067 | pout("glob(3) ran out of memory matching patterns (%s),(%s)\n", | |
1068 | pattern1, pattern2); | |
1069 | else if (retglob==GLOB_ABORTED) | |
1070 | pout("glob(3) aborted matching patterns (%s),(%s)\n", | |
1071 | pattern1, pattern2); | |
1072 | else if (retglob==GLOB_NOMATCH) { | |
1073 | pout("glob(3) found no matches for patterns (%s),(%s)\n", | |
1074 | pattern1, pattern2); | |
1075 | retval = 0; | |
1076 | } | |
1077 | else if (retglob) | |
1078 | pout("Unexplained error in glob(3) of patterns (%s),(%s)\n", | |
1079 | pattern1, pattern2); | |
1080 | ||
1081 | // Free memory and return | |
1082 | globfree(&globbuf); | |
1083 | ||
1084 | return retval; | |
1085 | } | |
1086 | ||
832b75ed GG |
1087 | // did we find too many paths? |
1088 | lim = globbuf.gl_pathc < MAX_NUM_DEV ? globbuf.gl_pathc : MAX_NUM_DEV; | |
1089 | if (lim < globbuf.gl_pathc) | |
1090 | pout("glob(3) found %d > MAX=%d devices matching patterns (%s),(%s): ignoring %d paths\n", | |
1091 | globbuf.gl_pathc, MAX_NUM_DEV, pattern1,pattern2, | |
1092 | globbuf.gl_pathc-MAX_NUM_DEV); | |
1093 | ||
1094 | // allocate space for up to lim number of ATA devices | |
1095 | if (!(mp = (char **)calloc(lim, sizeof(char*)))){ | |
1096 | pout("Out of memory constructing scan device list\n"); | |
1097 | return -1; | |
1098 | } | |
1099 | ||
1100 | // now step through the list returned by glob. No link checking needed | |
1101 | // in FreeBSD | |
1102 | for (i=0; i<globbuf.gl_pathc; i++){ | |
a37e7145 | 1103 | // because of the NO_CHECK in calls to glob, |
832b75ed GG |
1104 | // the pattern itself will be added to path list.. |
1105 | // so ignore any paths that have the ']' from pattern | |
1106 | if (strchr(globbuf.gl_pathv[i],']') == NULL) | |
1107 | mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); | |
1108 | } | |
1109 | ||
1110 | globfree(&globbuf); | |
4d59bff9 | 1111 | mp = (char **)realloc(mp,n*(sizeof(char*))); // shrink to correct size |
832b75ed GG |
1112 | bytes += (n)*(sizeof(char*)); // and set allocated byte count |
1113 | *names=mp; | |
1114 | return n; | |
1115 | } | |
1116 | ||
1117 | int make_device_names (char*** devlist, const char* name) { | |
1118 | if (!strcmp(name,"SCSI")) | |
1119 | return get_dev_names(devlist,"da"); | |
1120 | else if (!strcmp(name,"ATA")) | |
1121 | return get_dev_names(devlist,"ad"); | |
1122 | else | |
1123 | return 0; | |
1124 | } |