📄 os_linux.cpp
字号:
tw_ioctl->opcode = TW_ATA_PASSTHRU; tw_ioctl->input_length = 512; // correct even for non-data commands tw_ioctl->output_length = 512; // correct even for non-data commands tw_output = (TW_Output *)tw_ioctl; passthru = (TW_Passthru *)&(tw_ioctl->input_data); } else { pout("Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n" "Please contact " PACKAGE_BUGREPORT "\n", escalade_type, disknum); errno=ENOSYS; return -1; } // Same for (almost) all commands - but some reset below passthru->byte0.opcode = TW_OP_ATA_PASSTHRU; passthru->request_id = 0xFF; passthru->unit = disknum; passthru->status = 0; passthru->flags = 0x1; passthru->drive_head = 0x0; passthru->sector_num = 0; // All SMART commands use this CL/CH signature. These are magic // values from the ATA specifications. passthru->cylinder_lo = 0x4F; passthru->cylinder_hi = 0xC2; // SMART ATA COMMAND REGISTER value passthru->command = ATA_SMART_CMD; // Is this a command that reads or returns 512 bytes? // passthru->param values are: // 0x0 - non data command without TFR write check, // 0x8 - non data command with TFR write check, // 0xD - data command that returns data to host from device // 0xF - data command that writes data from host to device // passthru->size values are 0x5 for non-data and 0x07 for data if (command == READ_VALUES || command == READ_THRESHOLDS || command == READ_LOG || command == IDENTIFY || command == WRITE_LOG ) { readdata=1; passthru->byte0.sgloff = 0x5; passthru->size = 0x7; passthru->param = 0xD; passthru->sector_count = 0x1; // For 64-bit to work correctly, up the size of the command packet // in dwords by 1 to account for the 64-bit single sgl 'address' // field. Note that this doesn't agree with the typedefs but it's // right (agree with kernel driver behavior/typedefs). if (escalade_type==CONTROLLER_3WARE_9000_CHAR && sizeof(long)==8) passthru->size++; } else { // Non data command -- but doesn't use large sector // count register values. passthru->byte0.sgloff = 0x0; passthru->size = 0x5; passthru->param = 0x8; passthru->sector_count = 0x0; } // Now set ATA registers depending upon command switch (command){ case CHECK_POWER_MODE: passthru->command = ATA_CHECK_POWER_MODE; passthru->features = 0; passthru->cylinder_lo = 0; passthru->cylinder_hi = 0; break; case READ_VALUES: passthru->features = ATA_SMART_READ_VALUES; break; case READ_THRESHOLDS: passthru->features = ATA_SMART_READ_THRESHOLDS; break; case READ_LOG: passthru->features = ATA_SMART_READ_LOG_SECTOR; // log number to return passthru->sector_num = select; break; case WRITE_LOG: if (escalade_type == CONTROLLER_3WARE_9000_CHAR) memcpy((unsigned char *)tw_ioctl_apache->data_buffer, data, 512); else if (escalade_type == CONTROLLER_3WARE_678K_CHAR) memcpy((unsigned char *)tw_ioctl_char->data_buffer, data, 512); else { // COMMAND NOT SUPPORTED VIA SCSI IOCTL INTERFACE // memcpy(tw_output->output_data, data, 512); printwarning(command); errno=ENOTSUP; return -1; } readdata=0; passthru->features = ATA_SMART_WRITE_LOG_SECTOR; passthru->sector_count = 1; passthru->sector_num = select; passthru->param = 0xF; // PIO data write break; case IDENTIFY: // ATA IDENTIFY DEVICE passthru->command = ATA_IDENTIFY_DEVICE; passthru->features = 0; passthru->cylinder_lo = 0; passthru->cylinder_hi = 0; break; case PIDENTIFY: // 3WARE controller can NOT have packet device internally pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", disknum); pout("Note: /dev/sdX many need to be replaced with /dev/tweN or /dev/twaN\n"); errno=ENODEV; return -1; case ENABLE: passthru->features = ATA_SMART_ENABLE; break; case DISABLE: passthru->features = ATA_SMART_DISABLE; break; case AUTO_OFFLINE: passthru->features = ATA_SMART_AUTO_OFFLINE; // Enable or disable? passthru->sector_count = select; break; case AUTOSAVE: passthru->features = ATA_SMART_AUTOSAVE; // Enable or disable? passthru->sector_count = select; break; case IMMEDIATE_OFFLINE: passthru->features = ATA_SMART_IMMEDIATE_OFFLINE; // What test type to run? passthru->sector_num = select; break; case STATUS_CHECK: passthru->features = ATA_SMART_STATUS; break; case STATUS: // This is JUST to see if SMART is enabled, by giving SMART status // command. But it doesn't say if status was good, or failing. // See below for the difference. passthru->features = ATA_SMART_STATUS; break; default: pout("Unrecognized command %d in linux_3ware_command_interface(disk %d)\n" "Please contact " PACKAGE_BUGREPORT "\n", command, disknum); errno=ENOSYS; return -1; } // Now send the command down through an ioctl() if (escalade_type==CONTROLLER_3WARE_9000_CHAR) ioctlreturn=ioctl(fd, TW_IOCTL_FIRMWARE_PASS_THROUGH, tw_ioctl_apache); else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) ioctlreturn=ioctl(fd, TW_CMD_PACKET_WITH_DATA, tw_ioctl_char); else ioctlreturn=ioctl(fd, SCSI_IOCTL_SEND_COMMAND, tw_ioctl); // Deal with the different error cases if (ioctlreturn) { if (CONTROLLER_3WARE_678K==escalade_type && ((command==AUTO_OFFLINE || command==AUTOSAVE) && select)){ // error here is probably a kernel driver whose version is too old printwarning(command); errno=ENOTSUP; } if (!errno) errno=EIO; return -1; } // The passthru structure is valid after return from an ioctl if: // - we are using the character interface OR // - we are using the SCSI interface and this is a NON-READ-DATA command // For SCSI interface, note that we set passthru to a different // value after ioctl(). if (CONTROLLER_3WARE_678K==escalade_type) { if (readdata) passthru=NULL; else passthru=(TW_Passthru *)&(tw_output->output_data); } // See if the ATA command failed. Now that we have returned from // the ioctl() call, if passthru is valid, then: // - passthru->status contains the 3ware controller STATUS // - passthru->command contains the ATA STATUS register // - passthru->features contains the ATA ERROR register // // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS // If bit 0 (error bit) is set, then ATA ERROR register is valid. // While we *might* decode the ATA ERROR register, at the moment it // doesn't make much sense: we don't care in detail why the error // happened. if (passthru && (passthru->status || (passthru->command & 0x21))) { errno=EIO; return -1; } // If this is a read data command, copy data to output buffer if (readdata) { if (escalade_type==CONTROLLER_3WARE_9000_CHAR) memcpy(data, (unsigned char *)tw_ioctl_apache->data_buffer, 512); else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) memcpy(data, (unsigned char *)tw_ioctl_char->data_buffer, 512); else memcpy(data, tw_output->output_data, 512); } // For STATUS_CHECK, we need to check register values if (command==STATUS_CHECK) { // To find out if the SMART RETURN STATUS is good or failing, we // need to examine the values of the Cylinder Low and Cylinder // High Registers. unsigned short cyl_lo=passthru->cylinder_lo; unsigned short cyl_hi=passthru->cylinder_hi; // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good. if (cyl_lo==0x4F && cyl_hi==0xC2) return 0; // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL if (cyl_lo==0xF4 && cyl_hi==0x2C) return 1; // Any other values mean that something has gone wrong with the command if (CONTROLLER_3WARE_678K==escalade_type) { printwarning(command); errno=ENOSYS; return 0; } else { errno=EIO; return -1; } } // copy sector count register (one byte!) to return data if (command==CHECK_POWER_MODE) *data=*(char *)&(passthru->sector_count); // look for nonexistent devices/ports if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) { errno=ENODEV; return -1; } return 0;}int marvell_command_interface(int device, smart_command_set command, int select, char *data) { typedef struct { int inlen; int outlen; char cmd[540]; } mvsata_scsi_cmd; int copydata = 0; mvsata_scsi_cmd smart_command; unsigned char *buff = (unsigned char *)&smart_command.cmd[6]; // See struct hd_drive_cmd_hdr in hdreg.h // buff[0]: ATA COMMAND CODE REGISTER // buff[1]: ATA SECTOR NUMBER REGISTER // buff[2]: ATA FEATURES REGISTER // buff[3]: ATA SECTOR COUNT REGISTER // clear out buff. Large enough for HDIO_DRIVE_CMD (4+512 bytes) memset(&smart_command, 0, sizeof(smart_command)); smart_command.inlen = 540; smart_command.outlen = 540; smart_command.cmd[0] = 0xC; //Vendor-specific code smart_command.cmd[4] = 6; //command length buff[0] = ATA_SMART_CMD; switch (command){ case CHECK_POWER_MODE: buff[0]=ATA_CHECK_POWER_MODE; break; case READ_VALUES: buff[2]=ATA_SMART_READ_VALUES; copydata=buff[3]=1; break; case READ_THRESHOLDS: buff[2]=ATA_SMART_READ_THRESHOLDS; copydata=buff[1]=buff[3]=1; break; case READ_LOG: buff[2]=ATA_SMART_READ_LOG_SECTOR; buff[1]=select; copydata=buff[3]=1; break; case IDENTIFY: buff[0]=ATA_IDENTIFY_DEVICE; copydata=buff[3]=1; break; case PIDENTIFY: buff[0]=ATA_IDENTIFY_PACKET_DEVICE; copydata=buff[3]=1; break; case ENABLE: buff[2]=ATA_SMART_ENABLE; buff[1]=1; break; case DISABLE: buff[2]=ATA_SMART_DISABLE; buff[1]=1; break; case STATUS: case STATUS_CHECK: // this command only says if SMART is working. It could be // replaced with STATUS_CHECK below. buff[2] = ATA_SMART_STATUS; break; case AUTO_OFFLINE: buff[2]=ATA_SMART_AUTO_OFFLINE; buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!! break; case AUTOSAVE: buff[2]=ATA_SMART_AUTOSAVE; buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!! break; case IMMEDIATE_OFFLINE: buff[2]=ATA_SMART_IMMEDIATE_OFFLINE; buff[1]=select; break; default: pout("Unrecognized command %d in mvsata_os_specific_handler()\n", command); exit(1); break; } // There are two different types of ioctls(). The HDIO_DRIVE_TASK // one is this: // We are now doing the HDIO_DRIVE_CMD type ioctl. if (ioctl(device, SCSI_IOCTL_SEND_COMMAND, (void *)&smart_command)) return -1; if (command==CHECK_POWER_MODE) { // LEON -- CHECK THIS PLEASE. THIS SHOULD BE THE SECTOR COUNT // REGISTER, AND IT MIGHT BE buff[2] NOT buff[3]. Bruce data[0]=buff[3]; return 0; } // Always succeed on a SMART status, as a disk that failed returned // buff[4]=0xF4, buff[5]=0x2C, i.e. "Bad SMART status" (see below). if (command == STATUS) return 0; //Data returned is starting from 0 offset if (command == STATUS_CHECK) { // Cyl low and Cyl high unchanged means "Good SMART status" if (buff[4] == 0x4F && buff[5] == 0xC2) return 0; // These values mean "Bad SMART status" if (buff[4] == 0xF4 && buff[5] == 0x2C)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -