xref: /freebsd/sys/dev/hptmv/hptproc.c (revision 396c556d77189a5c474d35cec6f44a762e310b7d)
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 = NULL, *sStatus = NULL;
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