1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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 /*
29 * ioctl.c ioctl interface implementation
30 */
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35
36 #ifndef __KERNEL__
37 #define __KERNEL__
38 #endif
39
40 #include <dev/hptmv/global.h>
41 #include <dev/hptmv/hptintf.h>
42 #include <dev/hptmv/osbsd.h>
43 #include <dev/hptmv/access601.h>
44
45 #pragma pack(1)
46
47 typedef struct _HPT_REBUILD_PARAM
48 {
49 DEVICEID idMirror;
50 DWORD Lba;
51 UCHAR nSector;
52 } HPT_REBUILD_PARAM, *PHPT_REBUILD_PARAM;
53
54 #pragma pack()
55
56 #define MAX_EVENTS 10
57 static HPT_EVENT hpt_event_queue[MAX_EVENTS];
58 static int event_queue_head=0, event_queue_tail=0;
59
60 static int hpt_get_event(PHPT_EVENT pEvent);
61 static int hpt_set_array_state(DEVICEID idArray, DWORD state);
62 static void lock_driver_idle(IAL_ADAPTER_T *pAdapter);
63 static void HPTLIBAPI thread_io_done(_VBUS_ARG PCommand pCmd);
64 static int HPTLIBAPI R1ControlSgl(_VBUS_ARG PCommand pCmd,
65 FPSCAT_GATH pSgTable, int logical);
66
67 static void
get_disk_location(PDevice pDev,int * controller,int * channel)68 get_disk_location(PDevice pDev, int *controller, int *channel)
69 {
70 IAL_ADAPTER_T *pAdapTemp;
71 int i, j;
72
73 *controller = *channel = 0;
74
75 for (i=1, pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next, i++) {
76 for (j=0; j<MV_SATA_CHANNELS_NUM; j++) {
77 if (pDev == &pAdapTemp->VDevices[j].u.disk) {
78 *controller = i;
79 *channel = j;
80 return;
81 }
82 }
83 }
84 }
85
86 static int
event_queue_add(PHPT_EVENT pEvent)87 event_queue_add(PHPT_EVENT pEvent)
88 {
89 int p;
90 p = (event_queue_tail + 1) % MAX_EVENTS;
91 if (p==event_queue_head)
92 {
93 return -1;
94 }
95 hpt_event_queue[event_queue_tail] = *pEvent;
96 event_queue_tail = p;
97 return 0;
98 }
99
100 static int
event_queue_remove(PHPT_EVENT pEvent)101 event_queue_remove(PHPT_EVENT pEvent)
102 {
103 if (event_queue_head != event_queue_tail)
104 {
105 *pEvent = hpt_event_queue[event_queue_head];
106 event_queue_head++;
107 event_queue_head %= MAX_EVENTS;
108 return 0;
109 }
110 return -1;
111 }
112
113 void HPTLIBAPI
ioctl_ReportEvent(UCHAR event,PVOID param)114 ioctl_ReportEvent(UCHAR event, PVOID param)
115 {
116 HPT_EVENT e;
117 ZeroMemory(&e, sizeof(e));
118 e.EventType = event;
119 switch(event)
120 {
121 case ET_INITIALIZE_ABORTED:
122 case ET_INITIALIZE_FAILED:
123 memcpy(e.Data, ((PVDevice)param)->u.array.ArrayName, MAX_ARRAY_NAME);
124 case ET_INITIALIZE_STARTED:
125 case ET_INITIALIZE_FINISHED:
126
127 case ET_REBUILD_STARTED:
128 case ET_REBUILD_ABORTED:
129 case ET_REBUILD_FAILED:
130 case ET_REBUILD_FINISHED:
131
132 case ET_VERIFY_STARTED:
133 case ET_VERIFY_ABORTED:
134 case ET_VERIFY_FAILED:
135 case ET_VERIFY_FINISHED:
136 case ET_VERIFY_DATA_ERROR:
137
138 case ET_SPARE_TOOK_OVER:
139 case ET_DEVICE_REMOVED:
140 case ET_DEVICE_PLUGGED:
141 case ET_DEVICE_ERROR:
142 e.DeviceID = VDEV_TO_ID((PVDevice)param);
143 break;
144
145 default:
146 break;
147 }
148 event_queue_add(&e);
149 if (event==ET_DEVICE_REMOVED) {
150 int controller, channel;
151 get_disk_location(&((PVDevice)param)->u.disk, &controller, &channel);
152 hpt_printk(("Device removed: controller %d channel %d\n", controller, channel));
153 }
154 wakeup(param);
155 }
156
157 static int
hpt_delete_array(_VBUS_ARG DEVICEID id,DWORD options)158 hpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options)
159 {
160 PVDevice pArray = ID_TO_VDEV(id);
161 BOOLEAN del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1;
162 int i;
163 PVDevice pa;
164
165 if ((id==0) || check_VDevice_valid(pArray))
166 return -1;
167
168 if(!mIsArray(pArray)) return -1;
169
170 if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying ||
171 pArray->u.array.rf_initializing)
172 return -1;
173
174 for(i=0; i<pArray->u.array.bArnMember; i++) {
175 pa = pArray->u.array.pMember[i];
176 if (pa && mIsArray(pa)) {
177 if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying ||
178 pa->u.array.rf_initializing)
179 return -1;
180 }
181 }
182
183 if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
184 fDeleteArray(_VBUS_P pArray, del_block0);
185 return 0;
186
187 }
188
189 /* just to prevent driver from sending more commands */
nothing(_VBUS_ARG void * notused)190 static void HPTLIBAPI nothing(_VBUS_ARG void *notused){}
191
192 void
lock_driver_idle(IAL_ADAPTER_T * pAdapter)193 lock_driver_idle(IAL_ADAPTER_T *pAdapter)
194 {
195 _VBUS_INST(&pAdapter->VBus)
196 mtx_lock(&pAdapter->lock);
197 while (pAdapter->outstandingCommands) {
198 KdPrint(("outstandingCommands is %d, wait..\n", pAdapter->outstandingCommands));
199 if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
200 mtx_sleep(pAdapter, &pAdapter->lock, 0, "hptidle", 0);
201 }
202 CheckIdleCall(_VBUS_P0);
203 }
204
Kernel_DeviceIoControl(_VBUS_ARG DWORD dwIoControlCode,PVOID lpInBuffer,DWORD nInBufferSize,PVOID lpOutBuffer,DWORD nOutBufferSize,PDWORD lpBytesReturned)205 int Kernel_DeviceIoControl(_VBUS_ARG
206 DWORD dwIoControlCode, /* operation control code */
207 PVOID lpInBuffer, /* input data buffer */
208 DWORD nInBufferSize, /* size of input data buffer */
209 PVOID lpOutBuffer, /* output data buffer */
210 DWORD nOutBufferSize, /* size of output data buffer */
211 PDWORD lpBytesReturned /* byte count */
212 )
213 {
214 IAL_ADAPTER_T *pAdapter;
215
216 switch(dwIoControlCode) {
217 case HPT_IOCTL_DELETE_ARRAY:
218 {
219 DEVICEID idArray;
220 int iSuccess;
221 int i;
222 PVDevice pArray;
223 PVBus _vbus_p;
224 struct cam_periph *periph = NULL;
225
226 if (nInBufferSize!=sizeof(DEVICEID)+sizeof(DWORD)) return -1;
227 if (nOutBufferSize!=sizeof(int)) return -1;
228 idArray = *(DEVICEID *)lpInBuffer;
229
230 pArray = ID_TO_VDEV(idArray);
231
232 if((idArray == 0) || check_VDevice_valid(pArray))
233 return -1;
234
235 if(!mIsArray(pArray))
236 return -1;
237
238 _vbus_p=pArray->pVBus;
239 pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
240
241 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) {
242 if(pArray == _vbus_p->pVDevice[i])
243 {
244 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
245 if (periph != NULL && periph->refcount >= 1)
246 {
247 hpt_printk(("Can not delete a mounted device.\n"));
248 return -1;
249 }
250 }
251 /* the Mounted Disk isn't delete */
252 }
253
254 iSuccess = hpt_delete_array(_VBUS_P idArray, *(DWORD*)((DEVICEID *)lpInBuffer+1));
255
256 *(int*)lpOutBuffer = iSuccess;
257
258 if(iSuccess != 0)
259 return -1;
260 break;
261 }
262
263 case HPT_IOCTL_GET_EVENT:
264 {
265 PHPT_EVENT pInfo;
266
267 if (nInBufferSize!=0) return -1;
268 if (nOutBufferSize!=sizeof(HPT_EVENT)) return -1;
269
270 pInfo = (PHPT_EVENT)lpOutBuffer;
271
272 if (hpt_get_event(pInfo)!=0)
273 return -1;
274 }
275 break;
276
277 case HPT_IOCTL_SET_ARRAY_STATE:
278 {
279 DEVICEID idArray;
280 DWORD state;
281
282 if (nInBufferSize!=sizeof(HPT_SET_STATE_PARAM)) return -1;
283 if (nOutBufferSize!=0) return -1;
284
285 idArray = ((PHPT_SET_STATE_PARAM)lpInBuffer)->idArray;
286 state = ((PHPT_SET_STATE_PARAM)lpInBuffer)->state;
287
288 if(hpt_set_array_state(idArray, state)!=0)
289 return -1;
290 }
291 break;
292
293 case HPT_IOCTL_RESCAN_DEVICES:
294 {
295 if (nInBufferSize!=0) return -1;
296 if (nOutBufferSize!=0) return -1;
297
298 #ifndef FOR_DEMO
299 /* stop buzzer if user perform rescan */
300 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
301 if (pAdapter->beeping) {
302 pAdapter->beeping = 0;
303 BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
304 }
305 }
306 #endif
307 }
308 break;
309
310 default:
311 {
312 PVDevice pVDev;
313
314 switch(dwIoControlCode) {
315 /* read-only ioctl functions can be called directly. */
316 case HPT_IOCTL_GET_VERSION:
317 case HPT_IOCTL_GET_CONTROLLER_IDS:
318 case HPT_IOCTL_GET_CONTROLLER_COUNT:
319 case HPT_IOCTL_GET_CONTROLLER_INFO:
320 case HPT_IOCTL_GET_CHANNEL_INFO:
321 case HPT_IOCTL_GET_LOGICAL_DEVICES:
322 case HPT_IOCTL_GET_DEVICE_INFO:
323 case HPT_IOCTL_GET_DEVICE_INFO_V2:
324 case HPT_IOCTL_GET_EVENT:
325 case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
326 if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
327 lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1;
328 break;
329
330 default:
331 /*
332 * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be
333 * wrong for second controller.
334 */
335 switch(dwIoControlCode) {
336 case HPT_IOCTL_CREATE_ARRAY:
337 pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break;
338 case HPT_IOCTL_CREATE_ARRAY_V2:
339 pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->Members[0]); break;
340 case HPT_IOCTL_SET_ARRAY_INFO:
341 pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break;
342 case HPT_IOCTL_SET_DEVICE_INFO:
343 pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break;
344 case HPT_IOCTL_SET_DEVICE_INFO_V2:
345 pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk); break;
346 case HPT_IOCTL_SET_BOOT_MARK:
347 case HPT_IOCTL_ADD_SPARE_DISK:
348 case HPT_IOCTL_REMOVE_SPARE_DISK:
349 pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break;
350 case HPT_IOCTL_ADD_DISK_TO_ARRAY:
351 pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break;
352 default:
353 pVDev = 0;
354 }
355
356 if (pVDev && !check_VDevice_valid(pVDev)){
357 _vbus_p = pVDev->pVBus;
358
359 pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
360 /*
361 * create_array, and other functions can't be executed while channel is
362 * perform I/O commands. Wait until driver is idle.
363 */
364 lock_driver_idle(pAdapter);
365 if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
366 lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) {
367 mtx_unlock(&pAdapter->lock);
368 return -1;
369 }
370 mtx_unlock(&pAdapter->lock);
371 }
372 else
373 return -1;
374 break;
375 }
376
377 #ifdef SUPPORT_ARRAY
378 switch(dwIoControlCode)
379 {
380 case HPT_IOCTL_CREATE_ARRAY:
381 {
382 pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
383 mtx_lock(&pAdapter->lock);
384 if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE)
385 {
386 (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
387 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
388 }
389 else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT)
390 {
391 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
392 }
393 else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY)
394 {
395 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
396 }
397 mtx_unlock(&pAdapter->lock);
398 break;
399 }
400
401
402 case HPT_IOCTL_CREATE_ARRAY_V2:
403 {
404 pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
405 mtx_lock(&pAdapter->lock);
406 if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) {
407 (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
408 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
409 } else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) {
410 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
411 } else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) {
412 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
413 }
414 mtx_unlock(&pAdapter->lock);
415 break;
416 }
417 case HPT_IOCTL_ADD_DISK_TO_ARRAY:
418 {
419 PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray);
420 pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt;
421 if(pArray->u.array.rf_rebuilding == 0)
422 {
423 mtx_lock(&pAdapter->lock);
424 pArray->u.array.rf_auto_rebuild = 0;
425 pArray->u.array.rf_abort_rebuild = 0;
426 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE);
427 while (!pArray->u.array.rf_rebuilding)
428 {
429 if (mtx_sleep(pArray, &pAdapter->lock, 0, "hptwait", hz * 3) != 0)
430 break;
431 }
432 mtx_unlock(&pAdapter->lock);
433 }
434 break;
435 }
436 }
437 #endif
438 return 0;
439 }
440 }
441
442 if (lpBytesReturned)
443 *lpBytesReturned = nOutBufferSize;
444 return 0;
445 }
446
447 static int
hpt_get_event(PHPT_EVENT pEvent)448 hpt_get_event(PHPT_EVENT pEvent)
449 {
450 int ret = event_queue_remove(pEvent);
451 return ret;
452 }
453
454 static int
hpt_set_array_state(DEVICEID idArray,DWORD state)455 hpt_set_array_state(DEVICEID idArray, DWORD state)
456 {
457 IAL_ADAPTER_T *pAdapter;
458 PVDevice pVDevice = ID_TO_VDEV(idArray);
459 int i;
460
461 if(idArray == 0 || check_VDevice_valid(pVDevice)) return -1;
462 if(!mIsArray(pVDevice))
463 return -1;
464 if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1;
465
466 pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt;
467
468 switch(state)
469 {
470 case MIRROR_REBUILD_START:
471 {
472 mtx_lock(&pAdapter->lock);
473 if (pVDevice->u.array.rf_rebuilding ||
474 pVDevice->u.array.rf_verifying ||
475 pVDevice->u.array.rf_initializing) {
476 mtx_unlock(&pAdapter->lock);
477 return -1;
478 }
479
480 pVDevice->u.array.rf_auto_rebuild = 0;
481 pVDevice->u.array.rf_abort_rebuild = 0;
482
483 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice,
484 (UCHAR)((pVDevice->u.array.CriticalMembers || pVDevice->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
485
486 while (!pVDevice->u.array.rf_rebuilding)
487 {
488 if (mtx_sleep(pVDevice, &pAdapter->lock, 0,
489 "hptwait", hz * 20) != 0)
490 break;
491 }
492 mtx_unlock(&pAdapter->lock);
493 }
494
495 break;
496
497 case MIRROR_REBUILD_ABORT:
498 {
499 for(i = 0; i < pVDevice->u.array.bArnMember; i++) {
500 if(pVDevice->u.array.pMember[i] != 0 && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1)
501 hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state);
502 }
503
504 mtx_lock(&pAdapter->lock);
505 if(pVDevice->u.array.rf_rebuilding != 1) {
506 mtx_unlock(&pAdapter->lock);
507 return -1;
508 }
509
510 pVDevice->u.array.rf_abort_rebuild = 1;
511
512 while (pVDevice->u.array.rf_abort_rebuild)
513 {
514 if (mtx_sleep(pVDevice, &pAdapter->lock, 0,
515 "hptabrt", hz * 20) != 0)
516 break;
517 }
518 mtx_unlock(&pAdapter->lock);
519 }
520 break;
521
522 case AS_VERIFY_START:
523 {
524 /*if(pVDevice->u.array.rf_verifying)
525 return -1;*/
526 mtx_lock(&pAdapter->lock);
527 if (pVDevice->u.array.rf_rebuilding ||
528 pVDevice->u.array.rf_verifying ||
529 pVDevice->u.array.rf_initializing) {
530 mtx_unlock(&pAdapter->lock);
531 return -1;
532 }
533
534 pVDevice->u.array.RebuildSectors = 0;
535 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
536
537 while (!pVDevice->u.array.rf_verifying)
538 {
539 if (mtx_sleep(pVDevice, &pAdapter->lock, 0,
540 "hptvrfy", hz * 20) != 0)
541 break;
542 }
543 mtx_unlock(&pAdapter->lock);
544 }
545 break;
546
547 case AS_VERIFY_ABORT:
548 {
549 mtx_lock(&pAdapter->lock);
550 if(pVDevice->u.array.rf_verifying != 1) {
551 mtx_unlock(&pAdapter->lock);
552 return -1;
553 }
554
555 pVDevice->u.array.rf_abort_rebuild = 1;
556
557 while (pVDevice->u.array.rf_abort_rebuild)
558 {
559 if (mtx_sleep(pVDevice, &pAdapter->lock, 0,
560 "hptvrfy", hz * 80) != 0)
561 break;
562 }
563 mtx_unlock(&pAdapter->lock);
564 }
565 break;
566
567 case AS_INITIALIZE_START:
568 {
569 mtx_lock(&pAdapter->lock);
570 if (pVDevice->u.array.rf_rebuilding ||
571 pVDevice->u.array.rf_verifying ||
572 pVDevice->u.array.rf_initializing) {
573 mtx_unlock(&pAdapter->lock);
574 return -1;
575 }
576
577 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
578
579 while (!pVDevice->u.array.rf_initializing)
580 {
581 if (mtx_sleep(pVDevice, &pAdapter->lock, 0,
582 "hptinit", hz * 80) != 0)
583 break;
584 }
585 mtx_unlock(&pAdapter->lock);
586 }
587 break;
588
589 case AS_INITIALIZE_ABORT:
590 {
591 mtx_lock(&pAdapter->lock);
592 if(pVDevice->u.array.rf_initializing != 1) {
593 mtx_unlock(&pAdapter->lock);
594 return -1;
595 }
596
597 pVDevice->u.array.rf_abort_rebuild = 1;
598
599 while (pVDevice->u.array.rf_abort_rebuild)
600 {
601 if (mtx_sleep(pVDevice, &pAdapter->lock, 0,
602 "hptinit", hz * 80) != 0)
603 break;
604 }
605 mtx_unlock(&pAdapter->lock);
606 }
607 break;
608
609 default:
610 return -1;
611 }
612
613 return 0;
614 }
615
616 int HPTLIBAPI
R1ControlSgl(_VBUS_ARG PCommand pCmd,FPSCAT_GATH pSgTable,int logical)617 R1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical)
618 {
619 ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors);
620 if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY)
621 bufferSize<<=1;
622 if (logical) {
623 pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer;
624 pSgTable->wSgSize = (USHORT)bufferSize;
625 pSgTable->wSgFlag = SG_FLAG_EOT;
626 }
627 else {
628 /* build physical SG table for pCmd->uCmd.R1Control.Buffer */
629 ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage;
630 ULONG length;
631 int idx = 0;
632
633 v = pCmd->uCmd.R1Control.Buffer;
634 dataPointer = (ADDRESS)fOsPhysicalAddress(v);
635
636 if ((ULONG_PTR)dataPointer & 0x1)
637 return FALSE;
638
639 #define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0)
640 #define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE)
641
642 do {
643 if (idx >= MAX_SG_DESCRIPTORS) return FALSE;
644
645 pSgTable[idx].dSgAddress = fOsPhysicalAddress(v);
646 currvaddr = v;
647 currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr));
648
649
650 do {
651 nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE));
652 nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage));
653
654 if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break;
655 nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage);
656
657 if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) {
658 nextvaddr = nextpage;
659 break;
660 }
661
662 currvaddr = nextvaddr;
663 currphypage = nextphypage;
664 }while (1);
665
666 length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v;
667 v = nextvaddr;
668 bufferSize -= length;
669
670 pSgTable[idx].wSgSize = (USHORT)length;
671 pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT;
672 idx++;
673
674 }while (bufferSize);
675 }
676 return 1;
677 }
678
679 static int End_Job=0;
680 void HPTLIBAPI
thread_io_done(_VBUS_ARG PCommand pCmd)681 thread_io_done(_VBUS_ARG PCommand pCmd)
682 {
683 End_Job = 1;
684 wakeup((caddr_t)pCmd);
685 }
686
687 void
hpt_rebuild_data_block(IAL_ADAPTER_T * pAdapter,PVDevice pArray,UCHAR flags)688 hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags)
689 {
690 ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1);
691 PCommand pCmd;
692 UINT result;
693 int needsync=0, retry=0, needdelete=0;
694 void *buffer = NULL;
695
696 _VBUS_INST(&pAdapter->VBus)
697
698 if (pArray->u.array.rf_broken==1 ||
699 pArray->u.array.RebuildSectors>=capacity)
700 return;
701
702 mtx_lock(&pAdapter->lock);
703
704 switch(flags)
705 {
706 case DUPLICATE:
707 case REBUILD_PARITY:
708 if(pArray->u.array.rf_rebuilding == 0)
709 {
710 pArray->u.array.rf_rebuilding = 1;
711 hpt_printk(("Rebuilding started.\n"));
712 ioctl_ReportEvent(ET_REBUILD_STARTED, pArray);
713 }
714 break;
715
716 case INITIALIZE:
717 if(pArray->u.array.rf_initializing == 0)
718 {
719 pArray->u.array.rf_initializing = 1;
720 hpt_printk(("Initializing started.\n"));
721 ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray);
722 }
723 break;
724
725 case VERIFY:
726 if(pArray->u.array.rf_verifying == 0)
727 {
728 pArray->u.array.rf_verifying = 1;
729 hpt_printk(("Verifying started.\n"));
730 ioctl_ReportEvent(ET_VERIFY_STARTED, pArray);
731 }
732 break;
733 }
734
735 retry_cmd:
736 pCmd = AllocateCommand(_VBUS_P0);
737 HPT_ASSERT(pCmd);
738 pCmd->cf_control = 1;
739 End_Job = 0;
740
741 if (pArray->VDeviceType==VD_RAID_1)
742 {
743 #define MAX_REBUILD_SECTORS 0x40
744
745 /* take care for discontinuous buffer in R1ControlSgl */
746 buffer = malloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT);
747 if(!buffer) {
748 FreeCommand(_VBUS_P pCmd);
749 hpt_printk(("can't allocate rebuild buffer\n"));
750 goto fail;
751 }
752 switch(flags)
753 {
754 case DUPLICATE:
755 pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
756 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
757 break;
758
759 case VERIFY:
760 pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY;
761 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2;
762 break;
763
764 case INITIALIZE:
765 pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
766 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
767 break;
768 }
769
770 pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors;
771
772 if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors)
773 pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors;
774
775 pCmd->uCmd.R1Control.Buffer = buffer;
776 pCmd->pfnBuildSgl = R1ControlSgl;
777 }
778 else if (pArray->VDeviceType==VD_RAID_5)
779 {
780 switch(flags)
781 {
782 case DUPLICATE:
783 case REBUILD_PARITY:
784 pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break;
785 case VERIFY:
786 pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break;
787 case INITIALIZE:
788 pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break;
789 }
790 pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift;
791 }
792 else
793 HPT_ASSERT(0);
794
795 pCmd->pVDevice = pArray;
796 pCmd->pfnCompletion = thread_io_done;
797 pArray->pfnSendCommand(_VBUS_P pCmd);
798 CheckPendingCall(_VBUS_P0);
799
800 if (!End_Job) {
801 mtx_sleep(pCmd, &pAdapter->lock, 0, "hptrbld", hz * 60);
802 if (!End_Job) {
803 hpt_printk(("timeout, reset\n"));
804 fResetVBus(_VBUS_P0);
805 }
806 }
807
808 result = pCmd->Result;
809 FreeCommand(_VBUS_P pCmd);
810 if (buffer) free(buffer, M_DEVBUF);
811 KdPrintI(("cmd finished %d", result));
812
813 switch(result)
814 {
815 case RETURN_SUCCESS:
816 if (!pArray->u.array.rf_abort_rebuild)
817 {
818 if(pArray->u.array.RebuildSectors < capacity)
819 {
820 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags);
821 }
822 else
823 {
824 switch (flags)
825 {
826 case DUPLICATE:
827 case REBUILD_PARITY:
828 needsync = 1;
829 pArray->u.array.rf_rebuilding = 0;
830 pArray->u.array.rf_need_rebuild = 0;
831 pArray->u.array.CriticalMembers = 0;
832 pArray->u.array.RebuildSectors = MAX_LBA_T;
833 pArray->u.array.rf_duplicate_and_create = 0;
834 hpt_printk(("Rebuilding finished.\n"));
835 ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray);
836 break;
837 case INITIALIZE:
838 needsync = 1;
839 pArray->u.array.rf_initializing = 0;
840 pArray->u.array.rf_need_rebuild = 0;
841 pArray->u.array.RebuildSectors = MAX_LBA_T;
842 hpt_printk(("Initializing finished.\n"));
843 ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray);
844 break;
845 case VERIFY:
846 pArray->u.array.rf_verifying = 0;
847 hpt_printk(("Verifying finished.\n"));
848 ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray);
849 break;
850 }
851 }
852 }
853 else
854 {
855 pArray->u.array.rf_abort_rebuild = 0;
856 if (pArray->u.array.rf_rebuilding)
857 {
858 hpt_printk(("Abort rebuilding.\n"));
859 pArray->u.array.rf_rebuilding = 0;
860 pArray->u.array.rf_duplicate_and_create = 0;
861 ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray);
862 }
863 else if (pArray->u.array.rf_verifying)
864 {
865 hpt_printk(("Abort verifying.\n"));
866 pArray->u.array.rf_verifying = 0;
867 ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray);
868 }
869 else if (pArray->u.array.rf_initializing)
870 {
871 hpt_printk(("Abort initializing.\n"));
872 pArray->u.array.rf_initializing = 0;
873 ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray);
874 }
875 needdelete=1;
876 }
877 break;
878
879 case RETURN_DATA_ERROR:
880 if (flags==VERIFY)
881 {
882 needsync = 1;
883 pArray->u.array.rf_verifying = 0;
884 pArray->u.array.rf_need_rebuild = 1;
885 hpt_printk(("Verifying failed: found inconsistency\n"));
886 ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray);
887 ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
888
889 if (!pArray->vf_online || pArray->u.array.rf_broken) break;
890
891 pArray->u.array.rf_auto_rebuild = 0;
892 pArray->u.array.rf_abort_rebuild = 0;
893 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
894 (pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY);
895 }
896 break;
897
898 default:
899 hpt_printk(("command failed with error %d\n", result));
900 if (++retry<3)
901 {
902 hpt_printk(("retry (%d)\n", retry));
903 goto retry_cmd;
904 }
905 fail:
906 pArray->u.array.rf_abort_rebuild = 0;
907 switch (flags)
908 {
909 case DUPLICATE:
910 case REBUILD_PARITY:
911 needsync = 1;
912 pArray->u.array.rf_rebuilding = 0;
913 pArray->u.array.rf_duplicate_and_create = 0;
914 hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n"));
915 ioctl_ReportEvent(ET_REBUILD_FAILED, pArray);
916 break;
917
918 case INITIALIZE:
919 needsync = 1;
920 pArray->u.array.rf_initializing = 0;
921 hpt_printk(("Initializing failed.\n"));
922 ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray);
923 break;
924
925 case VERIFY:
926 needsync = 1;
927 pArray->u.array.rf_verifying = 0;
928 hpt_printk(("Verifying failed.\n"));
929 ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
930 break;
931 }
932 needdelete=1;
933 }
934
935 while (pAdapter->outstandingCommands)
936 {
937 KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands));
938 /* put this to have driver stop processing system commands quickly */
939 if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
940 mtx_sleep(pAdapter, &pAdapter->lock, 0, "hptidle", 0);
941 }
942
943 if (needsync) SyncArrayInfo(pArray);
944 if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE)))
945 fDeleteArray(_VBUS_P pArray, TRUE);
946
947 Check_Idle_Call(pAdapter);
948 mtx_unlock(&pAdapter->lock);
949 }
950