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