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