2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 * hptproc.c sysctl support
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>
42 #include <dev/hptmv/global.h>
43 #include <dev/hptmv/hptintf.h>
44 #include <dev/hptmv/osbsd.h>
45 #include <dev/hptmv/access601.h>
47 int hpt_rescan_all(void);
49 /***************************************************************************/
51 static char hptproc_buffer
[256];
52 extern char DRIVER_VERSION
[];
54 typedef struct sysctl_req HPT_GET_INFO
;
57 hpt_set_asc_info(IAL_ADAPTER_T
*pAdapter
, char *buffer
,int length
)
59 int orig_length
= length
+4;
60 PVBus _vbus_p
= &pAdapter
->VBus
;
62 PVDevice pSubArray
, pVDev
;
63 UINT i
, iarray
, ichan
;
64 struct cam_periph
*periph
= NULL
;
66 mtx_lock(&pAdapter
->lock
);
68 if (length
>=8 && strncmp(buffer
, "rebuild ", 8)==0)
72 if (length
>=5 && strncmp(buffer
, "start", 5)==0)
74 for(i
= 0; i
< MAX_ARRAY_PER_VBUS
; i
++)
75 if ((pArray
=ArrayTables(i
))->u
.array
.dArStamp
==0)
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
));
82 mtx_unlock(&pAdapter
->lock
);
85 else if (length
>=4 && strncmp(buffer
, "stop", 4)==0)
87 for(i
= 0; i
< MAX_ARRAY_PER_VBUS
; i
++)
88 if ((pArray
=ArrayTables(i
))->u
.array
.dArStamp
==0)
91 if (pArray
->u
.array
.rf_rebuilding
)
92 pArray
->u
.array
.rf_abort_rebuild
= 1;
94 mtx_unlock(&pAdapter
->lock
);
97 else if (length
>=3 && buffer
[1]==','&& buffer
[0]>='1'&& buffer
[2]>='1')
99 iarray
= buffer
[0]-'1';
100 ichan
= buffer
[2]-'1';
102 if(iarray
>= MAX_VDEVICE_PER_VBUS
|| ichan
>= MV_SATA_CHANNELS_NUM
) return -EINVAL
;
104 pArray
= _vbus_p
->pVDevice
[iarray
];
105 if (!pArray
|| (pArray
->vf_online
== 0)) {
106 mtx_unlock(&pAdapter
->lock
);
110 for (i
=0;i
<MV_SATA_CHANNELS_NUM
;i
++)
114 mtx_unlock(&pAdapter
->lock
);
118 pVDev
= &pAdapter
->VDevices
[ichan
];
119 if(!pVDev
->u
.disk
.df_on_line
|| pVDev
->pParent
) {
120 mtx_unlock(&pAdapter
->lock
);
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
])
128 periph
= hpt_get_periph(pAdapter
->mvSataAdapter
.adapterId
,i
);
129 if (periph
!= NULL
&& periph
->refcount
>= 1)
131 hpt_printk(("Can not use disk used by OS!\n"));
132 mtx_unlock(&pAdapter
->lock
);
135 /* the Mounted Disk isn't delete */
138 switch(pArray
->VDeviceType
)
145 if(hpt_add_disk_to_array(_VBUS_P
VDEV_TO_ID(pSubArray
), VDEV_TO_ID(pVDev
)) == -1) {
146 mtx_unlock(&pAdapter
->lock
);
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
);
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))
159 pSubArray
= pArray
->u
.array
.pMember
[i
];
163 mtx_unlock(&pAdapter
->lock
);
166 mtx_unlock(&pAdapter
->lock
);
170 else if (length
>=7 && strncmp(buffer
, "verify ", 7)==0)
174 if (length
>=6 && strncmp(buffer
, "start ", 6)==0)
178 if (length
>=1 && *buffer
>='1')
180 iarray
= *buffer
-'1';
181 if(iarray
>= MAX_VDEVICE_PER_VBUS
) {
182 mtx_unlock(&pAdapter
->lock
);
186 pArray
= _vbus_p
->pVDevice
[iarray
];
187 if (!pArray
|| (pArray
->vf_online
== 0)) {
188 mtx_unlock(&pAdapter
->lock
);
192 if(pArray
->VDeviceType
!= VD_RAID_1
&& pArray
->VDeviceType
!= VD_RAID_5
) {
193 mtx_unlock(&pAdapter
->lock
);
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
))
202 pArray
->u
.array
.RebuildSectors
= 0;
203 hpt_queue_dpc((HPT_DPC
)hpt_rebuild_data_block
, pAdapter
, pArray
, VERIFY
);
205 mtx_unlock(&pAdapter
->lock
);
209 else if (length
>=5 && strncmp(buffer
, "stop ", 5)==0)
213 if (length
>=1 && *buffer
>='1')
215 iarray
= *buffer
-'1';
216 if(iarray
>= MAX_VDEVICE_PER_VBUS
) {
217 mtx_unlock(&pAdapter
->lock
);
221 pArray
= _vbus_p
->pVDevice
[iarray
];
222 if (!pArray
|| (pArray
->vf_online
== 0)) {
223 mtx_unlock(&pAdapter
->lock
);
226 if(pArray
->u
.array
.rf_verifying
)
228 pArray
->u
.array
.rf_abort_rebuild
= 1;
230 mtx_unlock(&pAdapter
->lock
);
237 if (length
>=10 && strncmp(buffer
, "writeback ", 10)==0) {
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
);
251 if (0) {} /* just to compile */
253 else if (length
>=9 && strncmp(buffer
, "dbglevel ", 9)==0) {
256 if (length
>=1 && *buffer
>='0' && *buffer
<='3') {
257 hpt_dbg_level
= *buffer
-'0';
258 mtx_unlock(&pAdapter
->lock
);
262 else if (length
>=8 && strncmp(buffer
, "disable ", 8)==0) {
266 mtx_unlock(&pAdapter
->lock
);
272 * Since we have only one sysctl node, add adapter ID in the command
273 * line string: e.g. "hpt 0 rebuild start"
276 hpt_set_info(int length
)
284 PHPT_IOCTL_PARAM piop
;
286 char *buffer
= hptproc_buffer
;
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
;
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
,
306 piop
->nOutBufferSize
));
309 * map buffer to kernel.
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"));
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"));
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
);
333 * call kernel handler.
335 err
= Kernel_DeviceIoControl(&gIal_Adapter
->VBus
,
336 piop
->dwIoControlCode
, ke_area
, piop
->nInBufferSize
,
337 ke_area
+ piop
->nInBufferSize
, piop
->nOutBufferSize
, &dwRet
);
340 if (piop
->nOutBufferSize
)
341 err
= -copyout(ke_area
+ piop
->nInBufferSize
, (void*)(ULONG_PTR
)piop
->lpOutBuffer
, piop
->nOutBufferSize
);
343 if (err
== 0 && piop
->lpBytesReturned
)
344 err
= -copyout(&dwRet
, (void*)(ULONG_PTR
)piop
->lpBytesReturned
, sizeof(DWORD
));
346 free(ke_area
, M_DEVBUF
);
347 return err
== 0 ? length
: err
;
349 else KdPrintW(("Kernel_ioctl(): return %d\n", err
));
351 free(ke_area
, M_DEVBUF
);
354 KdPrintW(("Wrong signature: %x\n", piop
->Magic
));
363 #define shortswap(w) ((WORD)((w)>>8 | ((w) & 0xFF)<<8))
366 get_disk_name(char *name
, PDevice pDev
)
369 MV_SATA_CHANNEL
*pMvSataChannel
= pDev
->mv
;
370 IDENTIFY_DATA2
*pIdentifyData
= (IDENTIFY_DATA2
*)pMvSataChannel
->identifyDevice
;
372 for (i
= 0; i
< 10; i
++)
373 ((WORD
*)name
)[i
] = shortswap(pIdentifyData
->ModelNumber
[i
]);
378 hpt_copy_info(HPT_GET_INFO
*pinfo
, char *fmt
, ...)
384 return (SYSCTL_OUT(pinfo
, hptproc_buffer
, 1));
389 vsnprintf(hptproc_buffer
, sizeof(hptproc_buffer
), fmt
, ap
);
391 return(SYSCTL_OUT(pinfo
, hptproc_buffer
, strlen(hptproc_buffer
)));
396 hpt_copy_disk_info(HPT_GET_INFO
*pinfo
, PVDevice pVDev
, UINT iChan
)
398 char name
[32], arrayname
[16], *status
;
400 get_disk_name(name
, &pVDev
->u
.disk
);
402 if (!pVDev
->u
.disk
.df_on_line
)
404 else if (pVDev
->VDeviceType
==VD_SPARE
)
411 memcpy(arrayname
, pVDev
->pParent
->u
.array
.ArrayName
, MAX_ARRAY_NAME
);
412 if (pVDev
->pParent
->u
.array
.CriticalMembers
& (1<<pVDev
->bSerialNumber
))
419 hpt_copy_info(pinfo
, "Channel %d %s %5dMB %s %s\n",
421 name
, pVDev
->VDeviceCapacity
>>11, status
, arrayname
);
426 hpt_copy_array_info(HPT_GET_INFO
*pinfo
, int nld
, PVDevice pArray
)
429 char *sType
= NULL
, *sStatus
= NULL
;
433 switch (pArray
->VDeviceType
) {
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
]))
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
++)
471 if(mIsArray(pArray
->u
.array
.pMember
[i
]))
472 pTmpArray
= pArray
->u
.array
.pMember
[i
];
476 if (pTmpArray
->u
.array
.rf_rebuilding
) {
478 sprintf(buf
, "Rebuilding %lldMB", (pTmpArray
->u
.array
.RebuildSectors
>>11));
480 sprintf(buf
, "Rebuilding %d%%", (UINT
)((pTmpArray
->u
.array
.RebuildSectors
>>11)*100/((pTmpArray
->VDeviceCapacity
/(pTmpArray
->u
.array
.bArnMember
-1))>>11)));
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)));
488 else if (pTmpArray
->u
.array
.rf_need_rebuild
)
489 sStatus
= "Critical";
490 else if (pTmpArray
->u
.array
.rf_broken
)
491 sStatus
= "Critical";
493 if(pTmpArray
== pArray
) goto out
;
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
);
505 hpt_get_info(IAL_ADAPTER_T
*pAdapter
, HPT_GET_INFO
*pinfo
)
507 PVBus _vbus_p
= &pAdapter
->VBus
;
508 struct cam_periph
*periph
= NULL
;
513 mtx_lock(&pAdapter
->lock
);
514 if (pAdapter
->beeping
) {
515 pAdapter
->beeping
= 0;
516 BeepOff(pAdapter
->mvSataAdapter
.adapterIoBaseAddress
);
518 mtx_unlock(&pAdapter
->lock
);
521 hpt_copy_info(pinfo
, "Controller #%d:\n\n", pAdapter
->mvSataAdapter
.adapterId
);
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");
527 for (channel
= 0; channel
< MV_SATA_CHANNELS_NUM
; channel
++)
529 pVDev
= &(pAdapter
->VDevices
[channel
]);
530 if(pVDev
->u
.disk
.df_on_line
)
531 hpt_copy_disk_info(pinfo
, pVDev
, channel
);
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");
539 for(i
= 0; i
< MAX_VDEVICE_PER_VBUS
; i
++){
540 pVDev
= _vbus_p
->pVDevice
[i
];
547 hpt_copy_array_info(pinfo
, j
, pVDev
);
553 /* it may be add to an array after driver loaded, check it */
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])
560 get_disk_name(name
, &pVDev
->u
.disk
);
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"));
567 periph
= hpt_get_periph(pAdapter
->mvSataAdapter
.adapterId
, i
);
569 hpt_copy_info(pinfo
," %s\n","not registered");
571 hpt_copy_info(pinfo
," %s%d\n", periph
->periph_name
, periph
->unit_number
);
578 hpt_proc_in(SYSCTL_HANDLER_ARGS
, int *len
)
583 if ((req
->newlen
- req
->newidx
) >= sizeof(hptproc_buffer
)) {
586 i
= (req
->newlen
- req
->newidx
);
587 error
= SYSCTL_IN(req
, hptproc_buffer
, i
);
590 (hptproc_buffer
)[i
] = '\0';
596 hpt_status(SYSCTL_HANDLER_ARGS
)
598 int length
, error
=0, retval
=0;
599 IAL_ADAPTER_T
*pAdapter
;
601 error
= hpt_proc_in(oidp
, arg1
, arg2
, req
, &length
);
603 if (req
->newptr
!= NULL
)
605 if (error
|| length
== 0)
607 KdPrint(("error!\n"));
612 if (hpt_set_info(length
) >= 0)
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) {
627 hpt_copy_info(req
, NULL
);
635 #define xhptregister_node(name) hptregister_node(name)
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")
644 xhptregister_node(PROC_DIR_NAME
);