📄 os_freebsd.cpp
字号:
ata->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. ata->features = ATA_SMART_STATUS; break; default: pout("Unrecognized command %d in freebsd_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) {#ifdef IOCATAREQUEST ioctlreturn=ioctl(con->device,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);#else ioctlreturn=ioctl(con->atacommand,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);#endif } else {#ifdef IOCATAREQUEST ioctlreturn=ioctl(con->device,TWEIO_COMMAND,cmd_twe);#else ioctlreturn=ioctl(con->atacommand,TWEIO_COMMAND,cmd_twe);#endif } // Deal with the different error cases if (ioctlreturn) { if (!errno) errno=EIO; return -1; } // See if the ATA command failed. Now that we have returned from // the ioctl() call, if passthru is valid, then: // - ata->status contains the 3ware controller STATUS // - ata->command contains the ATA STATUS register // - ata->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 (ata->status || (ata->command & 0x21)) { 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); 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, cmd_twa->pdata, 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=ata->cylinder_lo; unsigned short cyl_hi=ata->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; errno=EIO; return -1; } // copy sector count register (one byte!) to return data if (command==CHECK_POWER_MODE) *data=*(char *)&(ata->sector_count); // look for nonexistent devices/ports if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) { errno=ENODEV; return -1; } return 0;}static int get_tw_channel_unit (const char* name, int* unit, int* dev) { const char *p; /* device node sanity check */ for (p = name + 3; *p; p++) if (*p < '0' || *p > '9') return -1; if (strlen(name) > 4 && *(name + 3) == '0') return -1; if (dev != NULL) *dev=atoi(name + 3); /* no need for unit number */ if (unit != NULL) *unit=0; return 0;}#ifndef IOCATAREQUESTstatic int get_ata_channel_unit ( const char* name, int* unit, int* dev) {#ifndef ATAREQUEST *dev=0; *unit=0;return 0;#else // there is no direct correlation between name 'ad0, ad1, ...' and // channel/unit number. So we need to iterate through the possible // channels and check each unit to see if we match names struct ata_cmd iocmd; int fd,maxunit; bzero(&iocmd, sizeof(struct ata_cmd)); if ((fd = open("/dev/ata", O_RDWR)) < 0) return -errno; iocmd.cmd = ATAGMAXCHANNEL; if (ioctl(fd, IOCATA, &iocmd) < 0) { return -errno; close(fd); } maxunit = iocmd.u.maxchan; for (*unit = 0; *unit < maxunit; (*unit)++) { iocmd.channel = *unit; iocmd.device = -1; iocmd.cmd = ATAGPARM; if (ioctl(fd, IOCATA, &iocmd) < 0) { close(fd); return -errno; } if (iocmd.u.param.type[0] && !strcmp(name,iocmd.u.param.name[0])) { *dev = 0; break; } if (iocmd.u.param.type[1] && !strcmp(name,iocmd.u.param.name[1])) { *dev = 1; break; } } close(fd); if (*unit == maxunit) return -1; else return 0;#endif}#endif// Guess device type (ata or scsi) based on device name (FreeBSD// specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst,// osst, nosst and sg.static const char * fbsd_dev_prefix = "/dev/";static const char * fbsd_dev_ata_disk_prefix = "ad";static const char * fbsd_dev_scsi_disk_plus = "da";static const char * fbsd_dev_scsi_tape1 = "sa";static const char * fbsd_dev_scsi_tape2 = "nsa";static const char * fbsd_dev_scsi_tape3 = "esa";static const char * fbsd_dev_twe_ctrl = "twe";static const char * fbsd_dev_twa_ctrl = "twa";static const char * fbsd_dev_cciss = "ciss";static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan) { int len; int dev_prefix_len = strlen(fbsd_dev_prefix); // if dev_name null, or string length zero if (!dev_name || !(len = strlen(dev_name))) return CONTROLLER_UNKNOWN; // Remove the leading /dev/... if it's there if (!strncmp(fbsd_dev_prefix, dev_name, dev_prefix_len)) { if (len <= dev_prefix_len) // if nothing else in the string, unrecognized return CONTROLLER_UNKNOWN; // else advance pointer to following characters dev_name += dev_prefix_len; } // form /dev/ad* or ad* if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name, strlen(fbsd_dev_ata_disk_prefix))) {#ifndef IOCATAREQUEST if (chan != NULL) { if (get_ata_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { return CONTROLLER_UNKNOWN; } }#endif return CONTROLLER_ATA; } // form /dev/da* or da* if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name, strlen(fbsd_dev_scsi_disk_plus))) goto handlescsi; // form /dev/sa* or sa* if (!strncmp(fbsd_dev_scsi_tape1, dev_name, strlen(fbsd_dev_scsi_tape1))) goto handlescsi; // form /dev/nsa* or nsa* if (!strncmp(fbsd_dev_scsi_tape2, dev_name, strlen(fbsd_dev_scsi_tape2))) goto handlescsi; // form /dev/esa* or esa* if (!strncmp(fbsd_dev_scsi_tape3, dev_name, strlen(fbsd_dev_scsi_tape3))) goto handlescsi; if (!strncmp(fbsd_dev_twa_ctrl,dev_name, strlen(fbsd_dev_twa_ctrl))) { if (chan != NULL) { if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { return CONTROLLER_UNKNOWN; } } else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) { return CONTROLLER_UNKNOWN; } return CONTROLLER_3WARE_9000_CHAR; } if (!strncmp(fbsd_dev_twe_ctrl,dev_name, strlen(fbsd_dev_twe_ctrl))) { if (chan != NULL) { if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { return CONTROLLER_UNKNOWN; } } else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) { return CONTROLLER_UNKNOWN; } return CONTROLLER_3WARE_678K_CHAR; } // form /dev/ciss* if (!strncmp(fbsd_dev_cciss, dev_name, strlen(fbsd_dev_cciss))) return CONTROLLER_CCISS; // we failed to recognize any of the forms return CONTROLLER_UNKNOWN; handlescsi: if (chan != NULL) { if (!(chan->devname = (char *)calloc(1,DEV_IDLEN+1))) return CONTROLLER_UNKNOWN; if (cam_get_device(dev_name,chan->devname,DEV_IDLEN,&(chan->unitnum)) == -1) return CONTROLLER_UNKNOWN; } return CONTROLLER_SCSI; }int guess_device_type (const char* dev_name) { return parse_ata_chan_dev(dev_name,NULL);}// global variable holding byte count of allocated memoryextern long long bytes;// we are going to take advantage of the fact that FreeBSD's devfs will only// have device entries for devices that exist. So if we get the equivilent of// ls /dev/ad?, we have all the ATA devices on the system//// If any errors occur, leave errno set as it was returned by the// system call, and return <0.// Return values:// -1 out of memory// -2 to -5 errors in globint get_dev_names(char*** names, const char* prefix) { int n = 0; char** mp; int retglob,lim; glob_t globbuf; int i; char pattern1[128],pattern2[128]; bzero(&globbuf,sizeof(globbuf)); // in case of non-clean exit *names=NULL; // handle 0-99 possible devices, will still be limited by MAX_NUM_DEV sprintf(pattern1,"/dev/%s[0-9]",prefix); sprintf(pattern2,"/dev/%s[0-9][0-9]",prefix); // Use glob to look for any directory entries matching the patterns // first call inits with first pattern match, second call appends // to first list. GLOB_NOCHECK results in no error if no more matches // found, however it does append the actual pattern to the list of // paths.... if ((retglob=glob(pattern1, GLOB_ERR|GLOB_NOCHECK, NULL, &globbuf)) || (retglob=glob(pattern2, GLOB_ERR|GLOB_APPEND|GLOB_NOCHECK,NULL,&globbuf))) { int retval = -1; // glob failed if (retglob==GLOB_NOSPACE) pout("glob(3) ran out of memory matching patterns (%s),(%s)\n", pattern1, pattern2); else if (retglob==GLOB_ABORTED) pout("glob(3) aborted matching patterns (%s),(%s)\n", pattern1, pattern2); else if (retglob==GLOB_NOMATCH) { pout("glob(3) found no matches for patterns (%s),(%s)\n", pattern1, pattern2); retval = 0; } else if (retglob) pout("Unexplained error in glob(3) of patterns (%s),(%s)\n", pattern1, pattern2); // Free memory and return globfree(&globbuf); return retval; } // did we find too many paths? lim = globbuf.gl_pathc < MAX_NUM_DEV ? globbuf.gl_pathc : MAX_NUM_DEV; if (lim < globbuf.gl_pathc) pout("glob(3) found %d > MAX=%d devices matching patterns (%s),(%s): ignoring %d paths\n", globbuf.gl_pathc, MAX_NUM_DEV, pattern1,pattern2, globbuf.gl_pathc-MAX_NUM_DEV); // allocate space for up to lim number of ATA devices if (!(mp = (char **)calloc(lim, sizeof(char*)))){ pout("Out of memory constructing scan device list\n"); return -1; } // now step through the list returned by glob. No link checking needed // in FreeBSD for (i=0; i<globbuf.gl_pathc; i++){ // because of the NO_CHECK in calls to glob, // the pattern itself will be added to path list.. // so ignore any paths that have the ']' from pattern if (strchr(globbuf.gl_pathv[i],']') == NULL) mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); } globfree(&globbuf); mp = (char **)realloc(mp,n*(sizeof(char*))); // shrink to correct size bytes += (n)*(sizeof(char*)); // and set allocated byte count *names=mp; return n;}int make_device_names (char*** devlist, const char* name) { if (!strcmp(name,"SCSI")) return get_dev_names(devlist,"da"); else if (!strcmp(name,"ATA")) return get_dev_names(devlist,"ad"); else return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -