1 /* 2 * Copyright (c) 2004-2005 HighPoint Technologies, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 /* 29 * hptproc.c sysctl support 30 */ 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/malloc.h> 35 #include <sys/sysctl.h> 36 #include <machine/stdarg.h> 37 38 #ifndef __KERNEL__ 39 #define __KERNEL__ 40 #endif 41 42 #include <dev/hptmv/global.h> 43 #include <dev/hptmv/hptintf.h> 44 #include <dev/hptmv/osbsd.h> 45 #include <dev/hptmv/access601.h> 46 47 int hpt_rescan_all(void); 48 49 /***************************************************************************/ 50 51 static char hptproc_buffer[256]; 52 extern char DRIVER_VERSION[]; 53 54 #define FORMAL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1, \ 55 intptr_t arg2, struct sysctl_req *req 56 #define REAL_HANDLER_ARGS oidp, arg1, arg2, req 57 typedef struct sysctl_req HPT_GET_INFO; 58 59 static int 60 hpt_set_asc_info(IAL_ADAPTER_T *pAdapter, char *buffer,int length) 61 { 62 int orig_length = length+4; 63 PVBus _vbus_p = &pAdapter->VBus; 64 PVDevice pArray; 65 PVDevice pSubArray, pVDev; 66 UINT i, iarray, ichan; 67 struct cam_periph *periph = NULL; 68 69 mtx_lock(&pAdapter->lock); 70 #ifdef SUPPORT_ARRAY 71 if (length>=8 && strncmp(buffer, "rebuild ", 8)==0) 72 { 73 buffer+=8; 74 length-=8; 75 if (length>=5 && strncmp(buffer, "start", 5)==0) 76 { 77 for(i = 0; i < MAX_ARRAY_PER_VBUS; i++) 78 if ((pArray=ArrayTables(i))->u.array.dArStamp==0) 79 continue; 80 else{ 81 if (pArray->u.array.rf_need_rebuild && !pArray->u.array.rf_rebuilding) 82 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, 83 (UCHAR)((pArray->u.array.CriticalMembers || pArray->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY)); 84 } 85 mtx_unlock(&pAdapter->lock); 86 return orig_length; 87 } 88 else if (length>=4 && strncmp(buffer, "stop", 4)==0) 89 { 90 for(i = 0; i < MAX_ARRAY_PER_VBUS; i++) 91 if ((pArray=ArrayTables(i))->u.array.dArStamp==0) 92 continue; 93 else{ 94 if (pArray->u.array.rf_rebuilding) 95 pArray->u.array.rf_abort_rebuild = 1; 96 } 97 mtx_unlock(&pAdapter->lock); 98 return orig_length; 99 } 100 else if (length>=3 && buffer[1]==','&& buffer[0]>='1'&& buffer[2]>='1') 101 { 102 iarray = buffer[0]-'1'; 103 ichan = buffer[2]-'1'; 104 105 if(iarray >= MAX_VDEVICE_PER_VBUS || ichan >= MV_SATA_CHANNELS_NUM) return -EINVAL; 106 107 pArray = _vbus_p->pVDevice[iarray]; 108 if (!pArray || (pArray->vf_online == 0)) { 109 mtx_unlock(&pAdapter->lock); 110 return -EINVAL; 111 } 112 113 for (i=0;i<MV_SATA_CHANNELS_NUM;i++) 114 if(i == ichan) 115 goto rebuild; 116 117 mtx_unlock(&pAdapter->lock); 118 return -EINVAL; 119 120 rebuild: 121 pVDev = &pAdapter->VDevices[ichan]; 122 if(!pVDev->u.disk.df_on_line || pVDev->pParent) { 123 mtx_unlock(&pAdapter->lock); 124 return -EINVAL; 125 } 126 127 /* Not allow to use a mounted disk ??? test*/ 128 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) 129 if(pVDev == _vbus_p->pVDevice[i]) 130 { 131 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId,i); 132 if (periph != NULL && periph->refcount >= 1) 133 { 134 hpt_printk(("Can not use disk used by OS!\n")); 135 mtx_unlock(&pAdapter->lock); 136 return -EINVAL; 137 } 138 /* the Mounted Disk isn't delete */ 139 } 140 141 switch(pArray->VDeviceType) 142 { 143 case VD_RAID_1: 144 case VD_RAID_5: 145 { 146 pSubArray = pArray; 147 loop: 148 if(hpt_add_disk_to_array(_VBUS_P VDEV_TO_ID(pSubArray), VDEV_TO_ID(pVDev)) == -1) { 149 mtx_unlock(&pAdapter->lock); 150 return -EINVAL; 151 } 152 pSubArray->u.array.rf_auto_rebuild = 0; 153 pSubArray->u.array.rf_abort_rebuild = 0; 154 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pSubArray, DUPLICATE); 155 break; 156 } 157 case VD_RAID_0: 158 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) 159 if(pArray->u.array.pMember[i] && mIsArray(pArray->u.array.pMember[i]) && 160 (pArray->u.array.pMember[i]->u.array.rf_broken == 1)) 161 { 162 pSubArray = pArray->u.array.pMember[i]; 163 goto loop; 164 } 165 default: 166 mtx_unlock(&pAdapter->lock); 167 return -EINVAL; 168 } 169 mtx_unlock(&pAdapter->lock); 170 return orig_length; 171 } 172 } 173 else if (length>=7 && strncmp(buffer, "verify ", 7)==0) 174 { 175 buffer+=7; 176 length-=7; 177 if (length>=6 && strncmp(buffer, "start ", 6)==0) 178 { 179 buffer+=6; 180 length-=6; 181 if (length>=1 && *buffer>='1') 182 { 183 iarray = *buffer-'1'; 184 if(iarray >= MAX_VDEVICE_PER_VBUS) { 185 mtx_unlock(&pAdapter->lock); 186 return -EINVAL; 187 } 188 189 pArray = _vbus_p->pVDevice[iarray]; 190 if (!pArray || (pArray->vf_online == 0)) { 191 mtx_unlock(&pAdapter->lock); 192 return -EINVAL; 193 } 194 195 if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5) { 196 mtx_unlock(&pAdapter->lock); 197 return -EINVAL; 198 } 199 200 if (!(pArray->u.array.rf_need_rebuild || 201 pArray->u.array.rf_rebuilding || 202 pArray->u.array.rf_verifying || 203 pArray->u.array.rf_initializing)) 204 { 205 pArray->u.array.RebuildSectors = 0; 206 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, VERIFY); 207 } 208 mtx_unlock(&pAdapter->lock); 209 return orig_length; 210 } 211 } 212 else if (length>=5 && strncmp(buffer, "stop ", 5)==0) 213 { 214 buffer+=5; 215 length-=5; 216 if (length>=1 && *buffer>='1') 217 { 218 iarray = *buffer-'1'; 219 if(iarray >= MAX_VDEVICE_PER_VBUS) { 220 mtx_unlock(&pAdapter->lock); 221 return -EINVAL; 222 } 223 224 pArray = _vbus_p->pVDevice[iarray]; 225 if (!pArray || (pArray->vf_online == 0)) { 226 mtx_unlock(&pAdapter->lock); 227 return -EINVAL; 228 } 229 if(pArray->u.array.rf_verifying) 230 { 231 pArray->u.array.rf_abort_rebuild = 1; 232 } 233 mtx_unlock(&pAdapter->lock); 234 return orig_length; 235 } 236 } 237 } 238 else 239 #ifdef _RAID5N_ 240 if (length>=10 && strncmp(buffer, "writeback ", 10)==0) { 241 buffer+=10; 242 length-=10; 243 if (length>=1 && *buffer>='0' && *buffer<='1') { 244 _vbus_(r5.enable_write_back) = *buffer-'0'; 245 if (_vbus_(r5.enable_write_back)) 246 hpt_printk(("RAID5 write back enabled")); 247 mtx_unlock(&pAdapter->lock); 248 return orig_length; 249 } 250 } 251 else 252 #endif 253 #endif 254 if (0) {} /* just to compile */ 255 #ifdef DEBUG 256 else if (length>=9 && strncmp(buffer, "dbglevel ", 9)==0) { 257 buffer+=9; 258 length-=9; 259 if (length>=1 && *buffer>='0' && *buffer<='3') { 260 hpt_dbg_level = *buffer-'0'; 261 mtx_unlock(&pAdapter->lock); 262 return orig_length; 263 } 264 } 265 else if (length>=8 && strncmp(buffer, "disable ", 8)==0) { 266 /* TO DO */ 267 } 268 #endif 269 mtx_unlock(&pAdapter->lock); 270 271 return -EINVAL; 272 } 273 274 /* 275 * Since we have only one sysctl node, add adapter ID in the command 276 * line string: e.g. "hpt 0 rebuild start" 277 */ 278 static int 279 hpt_set_info(int length) 280 { 281 int retval; 282 283 #ifdef SUPPORT_IOCTL 284 PUCHAR ke_area; 285 int err; 286 DWORD dwRet; 287 PHPT_IOCTL_PARAM piop; 288 #endif 289 char *buffer = hptproc_buffer; 290 if (length >= 6) { 291 if (strncmp(buffer,"hpt ",4) == 0) { 292 IAL_ADAPTER_T *pAdapter; 293 retval = buffer[4]-'0'; 294 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) { 295 if (pAdapter->mvSataAdapter.adapterId==retval) 296 return (retval = hpt_set_asc_info(pAdapter, buffer+6, length-6)) >= 0? retval : -EINVAL; 297 } 298 return -EINVAL; 299 } 300 #ifdef SUPPORT_IOCTL 301 piop = (PHPT_IOCTL_PARAM)buffer; 302 if (piop->Magic == HPT_IOCTL_MAGIC || 303 piop->Magic == HPT_IOCTL_MAGIC32) { 304 KdPrintE(("ioctl=%d in=%p len=%d out=%p len=%d\n", 305 piop->dwIoControlCode, 306 piop->lpInBuffer, 307 piop->nInBufferSize, 308 piop->lpOutBuffer, 309 piop->nOutBufferSize)); 310 311 /* 312 * map buffer to kernel. 313 */ 314 if (piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) { 315 KdPrintE(("User buffer too large\n")); 316 return -EINVAL; 317 } 318 319 ke_area = malloc(piop->nInBufferSize+piop->nOutBufferSize, M_DEVBUF, M_NOWAIT); 320 if (ke_area == NULL) { 321 KdPrintE(("Couldn't allocate kernel mem.\n")); 322 return -EINVAL; 323 } 324 325 if (piop->nInBufferSize) 326 copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize); 327 328 /* 329 * call kernel handler. 330 */ 331 err = Kernel_DeviceIoControl(&gIal_Adapter->VBus, 332 piop->dwIoControlCode, ke_area, piop->nInBufferSize, 333 ke_area + piop->nInBufferSize, piop->nOutBufferSize, &dwRet); 334 335 if (err==0) { 336 if (piop->nOutBufferSize) 337 copyout(ke_area + piop->nInBufferSize, (void*)(ULONG_PTR)piop->lpOutBuffer, piop->nOutBufferSize); 338 339 if (piop->lpBytesReturned) 340 copyout(&dwRet, (void*)(ULONG_PTR)piop->lpBytesReturned, sizeof(DWORD)); 341 342 free(ke_area, M_DEVBUF); 343 return length; 344 } 345 else KdPrintW(("Kernel_ioctl(): return %d\n", err)); 346 347 free(ke_area, M_DEVBUF); 348 return -EINVAL; 349 } else { 350 KdPrintW(("Wrong signature: %x\n", piop->Magic)); 351 return -EINVAL; 352 } 353 #endif 354 } 355 356 return -EINVAL; 357 } 358 359 #define shortswap(w) ((WORD)((w)>>8 | ((w) & 0xFF)<<8)) 360 361 static void 362 get_disk_name(char *name, PDevice pDev) 363 { 364 int i; 365 MV_SATA_CHANNEL *pMvSataChannel = pDev->mv; 366 IDENTIFY_DATA2 *pIdentifyData = (IDENTIFY_DATA2 *)pMvSataChannel->identifyDevice; 367 368 for (i = 0; i < 10; i++) 369 ((WORD*)name)[i] = shortswap(pIdentifyData->ModelNumber[i]); 370 name[20] = '\0'; 371 } 372 373 static int 374 hpt_copy_info(HPT_GET_INFO *pinfo, char *fmt, ...) 375 { 376 int printfretval; 377 va_list ap; 378 379 if(fmt == NULL) { 380 *hptproc_buffer = 0; 381 return (SYSCTL_OUT(pinfo, hptproc_buffer, 1)); 382 } 383 else 384 { 385 va_start(ap, fmt); 386 printfretval = vsnprintf(hptproc_buffer, sizeof(hptproc_buffer), fmt, ap); 387 va_end(ap); 388 return(SYSCTL_OUT(pinfo, hptproc_buffer, strlen(hptproc_buffer))); 389 } 390 } 391 392 static void 393 hpt_copy_disk_info(HPT_GET_INFO *pinfo, PVDevice pVDev, UINT iChan) 394 { 395 char name[32], arrayname[16], *status; 396 397 get_disk_name(name, &pVDev->u.disk); 398 399 if (!pVDev->u.disk.df_on_line) 400 status = "Disabled"; 401 else if (pVDev->VDeviceType==VD_SPARE) 402 status = "Spare "; 403 else 404 status = "Normal "; 405 406 #ifdef SUPPORT_ARRAY 407 if(pVDev->pParent) { 408 memcpy(arrayname, pVDev->pParent->u.array.ArrayName, MAX_ARRAY_NAME); 409 if (pVDev->pParent->u.array.CriticalMembers & (1<<pVDev->bSerialNumber)) 410 status = "Degraded"; 411 } 412 else 413 #endif 414 arrayname[0]=0; 415 416 hpt_copy_info(pinfo, "Channel %d %s %5dMB %s %s\n", 417 iChan+1, 418 name, pVDev->VDeviceCapacity>>11, status, arrayname); 419 } 420 421 #ifdef SUPPORT_ARRAY 422 static void 423 hpt_copy_array_info(HPT_GET_INFO *pinfo, int nld, PVDevice pArray) 424 { 425 int i; 426 char *sType=0, *sStatus=0; 427 char buf[32]; 428 PVDevice pTmpArray; 429 430 switch (pArray->VDeviceType) { 431 case VD_RAID_0: 432 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) 433 if(pArray->u.array.pMember[i]) { 434 if(mIsArray(pArray->u.array.pMember[i])) 435 sType = "RAID 1/0 "; 436 /* TO DO */ 437 else 438 sType = "RAID 0 "; 439 break; 440 } 441 break; 442 443 case VD_RAID_1: 444 sType = "RAID 1 "; 445 break; 446 447 case VD_JBOD: 448 sType = "JBOD "; 449 break; 450 451 case VD_RAID_5: 452 sType = "RAID 5 "; 453 break; 454 455 default: 456 sType = "N/A "; 457 break; 458 } 459 460 if (pArray->vf_online == 0) 461 sStatus = "Disabled"; 462 else if (pArray->u.array.rf_broken) 463 sStatus = "Critical"; 464 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) 465 { 466 if (!sStatus) 467 { 468 if(mIsArray(pArray->u.array.pMember[i])) 469 pTmpArray = pArray->u.array.pMember[i]; 470 else 471 pTmpArray = pArray; 472 473 if (pTmpArray->u.array.rf_rebuilding) { 474 #ifdef DEBUG 475 sprintf(buf, "Rebuilding %lldMB", (pTmpArray->u.array.RebuildSectors>>11)); 476 #else 477 sprintf(buf, "Rebuilding %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11))); 478 #endif 479 sStatus = buf; 480 } 481 else if (pTmpArray->u.array.rf_verifying) { 482 sprintf(buf, "Verifying %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11))); 483 sStatus = buf; 484 } 485 else if (pTmpArray->u.array.rf_need_rebuild) 486 sStatus = "Critical"; 487 else if (pTmpArray->u.array.rf_broken) 488 sStatus = "Critical"; 489 490 if(pTmpArray == pArray) goto out; 491 } 492 else 493 goto out; 494 } 495 out: 496 if (!sStatus) sStatus = "Normal"; 497 hpt_copy_info(pinfo, "%2d %11s %-20s %5lldMB %-16s", nld, sType, pArray->u.array.ArrayName, pArray->VDeviceCapacity>>11, sStatus); 498 } 499 #endif 500 501 static int 502 hpt_get_info(IAL_ADAPTER_T *pAdapter, HPT_GET_INFO *pinfo) 503 { 504 PVBus _vbus_p = &pAdapter->VBus; 505 struct cam_periph *periph = NULL; 506 UINT channel,j,i; 507 PVDevice pVDev; 508 509 #ifndef FOR_DEMO 510 mtx_lock(&pAdapter->lock); 511 if (pAdapter->beeping) { 512 pAdapter->beeping = 0; 513 BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress); 514 } 515 mtx_unlock(&pAdapter->lock); 516 #endif 517 518 hpt_copy_info(pinfo, "Controller #%d:\n\n", pAdapter->mvSataAdapter.adapterId); 519 520 hpt_copy_info(pinfo, "Physical device list\n"); 521 hpt_copy_info(pinfo, "Channel Model Capacity Status Array\n"); 522 hpt_copy_info(pinfo, "-------------------------------------------------------------------\n"); 523 524 for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++) 525 { 526 pVDev = &(pAdapter->VDevices[channel]); 527 if(pVDev->u.disk.df_on_line) 528 hpt_copy_disk_info(pinfo, pVDev, channel); 529 } 530 531 hpt_copy_info(pinfo, "\nLogical device list\n"); 532 hpt_copy_info(pinfo, "No. Type Name Capacity Status OsDisk\n"); 533 hpt_copy_info(pinfo, "--------------------------------------------------------------------------\n"); 534 535 j=1; 536 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++){ 537 pVDev = _vbus_p->pVDevice[i]; 538 if(pVDev){ 539 j=i+1; 540 #ifdef SUPPORT_ARRAY 541 if (mIsArray(pVDev)) 542 { 543 is_array: 544 hpt_copy_array_info(pinfo, j, pVDev); 545 } 546 else 547 #endif 548 { 549 char name[32]; 550 /* it may be add to an array after driver loaded, check it */ 551 #ifdef SUPPORT_ARRAY 552 if (pVDev->pParent) 553 /* in this case, pVDev can only be a RAID 1 source disk. */ 554 if (pVDev->pParent->VDeviceType==VD_RAID_1 && pVDev==pVDev->pParent->u.array.pMember[0]) 555 goto is_array; 556 #endif 557 get_disk_name(name, &pVDev->u.disk); 558 559 hpt_copy_info(pinfo, "%2d %s %s %5dMB %-16s", 560 j, "Single disk", name, pVDev->VDeviceCapacity>>11, 561 /* gmm 2001-6-19: Check if pDev has been added to an array. */ 562 ((pVDev->pParent) ? "Unavailable" : "Normal")); 563 } 564 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i); 565 if (periph == NULL) 566 hpt_copy_info(pinfo," %s\n","not registered"); 567 else 568 hpt_copy_info(pinfo," %s%d\n", periph->periph_name, periph->unit_number); 569 } 570 } 571 return 0; 572 } 573 574 static __inline int 575 hpt_proc_in(FORMAL_HANDLER_ARGS, int *len) 576 { 577 int i, error=0; 578 579 *len = 0; 580 if ((req->newlen - req->newidx) >= sizeof(hptproc_buffer)) { 581 error = EINVAL; 582 } else { 583 i = (req->newlen - req->newidx); 584 error = SYSCTL_IN(req, hptproc_buffer, i); 585 if (!error) 586 *len = i; 587 (hptproc_buffer)[i] = '\0'; 588 } 589 return (error); 590 } 591 592 static int 593 hpt_status(FORMAL_HANDLER_ARGS) 594 { 595 int length, error=0, retval=0; 596 IAL_ADAPTER_T *pAdapter; 597 598 error = hpt_proc_in(REAL_HANDLER_ARGS, &length); 599 600 if (req->newptr != NULL) 601 { 602 if (error || length == 0) 603 { 604 KdPrint(("error!\n")); 605 retval = EINVAL; 606 goto out; 607 } 608 609 if (hpt_set_info(length) >= 0) 610 retval = 0; 611 else 612 retval = EINVAL; 613 goto out; 614 } 615 616 hpt_copy_info(req, "%s Version %s\n", DRIVER_NAME, DRIVER_VERSION); 617 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) { 618 if (hpt_get_info(pAdapter, req) < 0) { 619 retval = EINVAL; 620 break; 621 } 622 } 623 624 hpt_copy_info(req, NULL); 625 goto out; 626 627 out: 628 return (retval); 629 } 630 631 632 #define xhptregister_node(name) hptregister_node(name) 633 634 #if __FreeBSD_version >= 1100024 635 #define hptregister_node(name) \ 636 SYSCTL_ROOT_NODE(OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \ 637 SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \ 638 NULL, 0, hpt_status, "A", "Get/Set " #name " state") 639 #else 640 #define hptregister_node(name) \ 641 SYSCTL_NODE(, OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \ 642 SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \ 643 NULL, 0, hpt_status, "A", "Get/Set " #name " state") 644 #endif 645 646 xhptregister_node(PROC_DIR_NAME); 647