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