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