📄 os_freebsd.cpp
字号:
request.u.ata.count=select; request.flags=ATA_CMD_CONTROL; break; case IMMEDIATE_OFFLINE: request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE; request.u.ata.lba = select|(0xc24f<<8); // put test in sector request.flags=ATA_CMD_CONTROL; break; case STATUS_CHECK: // same command, no HDIO in FreeBSD case STATUS: // this command only says if SMART is working. It could be // replaced with STATUS_CHECK below. request.u.ata.feature=ATA_SMART_STATUS; request.u.ata.lba=0xc24f<<8; request.flags=ATA_CMD_CONTROL; break; default: pout("Unrecognized command %d in ata_command_interface()\n" "Please contact " PACKAGE_BUGREPORT "\n", command); errno=ENOSYS; return -1; } if (command==STATUS_CHECK){ unsigned const char normal_lo=0x4f, normal_hi=0xc2; unsigned const char failed_lo=0xf4, failed_hi=0x2c; unsigned char low,high; #ifdef IOCATAREQUEST if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error)#else if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)#endif return -1;#if __FreeBSD_version < 502000 printwarning(NO_RETURN,NULL);#endif high = (request.u.ata.lba >> 16) & 0xff; low = (request.u.ata.lba >> 8) & 0xff; // Cyl low and Cyl high unchanged means "Good SMART status" if (low==normal_lo && high==normal_hi) return 0; // These values mean "Bad SMART status" if (low==failed_lo && high==failed_hi) return 1; // We haven't gotten output that makes sense; print out some debugging info char buf[512]; sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", (int)request.u.ata.command, (int)request.u.ata.feature, (int)request.u.ata.count, (int)((request.u.ata.lba) & 0xff), (int)((request.u.ata.lba>>8) & 0xff), (int)((request.u.ata.lba>>16) & 0xff), (int)request.error); printwarning(BAD_SMART,buf); return 0; }#ifdef IOCATAREQUEST if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error)#else if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)#endif { return -1; } // if (copydata) memcpy(data, buff, 512); return 0;#endif}// Interface to SCSI devices. See os_linux.cint do_normal_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report){ struct freebsd_dev_channel* con = NULL; struct cam_device* cam_dev = NULL; union ccb *ccb; if (report > 0) { unsigned int k; const unsigned char * ucp = iop->cmnd; const char * np; np = scsi_get_opcode_name(ucp[0]); pout(" [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < iop->cmnd_len; ++k) pout("%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; pout("]\n Outgoing data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } else pout("]"); } // check that "file descriptor" is valid if (isnotopen(&fd,&con)) return -ENOTTY; if (!(cam_dev = cam_open_spec_device(con->devname,con->unitnum,O_RDWR,NULL))) { warnx("%s",cam_errbuf); return -1; } if (!(ccb = cam_getccb(cam_dev))) { warnx("error allocating ccb"); return -ENOMEM; } // clear out structure, except for header that was filled in for us bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); cam_fill_csio(&ccb->csio, /*retrires*/ 1, /*cbfcnp*/ NULL, /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)), /* tagaction */ MSG_SIMPLE_Q_TAG, /* dataptr */ iop->dxferp, /* datalen */ iop->dxfer_len, /* senselen */ iop->max_sense_len, /* cdblen */ iop->cmnd_len, /* timout (converted to seconds) */ iop->timeout*1000); memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len); if (cam_send_ccb(cam_dev,ccb) < 0) { warn("error sending SCSI ccb"); #if __FreeBSD_version > 500000 cam_error_print(cam_dev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); #endif cam_freeccb(ccb); return -1; } if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { #if __FreeBSD_version > 500000 cam_error_print(cam_dev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); #endif cam_freeccb(ccb); return -1; } if (iop->sensep) { memcpy(iop->sensep,&(ccb->csio.sense_data),sizeof(struct scsi_sense_data)); iop->resp_sense_len = sizeof(struct scsi_sense_data); } iop->scsi_status = ccb->csio.scsi_status; cam_freeccb(ccb); if (cam_dev) cam_close_device(cam_dev); if (report > 0) { int trunc; pout(" status=0\n"); trunc = (iop->dxfer_len > 256) ? 1 : 0; pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } return 0;}/* Check and call the right interface. Maybe when the do_generic_scsi_cmd_io interface is better we can take off this crude way of calling the right interface */int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report){struct freebsd_dev_channel *fdchan; switch(con->controller_type) { case CONTROLLER_CCISS: // check that "file descriptor" is valid if (isnotopen(&dev_fd,&fdchan)) return -ENOTTY;#ifdef HAVE_DEV_CISS_CISSIO_H return cciss_io_interface(fdchan->device, con->controller_port-1, iop, report);#else { static int warned = 0; if (!warned) { pout("CCISS support is not available in this build of smartmontools,\n" "/usr/src/sys/dev/ciss/cissio.h was not available at build time.\n\n"); warned = 1; } } errno = ENOSYS; return -1;#endif // not reached break; default: return do_normal_scsi_cmnd_io(dev_fd, iop, report); // not reached break; }}// Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c#define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520#define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048#define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) { // to hold true file descriptor struct freebsd_dev_channel* con; // return value and buffer for ioctl() int ioctlreturn, readdata=0; struct twe_usercommand* cmd_twe = NULL; TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL; TWE_Command_ATA* ata = NULL; // Used by both the SCSI and char interfaces char ioctl_buffer[TW_IOCTL_BUFFER_SIZE]; if (disknum < 0) { printwarning(NO_DISK_3WARE,NULL); return -1; } // check that "file descriptor" is valid if (isnotopen(&fd,&con)) return -1; memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE); if (escalade_type==CONTROLLER_3WARE_9000_CHAR) { cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer; cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf; cmd_twa->driver_pkt.buffer_length = 512; ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k; } else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) { cmd_twe = (struct twe_usercommand*)ioctl_buffer; ata = &cmd_twe->tu_command.ata; } else { pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n" "Please contact " PACKAGE_BUGREPORT "\n", escalade_type, disknum); errno=ENOSYS; return -1; } ata->opcode = TWE_OP_ATA_PASSTHROUGH; // Same for (almost) all commands - but some reset below ata->request_id = 0xFF; ata->unit = disknum; ata->status = 0; ata->flags = 0x1; ata->drive_head = 0x0; ata->sector_num = 0; // All SMART commands use this CL/CH signature. These are magic // values from the ATA specifications. ata->cylinder_lo = 0x4F; ata->cylinder_hi = 0xC2; // SMART ATA COMMAND REGISTER value ata->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; if (escalade_type==CONTROLLER_3WARE_678K_CHAR) { cmd_twe->tu_data = data; cmd_twe->tu_size = 512; } ata->sgl_offset = 0x5; ata->size = 0x5; ata->param = 0xD; ata->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 (sizeof(long)==8) // ata->size++; } else { // Non data command -- but doesn't use large sector // count register values. ata->sgl_offset = 0x0; ata->size = 0x5; ata->param = 0x8; ata->sector_count = 0x0; } // Now set ATA registers depending upon command switch (command){ case CHECK_POWER_MODE: ata->command = ATA_CHECK_POWER_MODE; ata->features = 0; ata->cylinder_lo = 0; ata->cylinder_hi = 0; break; case READ_VALUES: ata->features = ATA_SMART_READ_VALUES; break; case READ_THRESHOLDS: ata->features = ATA_SMART_READ_THRESHOLDS; break; case READ_LOG: ata->features = ATA_SMART_READ_LOG_SECTOR; // log number to return ata->sector_num = select; break; case WRITE_LOG: readdata=0; ata->features = ATA_SMART_WRITE_LOG_SECTOR; ata->sector_count = 1; ata->sector_num = select; ata->param = 0xF; // PIO data write break; case IDENTIFY: // ATA IDENTIFY DEVICE ata->command = ATA_IDENTIFY_DEVICE; ata->features = 0; ata->cylinder_lo = 0; ata->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); errno=ENODEV; return -1; case ENABLE: ata->features = ATA_SMART_ENABLE; break; case DISABLE: ata->features = ATA_SMART_DISABLE; break; case AUTO_OFFLINE: ata->features = ATA_SMART_AUTO_OFFLINE; // Enable or disable? ata->sector_count = select; break; case AUTOSAVE: ata->features = ATA_SMART_AUTOSAVE; // Enable or disable? ata->sector_count = select; break; case IMMEDIATE_OFFLINE: ata->features = ATA_SMART_IMMEDIATE_OFFLINE; // What test type to run? ata->sector_num = select; break; case STATUS_CHECK:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -