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