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