]>
Commit | Line | Data |
---|---|---|
a23d5117 GI |
1 | |
2 | ||
3 | // This is needed for the various HAVE_* macros and PROJECT_* macros. | |
4 | #include "config.h" | |
5 | ||
6 | // These are needed to define prototypes and structures for the | |
7 | // functions defined below | |
8 | #include "int64.h" | |
9 | #include "atacmds.h" | |
10 | #include "scsicmds.h" | |
11 | #include "utility.h" | |
12 | ||
13 | // This is to include whatever structures and prototypes you define in | |
14 | // os_generic.h | |
15 | #include "os_qnxnto.h" | |
16 | ||
17 | // Needed by '-V' option (CVS versioning) of smartd/smartctl. You | |
18 | // should have one *_H_CVSID macro appearing below for each file | |
19 | // appearing with #include "*.h" above. Please list these (below) in | |
20 | // alphabetic/dictionary order. | |
21 | const char *os_XXXX_c_cvsid="$Id: os_qnxnto.cpp,v 1.3 2008/06/12 21:46:31 ballen4705 Exp $" \ | |
22 | ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_QNXNTO_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; | |
23 | ||
24 | ||
25 | // This is here to prevent compiler warnings for unused arguments of | |
26 | // functions. | |
27 | #define ARGUSED(x) ((void)(x)) | |
28 | ||
29 | // Please eliminate the following block: both the #include and | |
30 | // the 'unsupported()' function. They are only here to warn | |
31 | // unsuspecting users that their Operating System is not supported! If | |
32 | // you wish, you can use a similar warning mechanism for any of the | |
33 | // functions in this file that you can not (or choose not to) | |
34 | // implement. | |
35 | ||
36 | ||
37 | #ifdef HAVE_UNAME | |
38 | #include <sys/utsname.h> | |
39 | #endif | |
40 | //---------------------------------------------------------------------------------------------- | |
41 | // private Functions | |
42 | static int ata_sense_data(void *sdata,int *error,int *key,int *asc,int *ascq); | |
43 | static int ata_interpret_sense(struct cam_pass_thru *cpt,void *sense,int *status,int rcount); | |
44 | static int ata_pass_thru(int fd,struct cam_pass_thru *pcpt); | |
45 | //---------------------------------------------------------------------------------------------- | |
46 | static void unsupported(){ | |
47 | static int warninggiven; | |
48 | ||
49 | if (!warninggiven) { | |
50 | char *osname; | |
51 | extern unsigned char debugmode; | |
52 | unsigned char savedebugmode=debugmode; | |
53 | ||
54 | #ifdef HAVE_UNAME | |
55 | struct utsname ostype; | |
56 | uname(&ostype); | |
57 | osname=ostype.sysname; | |
58 | #else | |
59 | osname="host's"; | |
60 | #endif | |
61 | ||
62 | debugmode=1; | |
63 | pout("\n" | |
64 | "############################################################################\n" | |
65 | "WARNING: smartmontools has not been ported to the %s Operating System.\n" | |
66 | "Please see the files os_generic.cpp and os_generic.h for porting instructions.\n" | |
67 | "############################################################################\n\n", | |
68 | osname); | |
69 | debugmode=savedebugmode; | |
70 | warninggiven=1; | |
71 | } | |
72 | ||
73 | return; | |
74 | } | |
75 | // End of the 'unsupported()' block that you should eliminate. | |
76 | ||
77 | ||
78 | // print examples for smartctl. You should modify this function so | |
79 | // that the device paths are sensible for your OS, and to eliminate | |
80 | // unsupported commands (eg, 3ware controllers). | |
81 | void print_smartctl_examples(){ | |
82 | printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); | |
83 | #ifdef HAVE_GETOPT_LONG | |
84 | printf( | |
85 | " smartctl -a /dev/hd0 (Prints all SMART information)\n\n" | |
86 | " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hd0\n" | |
87 | " (Enables SMART on first disk)\n\n" | |
88 | " smartctl -t long /dev/hd0 (Executes extended disk self-test)\n\n" | |
89 | " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hd0\n" | |
90 | " (Prints Self-Test & Attribute errors)\n" | |
91 | " smartctl -a --device=3ware,2 /dev/sda\n" | |
92 | " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" | |
93 | ); | |
94 | #else | |
95 | printf( | |
96 | " smartctl -a /dev/hd0 (Prints all SMART information)\n" | |
97 | " smartctl -s on -o on -S on /dev/hd0 (Enables SMART on first disk)\n" | |
98 | " smartctl -t long /dev/hd0 (Executes extended disk self-test)\n" | |
99 | " smartctl -A -l selftest -q errorsonly /dev/hd0\n" | |
100 | " (Prints Self-Test & Attribute errors)\n" | |
101 | " smartctl -a -d 3ware,2 /dev/sda\n" | |
102 | " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" | |
103 | ); | |
104 | #endif | |
105 | return; | |
106 | } | |
107 | ||
108 | // tries to guess device type given the name (a path). See utility.h | |
109 | // for return values. | |
110 | static const char *net_dev_prefix = "/dev/"; | |
111 | static const char *net_dev_ata_disk = "hd"; | |
112 | ||
113 | int guess_device_type (const char* dev_name) | |
114 | { | |
115 | int len,dev_prefix_len; | |
116 | dev_prefix_len=strlen(net_dev_prefix); | |
117 | if(!dev_name||!(len=strlen(dev_name))) | |
118 | return(CONTROLLER_UNKNOWN); | |
119 | if (!strncmp(net_dev_prefix,dev_name,dev_prefix_len)) | |
120 | { | |
121 | if(len<=dev_prefix_len) | |
122 | return(CONTROLLER_UNKNOWN); | |
123 | else | |
124 | dev_name += dev_prefix_len; | |
125 | } | |
126 | if(!strncmp(net_dev_ata_disk,dev_name,strlen(net_dev_ata_disk))) | |
127 | return(CONTROLLER_ATA); | |
128 | return(CONTROLLER_UNKNOWN); | |
129 | } | |
130 | ||
131 | // makes a list of ATA or SCSI devices for the DEVICESCAN directive of | |
132 | // smartd. Returns number N of devices, or -1 if out of | |
133 | // memory. Allocates N+1 arrays: one of N pointers (devlist); the | |
134 | // other N arrays each contain null-terminated character strings. In | |
135 | // the case N==0, no arrays are allocated because the array of 0 | |
136 | // pointers has zero length, equivalent to calling malloc(0). | |
137 | int make_device_names (char*** devlist, const char* name) { | |
138 | ARGUSED(devlist); | |
139 | ARGUSED(name); | |
140 | unsupported(); | |
141 | return 0; | |
142 | } | |
143 | ||
144 | // Like open(). Return non-negative integer handle, only used by the | |
145 | // functions below. type=="ATA" or "SCSI". If you need to store | |
146 | // extra information about your devices, create a private internal | |
147 | // array within this file (see os_freebsd.cpp for an example). If you | |
148 | // can not open the device (permission denied, does not exist, etc) | |
149 | // set errno as open() does and return <0. | |
150 | int deviceopen(const char *pathname, char *type) | |
151 | { | |
152 | if(!strcmp(type, "ATA")) | |
153 | return(open(pathname,O_RDWR|O_NONBLOCK)); | |
154 | else | |
155 | return(-1); | |
156 | } | |
157 | ||
158 | // Like close(). Acts only on integer handles returned by | |
159 | // deviceopen() above. | |
160 | int deviceclose(int fd) | |
161 | { | |
162 | return(close(fd)); | |
163 | } | |
164 | //---------------------------------------------------------------------------------------------- | |
165 | // Interface to ATA devices. See os_linux.cpp for the cannonical example. | |
166 | // DETAILED DESCRIPTION OF ARGUMENTS | |
167 | // device: is the integer handle provided by deviceopen() | |
168 | // command: defines the different operations, see atacmds.h | |
169 | // select: additional input data IF NEEDED (which log, which type of | |
170 | // self-test). | |
171 | // data: location to write output data, IF NEEDED (1 or 512 bytes). | |
172 | // Note: not all commands use all arguments. | |
173 | // RETURN VALUES (for all commands BUT command==STATUS_CHECK) | |
174 | // -1 if the command failed | |
175 | // 0 if the command succeeded, | |
176 | // RETURN VALUES if command==STATUS_CHECK | |
177 | // -1 if the command failed OR the disk SMART status can't be determined | |
178 | // 0 if the command succeeded and disk SMART status is "OK" | |
179 | // 1 if the command succeeded and disk SMART status is "FAILING" | |
180 | int ata_command_interface(int fd,smart_command_set command,int select,char *data) | |
181 | { | |
182 | struct cam_pass_thru cpt; | |
183 | ATA_SENSE sense; | |
184 | CDB *cdb; | |
185 | int status,rc; | |
186 | memset(&cpt,0x00,sizeof(struct cam_pass_thru)); | |
187 | cdb=(CDB *)cpt.cam_cdb; | |
188 | rc=-1; | |
189 | switch(command) | |
190 | { | |
191 | case READ_VALUES: | |
192 | cpt.cam_flags = CAM_DIR_IN; | |
193 | cpt.cam_cdb_len = 16; | |
194 | cpt.cam_dxfer_len = 512; | |
195 | cpt.cam_data_ptr = (uint32_t)data; | |
196 | cpt.cam_sense_len = sizeof(sense); | |
197 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
198 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
199 | cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; | |
200 | cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; | |
201 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
202 | cdb->ata_pass_thru.features = ATA_SMART_READ_VALUES; | |
203 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
204 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
205 | break; | |
206 | case READ_THRESHOLDS: | |
207 | cpt.cam_flags = CAM_DIR_IN; | |
208 | cpt.cam_cdb_len = 16; | |
209 | cpt.cam_dxfer_len = 512; | |
210 | cpt.cam_data_ptr = (uint32_t)data; | |
211 | cpt.cam_sense_len = sizeof(sense); | |
212 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
213 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
214 | cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; | |
215 | cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; | |
216 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
217 | cdb->ata_pass_thru.features = ATA_SMART_READ_THRESHOLDS; | |
218 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
219 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
220 | break; | |
221 | case READ_LOG: | |
222 | cpt.cam_flags = CAM_DIR_IN; | |
223 | cpt.cam_cdb_len = 16; | |
224 | cpt.cam_dxfer_len = 512; | |
225 | cpt.cam_data_ptr = (uint32_t)data; | |
226 | cpt.cam_sense_len = sizeof(sense); | |
227 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
228 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
229 | cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; | |
230 | cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; | |
231 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
232 | cdb->ata_pass_thru.features = ATA_SMART_READ_LOG_SECTOR; | |
233 | cdb->ata_pass_thru.sector_count= 1; | |
234 | cdb->ata_pass_thru.lba_low = select; | |
235 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
236 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
237 | break; | |
238 | case WRITE_LOG: | |
239 | return(-1); | |
240 | break; | |
241 | case IDENTIFY: | |
242 | cpt.cam_flags = CAM_DIR_IN; | |
243 | cpt.cam_cdb_len = 16; | |
244 | cpt.cam_dxfer_len = 512; | |
245 | cpt.cam_data_ptr = (uint32_t)data; | |
246 | cpt.cam_sense_len = sizeof(sense); | |
247 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
248 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
249 | cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; | |
250 | cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; | |
251 | cdb->ata_pass_thru.command = ATA_IDENTIFY_DEVICE; | |
252 | break; | |
253 | case PIDENTIFY: | |
254 | cpt.cam_flags = CAM_DIR_IN; | |
255 | cpt.cam_cdb_len = 16; | |
256 | cpt.cam_dxfer_len = 512; | |
257 | cpt.cam_data_ptr = (uint32_t)data; | |
258 | cpt.cam_sense_len = sizeof(sense); | |
259 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
260 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
261 | cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; | |
262 | cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; | |
263 | cdb->ata_pass_thru.command = ATA_IDENTIFY_PACKET_DEVICE; | |
264 | break; | |
265 | case ENABLE: | |
266 | cpt.cam_flags = CAM_DIR_NONE; | |
267 | cpt.cam_cdb_len = 16; | |
268 | cpt.cam_sense_len = sizeof(sense); | |
269 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
270 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
271 | cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; | |
272 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
273 | cdb->ata_pass_thru.features = ATA_SMART_ENABLE; | |
274 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
275 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
276 | break; | |
277 | case DISABLE: | |
278 | cpt.cam_flags = CAM_DIR_NONE; | |
279 | cpt.cam_cdb_len = 16; | |
280 | cpt.cam_sense_len = sizeof(sense); | |
281 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
282 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
283 | cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; | |
284 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
285 | cdb->ata_pass_thru.features = ATA_SMART_DISABLE; | |
286 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
287 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
288 | break; | |
289 | case AUTO_OFFLINE: | |
290 | // NOTE: According to ATAPI 4 and UP, this command is obsolete | |
291 | cpt.cam_flags = CAM_DIR_NONE; | |
292 | cpt.cam_cdb_len = 16; | |
293 | cpt.cam_sense_len = sizeof(sense); | |
294 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
295 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
296 | cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; | |
297 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
298 | cdb->ata_pass_thru.features = ATA_SMART_AUTO_OFFLINE; | |
299 | cdb->ata_pass_thru.lba_low = select; | |
300 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
301 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
302 | break; | |
303 | case AUTOSAVE: | |
304 | cpt.cam_flags = CAM_DIR_NONE; | |
305 | cpt.cam_cdb_len = 16; | |
306 | cpt.cam_sense_len = sizeof(sense); | |
307 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
308 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
309 | cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; | |
310 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
311 | cdb->ata_pass_thru.features = ATA_SMART_AUTOSAVE; | |
312 | cdb->ata_pass_thru.sector_count= select; | |
313 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
314 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
315 | break; | |
316 | case IMMEDIATE_OFFLINE: | |
317 | // NOTE: According to ATAPI 4 and UP, this command is obsolete | |
318 | cpt.cam_flags = CAM_DIR_NONE; | |
319 | cpt.cam_cdb_len = 16; | |
320 | cpt.cam_sense_len = sizeof(sense); | |
321 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
322 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
323 | cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; | |
324 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
325 | cdb->ata_pass_thru.features = ATA_SMART_IMMEDIATE_OFFLINE; | |
326 | cdb->ata_pass_thru.lba_low = select; | |
327 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
328 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
329 | break; | |
330 | case STATUS_CHECK: | |
331 | // same command, no HDIO in NetBSD | |
332 | case STATUS: | |
333 | cpt.cam_flags = CAM_DIR_NONE; | |
334 | cpt.cam_cdb_len = 16; | |
335 | cpt.cam_sense_len = sizeof(sense); | |
336 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
337 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
338 | cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; | |
339 | cdb->ata_pass_thru.flags = ATA_FLG_CK_COND; | |
340 | cdb->ata_pass_thru.command = ATA_SMART_CMD; | |
341 | cdb->ata_pass_thru.features = ATA_SMART_STATUS; | |
342 | cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; | |
343 | cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; | |
344 | break; | |
345 | case CHECK_POWER_MODE: | |
346 | cpt.cam_flags = CAM_DIR_NONE; | |
347 | cpt.cam_cdb_len = 16; | |
348 | cpt.cam_sense_len = sizeof(sense); | |
349 | cpt.cam_sense_ptr = (uint32_t)&sense; | |
350 | cdb->ata_pass_thru.opcode = SC_ATA_PT16; | |
351 | cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; | |
352 | cdb->ata_pass_thru.flags = ATA_FLG_CK_COND; | |
353 | cdb->ata_pass_thru.command = ATA_CHECK_POWER_MODE; | |
354 | break; | |
355 | default: | |
356 | pout("Unrecognized command %d in ata_command_interface()\n", command); | |
357 | errno=ENOSYS; | |
358 | return(-1); | |
359 | } | |
360 | // execute now | |
361 | if((status=ata_pass_thru(fd,&cpt))==EOK) | |
362 | { | |
363 | rc=status==EOK?0:-1; | |
364 | if(cpt.cam_status!=CAM_REQ_CMP) | |
365 | { | |
366 | ata_interpret_sense(&cpt,&sense,&status,0); | |
367 | if(command==STATUS||command==STATUS_CHECK) | |
368 | rc=((sense.desc.lba_high<<8)|sense.desc.lba_mid)==ATA_SMART_SIG?0:1; | |
369 | } | |
370 | } | |
371 | if(command==CHECK_POWER_MODE) | |
372 | data[0]=cdb->ata_pass_thru.sector_count; | |
373 | // finish | |
374 | return(rc); | |
375 | } | |
376 | //---------------------------------------------------------------------------------------------- | |
377 | int marvell_command_interface(int fd, smart_command_set command, int select, char *data) | |
378 | { | |
379 | ARGUSED(fd); | |
380 | ARGUSED(command); | |
381 | ARGUSED(select); | |
382 | ARGUSED(data); | |
383 | unsupported(); | |
384 | return -1; | |
385 | } | |
386 | //---------------------------------------------------------------------------------------------- | |
387 | int highpoint_command_interface(int fd, smart_command_set command, int select, char *data) | |
388 | { | |
389 | ARGUSED(fd); | |
390 | ARGUSED(command); | |
391 | ARGUSED(select); | |
392 | ARGUSED(data); | |
393 | unsupported(); | |
394 | return -1; | |
395 | } | |
396 | //---------------------------------------------------------------------------------------------- | |
397 | // Interface to ATA devices behind 3ware escalade/apache RAID | |
398 | // controller cards. Same description as ata_command_interface() | |
399 | // above except that 0 <= disknum <= 15 specifies the ATA disk | |
400 | // attached to the controller, and controller_type specifies the | |
401 | // precise type of 3ware controller. See os_linux.c | |
402 | int escalade_command_interface(int fd,int disknum,int controller_type,smart_command_set command,int select,char *data) | |
403 | { | |
404 | ARGUSED(fd); | |
405 | ARGUSED(disknum); | |
406 | ARGUSED(controller_type); | |
407 | ARGUSED(command); | |
408 | ARGUSED(select); | |
409 | ARGUSED(data); | |
410 | ||
411 | unsupported(); | |
412 | return -1; | |
413 | } | |
414 | ||
415 | int areca_command_interface(int fd,int disknum,smart_command_set command,int select,char *data) | |
416 | { | |
417 | ARGUSED(fd); | |
418 | ARGUSED(disknum); | |
419 | ARGUSED(command); | |
420 | ARGUSED(select); | |
421 | ARGUSED(data); | |
422 | ||
423 | unsupported(); | |
424 | return -1; | |
425 | } | |
426 | //---------------------------------------------------------------------------------------------- | |
427 | #include <errno.h> | |
428 | // Interface to SCSI devices. See os_linux.c | |
429 | int do_scsi_cmnd_io(int fd,struct scsi_cmnd_io * iop,int report) | |
430 | { | |
431 | ARGUSED(fd); | |
432 | ARGUSED(iop); | |
433 | ARGUSED(report); | |
434 | unsupported(); | |
435 | return -ENOSYS; | |
436 | } | |
437 | //---------------------------------------------------------------------------------------------- | |
438 | //---------------------------------------------------------------------------------------------- | |
439 | static int ata_sense_data(void *sdata,int *error,int *key,int *asc,int *ascq) | |
440 | { | |
441 | SCSI_SENSE *sf; | |
442 | SCSI_SENSE_DESCRIPTOR *sd; | |
443 | sf=(SCSI_SENSE *)sdata; | |
444 | sd=(SCSI_SENSE_DESCRIPTOR *)sdata; | |
445 | *error=sf->error; | |
446 | if(*error & SENSE_DATA_FMT_DESCRIPTOR) | |
447 | { | |
448 | *key=sd->sense & SK_MSK; | |
449 | *asc=sd->asc; | |
450 | *ascq=sd->ascq; | |
451 | } | |
452 | else | |
453 | { | |
454 | *key=sf->sense & SK_MSK; | |
455 | *asc=sf->asc; | |
456 | *ascq=sf->ascq; | |
457 | } | |
458 | return(CAM_SUCCESS); | |
459 | } | |
460 | //---------------------------------------------------------------------------------------------- | |
461 | static int ata_interpret_sense(struct cam_pass_thru *cpt,void *sense,int *status,int rcount) | |
462 | { | |
463 | int retry; | |
464 | int key; | |
465 | int asc; | |
466 | int ascq; | |
467 | int error; | |
468 | *status=EIO; | |
469 | retry=CAM_TRUE; | |
470 | if(cpt->cam_status&CAM_AUTOSNS_VALID) | |
471 | { | |
472 | ata_sense_data(sense,&error,&key,&asc,&ascq); | |
473 | switch(key) | |
474 | { | |
475 | case SK_NO_SENSE: // No sense data (no error) | |
476 | retry=CAM_FALSE; | |
477 | *status=EOK; | |
478 | break; | |
479 | case SK_RECOVERED: // Recovered error | |
480 | switch(asc) | |
481 | { | |
482 | case ASC_ATA_PASS_THRU: | |
483 | switch(ascq) | |
484 | { | |
485 | case ASCQ_ATA_PASS_THRU_INFO_AVAIL: | |
486 | break; | |
487 | default: | |
488 | break; | |
489 | } | |
490 | break; | |
491 | default: | |
492 | break; | |
493 | } | |
494 | retry=CAM_FALSE; | |
495 | *status=EOK; | |
496 | break; | |
497 | case SK_NOT_RDY: // Device not ready | |
498 | *status=EAGAIN; | |
499 | switch(asc) | |
500 | { | |
501 | case ASC_NOT_READY: | |
502 | switch(ascq) | |
503 | { | |
504 | case ASCQ_BECOMING_READY: | |
505 | case ASCQ_CAUSE_NOT_REPORTABLE: | |
506 | default: | |
507 | retry=CAM_FALSE; | |
508 | break; | |
509 | } | |
510 | break; | |
511 | case ASC_MEDIA_NOT_PRESENT: | |
512 | *status=ENXIO; | |
513 | retry=CAM_FALSE; | |
514 | break; | |
515 | } | |
516 | break; | |
517 | case SK_MEDIUM: // Medium error | |
518 | case SK_HARDWARE: // Hardware error | |
519 | retry=CAM_FALSE; | |
520 | *status=EIO; | |
521 | break; | |
522 | case SK_ILLEGAL: // Illegal Request (bad command) | |
523 | retry=CAM_FALSE; | |
524 | *status=EINVAL; | |
525 | break; | |
526 | case SK_UNIT_ATN: // Unit Attention | |
527 | switch(asc) | |
528 | { | |
529 | case ASC_MEDIUM_CHANGED: | |
530 | *status=ESTALE; | |
531 | retry=CAM_FALSE; | |
532 | break; | |
533 | case ASC_BUS_RESET: | |
534 | break; | |
535 | } | |
536 | break; | |
537 | case SK_DATA_PROT: // Data Protect | |
538 | retry=CAM_FALSE; | |
539 | *status=EROFS; | |
540 | break; | |
541 | case SK_VENDOR: // Vendor Specific | |
542 | case SK_CPY_ABORT: // Copy Aborted | |
543 | retry=CAM_FALSE; | |
544 | *status=EIO; | |
545 | break; | |
546 | case SK_CMD_ABORT: // Aborted Command | |
547 | retry=CAM_FALSE; | |
548 | *status=ECANCELED; | |
549 | break; | |
550 | case SK_EQUAL: // Equal | |
551 | case SK_VOL_OFL: // Volume Overflow | |
552 | case SK_MISCMP: // Miscompare | |
553 | case SK_RESERVED: // Reserved | |
554 | break; | |
555 | } | |
556 | if(*status==EOK) | |
557 | { | |
558 | switch(cpt->cam_status&CAM_STATUS_MASK) | |
559 | { | |
560 | case CAM_REQ_CMP_ERR: // CCB request completed with an err | |
561 | retry=CAM_FALSE; | |
562 | *status=EIO; | |
563 | break; | |
564 | case CAM_BUSY: // CAM subsystem is busy | |
565 | *status=EAGAIN; | |
566 | break; | |
567 | case CAM_REQ_INVALID: // CCB request is invalid | |
568 | case CAM_PATH_INVALID: // Path ID supplied is invalid | |
569 | case CAM_DEV_NOT_THERE: // SCSI device not installed/there | |
570 | case CAM_SEL_TIMEOUT: // Target selection timeout | |
571 | case CAM_LUN_INVALID: // LUN supplied is invalid | |
572 | case CAM_TID_INVALID: // Target ID supplied is invalid | |
573 | retry=CAM_FALSE; | |
574 | *status=ENXIO; | |
575 | break; | |
576 | case CAM_CMD_TIMEOUT: // Command timeout | |
577 | *status=rcount?EAGAIN:EIO; | |
578 | break; | |
579 | case CAM_MSG_REJECT_REC: // Message reject received | |
580 | case CAM_SCSI_BUS_RESET: // SCSI bus reset sent/received | |
581 | case CAM_UNCOR_PARITY: // Uncorrectable parity err occurred | |
582 | case CAM_AUTOSENSE_FAIL: // Autosense: Request sense cmd fail | |
583 | case CAM_NO_HBA: // No HBA detected Error | |
584 | case CAM_DATA_RUN_ERR: // Data overrun/underrun error | |
585 | retry=CAM_FALSE; | |
586 | *status=EIO; | |
587 | break; | |
588 | case CAM_UNEXP_BUSFREE: // Unexpected BUS free | |
589 | case CAM_SEQUENCE_FAIL: // Target bus phase sequence failure | |
590 | *status=EIO; | |
591 | break; | |
592 | case CAM_PROVIDE_FAIL: // Unable to provide requ. capability | |
593 | retry=CAM_FALSE; | |
594 | *status=ENOTTY; | |
595 | break; | |
596 | case CAM_CCB_LEN_ERR: // CCB length supplied is inadequate | |
597 | case CAM_BDR_SENT: // A SCSI BDR msg was sent to target | |
598 | case CAM_REQ_TERMIO: // CCB request terminated by the host | |
599 | case CAM_FUNC_NOTAVAIL: // The requ. func is not available | |
600 | case CAM_NO_NEXUS: // Nexus is not established | |
601 | case CAM_IID_INVALID: // The initiator ID is invalid | |
602 | case CAM_CDB_RECVD: // The SCSI CDB has been received | |
603 | retry=CAM_FALSE; | |
604 | *status=EIO; | |
605 | break; | |
606 | case CAM_SCSI_BUSY: // SCSI bus busy | |
607 | *status=EAGAIN; | |
608 | break; | |
609 | } | |
610 | } | |
611 | } | |
612 | return(retry); | |
613 | } | |
614 | //---------------------------------------------------------------------------------------------- | |
615 | static int ata_pass_thru(int fd,struct cam_pass_thru *pcpt) | |
616 | { | |
617 | int icnt; | |
618 | int status; | |
619 | iov_t iov[3]; | |
620 | struct cam_pass_thru cpt; | |
621 | cpt=*pcpt; | |
622 | icnt=1; | |
623 | SETIOV(&iov[0],&cpt,sizeof(cpt)); | |
624 | cpt.cam_timeout=cpt.cam_timeout?cpt.cam_timeout:CAM_TIME_DEFAULT; | |
625 | if(cpt.cam_sense_len) | |
626 | { | |
627 | SETIOV(&iov[1],cpt.cam_sense_ptr,cpt.cam_sense_len); | |
628 | cpt.cam_sense_ptr=sizeof(cpt); | |
629 | icnt++; | |
630 | } | |
631 | if(cpt.cam_dxfer_len) | |
632 | { | |
633 | SETIOV(&iov[2],(void *)cpt.cam_data_ptr,cpt.cam_dxfer_len); | |
634 | cpt.cam_data_ptr=(paddr_t)sizeof(cpt)+cpt.cam_sense_len; | |
635 | icnt++; | |
636 | } | |
637 | if((status=devctlv(fd,DCMD_CAM_PASS_THRU,icnt,icnt,iov,iov,NULL))) | |
638 | pout("ata_pass_thru devctl: %s\n",strerror(status)); | |
639 | pcpt->cam_status=cpt.cam_status; | |
640 | pcpt->cam_scsi_status=cpt.cam_scsi_status; | |
641 | return(status); | |
642 | } | |
643 | //---------------------------------------------------------------------------------------------- |