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