1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
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
47int hpt_rescan_all(void);
48
49/***************************************************************************/
50
51static char hptproc_buffer[256];
52extern char DRIVER_VERSION[];
53
54typedef struct sysctl_req HPT_GET_INFO;
55
56static int
57hpt_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
117rebuild:
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;
144loop:
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 */
275static int
276hpt_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					err = -copyout(ke_area + piop->nInBufferSize, (void*)(ULONG_PTR)piop->lpOutBuffer, piop->nOutBufferSize);
342
343				if (err == 0 && piop->lpBytesReturned)
344					err = -copyout(&dwRet, (void*)(ULONG_PTR)piop->lpBytesReturned, sizeof(DWORD));
345
346				free(ke_area, M_DEVBUF);
347				return err == 0 ? length : err;
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
365static void
366get_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
377static int
378hpt_copy_info(HPT_GET_INFO *pinfo, char *fmt, ...)
379{
380	va_list ap;
381
382	if(fmt == NULL) {
383		*hptproc_buffer = 0;
384		return (SYSCTL_OUT(pinfo, hptproc_buffer, 1));
385	}
386	else
387	{
388		va_start(ap, fmt);
389		vsnprintf(hptproc_buffer, sizeof(hptproc_buffer), fmt, ap);
390		va_end(ap);
391		return(SYSCTL_OUT(pinfo, hptproc_buffer, strlen(hptproc_buffer)));
392	}
393}
394
395static void
396hpt_copy_disk_info(HPT_GET_INFO *pinfo, PVDevice pVDev, UINT iChan)
397{
398	char name[32], arrayname[16], *status;
399
400	get_disk_name(name, &pVDev->u.disk);
401
402	if (!pVDev->u.disk.df_on_line)
403		status = "Disabled";
404	else if (pVDev->VDeviceType==VD_SPARE)
405		status = "Spare   ";
406	else
407		status = "Normal  ";
408
409#ifdef SUPPORT_ARRAY
410	if(pVDev->pParent) {
411		memcpy(arrayname, pVDev->pParent->u.array.ArrayName, MAX_ARRAY_NAME);
412		if (pVDev->pParent->u.array.CriticalMembers & (1<<pVDev->bSerialNumber))
413			status = "Degraded";
414	}
415	else
416#endif
417		arrayname[0]=0;
418
419	hpt_copy_info(pinfo, "Channel %d  %s  %5dMB  %s %s\n",
420		iChan+1,
421		name, pVDev->VDeviceCapacity>>11, status, arrayname);
422}
423
424#ifdef SUPPORT_ARRAY
425static void
426hpt_copy_array_info(HPT_GET_INFO *pinfo, int nld, PVDevice pArray)
427{
428	int i;
429	char *sType = NULL, *sStatus = NULL;
430	char buf[32];
431    PVDevice pTmpArray;
432
433	switch (pArray->VDeviceType) {
434		case VD_RAID_0:
435			for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
436		  		if(pArray->u.array.pMember[i])	{
437			  		if(mIsArray(pArray->u.array.pMember[i]))
438				 		sType = "RAID 1/0   ";
439			  			/* TO DO */
440			  		else
441				 		sType = "RAID 0     ";
442			  		break;
443		  		}
444			break;
445
446		case VD_RAID_1:
447			sType = "RAID 1     ";
448			break;
449
450		case VD_JBOD:
451			sType = "JBOD       ";
452			break;
453
454		case VD_RAID_5:
455       		sType = "RAID 5     ";
456			break;
457
458		default:
459			sType = "N/A        ";
460			break;
461	}
462
463	if (pArray->vf_online == 0)
464		sStatus = "Disabled";
465	else if (pArray->u.array.rf_broken)
466		sStatus = "Critical";
467	for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
468	{
469		if (!sStatus)
470		{
471			if(mIsArray(pArray->u.array.pMember[i]))
472                		pTmpArray = pArray->u.array.pMember[i];
473			else
474			   	pTmpArray = pArray;
475
476			if (pTmpArray->u.array.rf_rebuilding) {
477#ifdef DEBUG
478				sprintf(buf, "Rebuilding %lldMB", (pTmpArray->u.array.RebuildSectors>>11));
479#else
480				sprintf(buf, "Rebuilding %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)));
481#endif
482				sStatus = buf;
483			}
484			else if (pTmpArray->u.array.rf_verifying) {
485				sprintf(buf, "Verifying %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)));
486				sStatus = buf;
487			}
488			else if (pTmpArray->u.array.rf_need_rebuild)
489				sStatus = "Critical";
490			else if (pTmpArray->u.array.rf_broken)
491				sStatus = "Critical";
492
493			if(pTmpArray == pArray) goto out;
494		}
495		else
496			goto out;
497	}
498out:
499	if (!sStatus) sStatus = "Normal";
500	hpt_copy_info(pinfo, "%2d  %11s  %-20s  %5lldMB  %-16s", nld, sType, pArray->u.array.ArrayName, pArray->VDeviceCapacity>>11, sStatus);
501}
502#endif
503
504static int
505hpt_get_info(IAL_ADAPTER_T *pAdapter, HPT_GET_INFO *pinfo)
506{
507	PVBus _vbus_p = &pAdapter->VBus;
508	struct cam_periph *periph = NULL;
509	UINT channel,j,i;
510	PVDevice pVDev;
511
512#ifndef FOR_DEMO
513	mtx_lock(&pAdapter->lock);
514	if (pAdapter->beeping) {
515		pAdapter->beeping = 0;
516		BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
517	}
518	mtx_unlock(&pAdapter->lock);
519#endif
520
521	hpt_copy_info(pinfo, "Controller #%d:\n\n", pAdapter->mvSataAdapter.adapterId);
522
523	hpt_copy_info(pinfo, "Physical device list\n");
524	hpt_copy_info(pinfo, "Channel    Model                Capacity  Status   Array\n");
525	hpt_copy_info(pinfo, "-------------------------------------------------------------------\n");
526
527    for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++)
528	{
529		pVDev = &(pAdapter->VDevices[channel]);
530		if(pVDev->u.disk.df_on_line)
531			 hpt_copy_disk_info(pinfo, pVDev, channel);
532	}
533
534	hpt_copy_info(pinfo, "\nLogical device list\n");
535	hpt_copy_info(pinfo, "No. Type         Name                 Capacity  Status            OsDisk\n");
536	hpt_copy_info(pinfo, "--------------------------------------------------------------------------\n");
537
538	j=1;
539	for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++){
540        pVDev = _vbus_p->pVDevice[i];
541		if(pVDev){
542			j=i+1;
543#ifdef SUPPORT_ARRAY
544			if (mIsArray(pVDev))
545			{
546		is_array:
547				hpt_copy_array_info(pinfo, j, pVDev);
548			}
549			else
550#endif
551			{
552				char name[32];
553				/* it may be add to an array after driver loaded, check it */
554#ifdef SUPPORT_ARRAY
555				if (pVDev->pParent)
556					/* in this case, pVDev can only be a RAID 1 source disk. */
557					if (pVDev->pParent->VDeviceType==VD_RAID_1 && pVDev==pVDev->pParent->u.array.pMember[0])
558						goto is_array;
559#endif
560				get_disk_name(name, &pVDev->u.disk);
561
562				hpt_copy_info(pinfo, "%2d  %s  %s  %5dMB  %-16s",
563					j, "Single disk", name, pVDev->VDeviceCapacity>>11,
564					/* gmm 2001-6-19: Check if pDev has been added to an array. */
565					((pVDev->pParent) ? "Unavailable" : "Normal"));
566			}
567			periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
568			if (periph == NULL)
569				hpt_copy_info(pinfo,"  %s\n","not registered");
570			else
571				hpt_copy_info(pinfo,"  %s%d\n", periph->periph_name, periph->unit_number);
572		 }
573	}
574	return 0;
575}
576
577static __inline int
578hpt_proc_in(SYSCTL_HANDLER_ARGS, int *len)
579{
580	int i, error=0;
581
582	*len = 0;
583	if ((req->newlen - req->newidx) >= sizeof(hptproc_buffer)) {
584		error = EINVAL;
585	} else {
586		i = (req->newlen - req->newidx);
587		error = SYSCTL_IN(req, hptproc_buffer, i);
588		if (!error)
589			*len = i;
590		(hptproc_buffer)[i] = '\0';
591	}
592	return (error);
593}
594
595static int
596hpt_status(SYSCTL_HANDLER_ARGS)
597{
598	int length, error=0, retval=0;
599	IAL_ADAPTER_T *pAdapter;
600
601	error = hpt_proc_in(oidp, arg1, arg2, req, &length);
602
603    if (req->newptr != NULL)
604	{
605		if (error || length == 0)
606		{
607    		KdPrint(("error!\n"));
608    		retval = EINVAL;
609    		goto out;
610		}
611
612		if (hpt_set_info(length) >= 0)
613			retval = 0;
614		else
615			retval = EINVAL;
616		goto out;
617    }
618
619	hpt_copy_info(req, "%s Version %s\n", DRIVER_NAME, DRIVER_VERSION);
620	for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
621		if (hpt_get_info(pAdapter, req) < 0) {
622			retval = EINVAL;
623			break;
624		}
625	}
626
627	hpt_copy_info(req, NULL);
628	goto out;
629
630out:
631	return (retval);
632}
633
634
635#define xhptregister_node(name) hptregister_node(name)
636
637#define hptregister_node(name) \
638    SYSCTL_ROOT_NODE(OID_AUTO, name, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, \
639        "Get/Set " #name " state root node"); \
640        SYSCTL_OID(_ ## name, OID_AUTO, status, \
641            CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, \
642            NULL, 0, hpt_status, "A", "Get/Set " #name " state")
643
644xhptregister_node(PROC_DIR_NAME);
645