2 * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
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 #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;
60 hpt_set_asc_info(IAL_ADAPTER_T *pAdapter, char *buffer,int length)
62 int orig_length = length+4;
63 PVBus _vbus_p = &pAdapter->VBus;
65 PVDevice pSubArray, pVDev;
66 UINT i, iarray, ichan;
67 struct cam_periph *periph = NULL;
69 mtx_lock(&pAdapter->lock);
71 if (length>=8 && strncmp(buffer, "rebuild ", 8)==0)
75 if (length>=5 && strncmp(buffer, "start", 5)==0)
77 for(i = 0; i < MAX_ARRAY_PER_VBUS; i++)
78 if ((pArray=ArrayTables(i))->u.array.dArStamp==0)
81 if (pArray->u.array.rf_need_rebuild && !pArray->u.array.rf_rebuilding)
82 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
83 (UCHAR)((pArray->u.array.CriticalMembers || pArray->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
85 mtx_unlock(&pAdapter->lock);
88 else if (length>=4 && strncmp(buffer, "stop", 4)==0)
90 for(i = 0; i < MAX_ARRAY_PER_VBUS; i++)
91 if ((pArray=ArrayTables(i))->u.array.dArStamp==0)
94 if (pArray->u.array.rf_rebuilding)
95 pArray->u.array.rf_abort_rebuild = 1;
97 mtx_unlock(&pAdapter->lock);
100 else if (length>=3 && buffer[1]==','&& buffer[0]>='1'&& buffer[2]>='1')
102 iarray = buffer[0]-'1';
103 ichan = buffer[2]-'1';
105 if(iarray >= MAX_VDEVICE_PER_VBUS || ichan >= MV_SATA_CHANNELS_NUM) return -EINVAL;
107 pArray = _vbus_p->pVDevice[iarray];
108 if (!pArray || (pArray->vf_online == 0)) {
109 mtx_unlock(&pAdapter->lock);
113 for (i=0;i<MV_SATA_CHANNELS_NUM;i++)
117 mtx_unlock(&pAdapter->lock);
121 pVDev = &pAdapter->VDevices[ichan];
122 if(!pVDev->u.disk.df_on_line || pVDev->pParent) {
123 mtx_unlock(&pAdapter->lock);
127 /* Not allow to use a mounted disk ??? test*/
128 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
129 if(pVDev == _vbus_p->pVDevice[i])
131 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId,i);
132 if (periph != NULL && periph->refcount >= 1)
134 hpt_printk(("Can not use disk used by OS!\n"));
135 mtx_unlock(&pAdapter->lock);
138 /* the Mounted Disk isn't delete */
141 switch(pArray->VDeviceType)
148 if(hpt_add_disk_to_array(_VBUS_P VDEV_TO_ID(pSubArray), VDEV_TO_ID(pVDev)) == -1) {
149 mtx_unlock(&pAdapter->lock);
152 pSubArray->u.array.rf_auto_rebuild = 0;
153 pSubArray->u.array.rf_abort_rebuild = 0;
154 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pSubArray, DUPLICATE);
158 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
159 if(pArray->u.array.pMember[i] && mIsArray(pArray->u.array.pMember[i]) &&
160 (pArray->u.array.pMember[i]->u.array.rf_broken == 1))
162 pSubArray = pArray->u.array.pMember[i];
166 mtx_unlock(&pAdapter->lock);
169 mtx_unlock(&pAdapter->lock);
173 else if (length>=7 && strncmp(buffer, "verify ", 7)==0)
177 if (length>=6 && strncmp(buffer, "start ", 6)==0)
181 if (length>=1 && *buffer>='1')
183 iarray = *buffer-'1';
184 if(iarray >= MAX_VDEVICE_PER_VBUS) {
185 mtx_unlock(&pAdapter->lock);
189 pArray = _vbus_p->pVDevice[iarray];
190 if (!pArray || (pArray->vf_online == 0)) {
191 mtx_unlock(&pAdapter->lock);
195 if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5) {
196 mtx_unlock(&pAdapter->lock);
200 if (!(pArray->u.array.rf_need_rebuild ||
201 pArray->u.array.rf_rebuilding ||
202 pArray->u.array.rf_verifying ||
203 pArray->u.array.rf_initializing))
205 pArray->u.array.RebuildSectors = 0;
206 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, VERIFY);
208 mtx_unlock(&pAdapter->lock);
212 else if (length>=5 && strncmp(buffer, "stop ", 5)==0)
216 if (length>=1 && *buffer>='1')
218 iarray = *buffer-'1';
219 if(iarray >= MAX_VDEVICE_PER_VBUS) {
220 mtx_unlock(&pAdapter->lock);
224 pArray = _vbus_p->pVDevice[iarray];
225 if (!pArray || (pArray->vf_online == 0)) {
226 mtx_unlock(&pAdapter->lock);
229 if(pArray->u.array.rf_verifying)
231 pArray->u.array.rf_abort_rebuild = 1;
233 mtx_unlock(&pAdapter->lock);
240 if (length>=10 && strncmp(buffer, "writeback ", 10)==0) {
243 if (length>=1 && *buffer>='0' && *buffer<='1') {
244 _vbus_(r5.enable_write_back) = *buffer-'0';
245 if (_vbus_(r5.enable_write_back))
246 hpt_printk(("RAID5 write back enabled"));
247 mtx_unlock(&pAdapter->lock);
254 if (0) {} /* just to compile */
256 else if (length>=9 && strncmp(buffer, "dbglevel ", 9)==0) {
259 if (length>=1 && *buffer>='0' && *buffer<='3') {
260 hpt_dbg_level = *buffer-'0';
261 mtx_unlock(&pAdapter->lock);
265 else if (length>=8 && strncmp(buffer, "disable ", 8)==0) {
269 mtx_unlock(&pAdapter->lock);
275 * Since we have only one sysctl node, add adapter ID in the command
276 * line string: e.g. "hpt 0 rebuild start"
279 hpt_set_info(int length)
287 PHPT_IOCTL_PARAM piop;
289 char *buffer = hptproc_buffer;
291 if (strncmp(buffer,"hpt ",4) == 0) {
292 IAL_ADAPTER_T *pAdapter;
293 retval = buffer[4]-'0';
294 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
295 if (pAdapter->mvSataAdapter.adapterId==retval)
296 return (retval = hpt_set_asc_info(pAdapter, buffer+6, length-6)) >= 0? retval : -EINVAL;
301 piop = (PHPT_IOCTL_PARAM)buffer;
302 if (piop->Magic == HPT_IOCTL_MAGIC ||
303 piop->Magic == HPT_IOCTL_MAGIC32) {
304 KdPrintE(("ioctl=%d in=%p len=%d out=%p len=%d\n",
305 piop->dwIoControlCode,
309 piop->nOutBufferSize));
312 * map buffer to kernel.
314 if (piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) {
315 KdPrintE(("User buffer too large\n"));
319 ke_area = malloc(piop->nInBufferSize+piop->nOutBufferSize, M_DEVBUF, M_NOWAIT);
320 if (ke_area == NULL) {
321 KdPrintE(("Couldn't allocate kernel mem.\n"));
325 if (piop->nInBufferSize)
326 copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize);
329 * call kernel handler.
331 err = Kernel_DeviceIoControl(&gIal_Adapter->VBus,
332 piop->dwIoControlCode, ke_area, piop->nInBufferSize,
333 ke_area + piop->nInBufferSize, piop->nOutBufferSize, &dwRet);
336 if (piop->nOutBufferSize)
337 copyout(ke_area + piop->nInBufferSize, (void*)(ULONG_PTR)piop->lpOutBuffer, piop->nOutBufferSize);
339 if (piop->lpBytesReturned)
340 copyout(&dwRet, (void*)(ULONG_PTR)piop->lpBytesReturned, sizeof(DWORD));
342 free(ke_area, M_DEVBUF);
345 else KdPrintW(("Kernel_ioctl(): return %d\n", err));
347 free(ke_area, M_DEVBUF);
350 KdPrintW(("Wrong signature: %x\n", piop->Magic));
359 #define shortswap(w) ((WORD)((w)>>8 | ((w) & 0xFF)<<8))
362 get_disk_name(char *name, PDevice pDev)
365 MV_SATA_CHANNEL *pMvSataChannel = pDev->mv;
366 IDENTIFY_DATA2 *pIdentifyData = (IDENTIFY_DATA2 *)pMvSataChannel->identifyDevice;
368 for (i = 0; i < 10; i++)
369 ((WORD*)name)[i] = shortswap(pIdentifyData->ModelNumber[i]);
374 hpt_copy_info(HPT_GET_INFO *pinfo, char *fmt, ...)
381 return (SYSCTL_OUT(pinfo, hptproc_buffer, 1));
386 printfretval = vsnprintf(hptproc_buffer, sizeof(hptproc_buffer), fmt, ap);
388 return(SYSCTL_OUT(pinfo, hptproc_buffer, strlen(hptproc_buffer)));
393 hpt_copy_disk_info(HPT_GET_INFO *pinfo, PVDevice pVDev, UINT iChan)
395 char name[32], arrayname[16], *status;
397 get_disk_name(name, &pVDev->u.disk);
399 if (!pVDev->u.disk.df_on_line)
401 else if (pVDev->VDeviceType==VD_SPARE)
408 memcpy(arrayname, pVDev->pParent->u.array.ArrayName, MAX_ARRAY_NAME);
409 if (pVDev->pParent->u.array.CriticalMembers & (1<<pVDev->bSerialNumber))
416 hpt_copy_info(pinfo, "Channel %d %s %5dMB %s %s\n",
418 name, pVDev->VDeviceCapacity>>11, status, arrayname);
423 hpt_copy_array_info(HPT_GET_INFO *pinfo, int nld, PVDevice pArray)
426 char *sType=0, *sStatus=0;
430 switch (pArray->VDeviceType) {
432 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
433 if(pArray->u.array.pMember[i]) {
434 if(mIsArray(pArray->u.array.pMember[i]))
460 if (pArray->vf_online == 0)
461 sStatus = "Disabled";
462 else if (pArray->u.array.rf_broken)
463 sStatus = "Critical";
464 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
468 if(mIsArray(pArray->u.array.pMember[i]))
469 pTmpArray = pArray->u.array.pMember[i];
473 if (pTmpArray->u.array.rf_rebuilding) {
475 sprintf(buf, "Rebuilding %lldMB", (pTmpArray->u.array.RebuildSectors>>11));
477 sprintf(buf, "Rebuilding %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)));
481 else if (pTmpArray->u.array.rf_verifying) {
482 sprintf(buf, "Verifying %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)));
485 else if (pTmpArray->u.array.rf_need_rebuild)
486 sStatus = "Critical";
487 else if (pTmpArray->u.array.rf_broken)
488 sStatus = "Critical";
490 if(pTmpArray == pArray) goto out;
496 if (!sStatus) sStatus = "Normal";
497 hpt_copy_info(pinfo, "%2d %11s %-20s %5lldMB %-16s", nld, sType, pArray->u.array.ArrayName, pArray->VDeviceCapacity>>11, sStatus);
502 hpt_get_info(IAL_ADAPTER_T *pAdapter, HPT_GET_INFO *pinfo)
504 PVBus _vbus_p = &pAdapter->VBus;
505 struct cam_periph *periph = NULL;
510 mtx_lock(&pAdapter->lock);
511 if (pAdapter->beeping) {
512 pAdapter->beeping = 0;
513 BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
515 mtx_unlock(&pAdapter->lock);
518 hpt_copy_info(pinfo, "Controller #%d:\n\n", pAdapter->mvSataAdapter.adapterId);
520 hpt_copy_info(pinfo, "Physical device list\n");
521 hpt_copy_info(pinfo, "Channel Model Capacity Status Array\n");
522 hpt_copy_info(pinfo, "-------------------------------------------------------------------\n");
524 for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++)
526 pVDev = &(pAdapter->VDevices[channel]);
527 if(pVDev->u.disk.df_on_line)
528 hpt_copy_disk_info(pinfo, pVDev, channel);
531 hpt_copy_info(pinfo, "\nLogical device list\n");
532 hpt_copy_info(pinfo, "No. Type Name Capacity Status OsDisk\n");
533 hpt_copy_info(pinfo, "--------------------------------------------------------------------------\n");
536 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++){
537 pVDev = _vbus_p->pVDevice[i];
544 hpt_copy_array_info(pinfo, j, pVDev);
550 /* it may be add to an array after driver loaded, check it */
553 /* in this case, pVDev can only be a RAID 1 source disk. */
554 if (pVDev->pParent->VDeviceType==VD_RAID_1 && pVDev==pVDev->pParent->u.array.pMember[0])
557 get_disk_name(name, &pVDev->u.disk);
559 hpt_copy_info(pinfo, "%2d %s %s %5dMB %-16s",
560 j, "Single disk", name, pVDev->VDeviceCapacity>>11,
561 /* gmm 2001-6-19: Check if pDev has been added to an array. */
562 ((pVDev->pParent) ? "Unavailable" : "Normal"));
564 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
566 hpt_copy_info(pinfo," %s\n","not registered");
568 hpt_copy_info(pinfo," %s%d\n", periph->periph_name, periph->unit_number);
575 hpt_proc_in(FORMAL_HANDLER_ARGS, int *len)
580 if ((req->newlen - req->newidx) >= sizeof(hptproc_buffer)) {
583 i = (req->newlen - req->newidx);
584 error = SYSCTL_IN(req, hptproc_buffer, i);
587 (hptproc_buffer)[i] = '\0';
593 hpt_status(FORMAL_HANDLER_ARGS)
595 int length, error=0, retval=0;
596 IAL_ADAPTER_T *pAdapter;
598 error = hpt_proc_in(REAL_HANDLER_ARGS, &length);
600 if (req->newptr != NULL)
602 if (error || length == 0)
604 KdPrint(("error!\n"));
609 if (hpt_set_info(length) >= 0)
616 hpt_copy_info(req, "%s Version %s\n", DRIVER_NAME, DRIVER_VERSION);
617 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
618 if (hpt_get_info(pAdapter, req) < 0) {
624 hpt_copy_info(req, NULL);
632 #define xhptregister_node(name) hptregister_node(name)
634 #if __FreeBSD_version >= 1100024
635 #define hptregister_node(name) \
636 SYSCTL_ROOT_NODE(OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \
637 SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \
638 NULL, 0, hpt_status, "A", "Get/Set " #name " state")
640 #define hptregister_node(name) \
641 SYSCTL_NODE(, OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \
642 SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \
643 NULL, 0, hpt_status, "A", "Get/Set " #name " state")
646 xhptregister_node(PROC_DIR_NAME);