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