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