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