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