vserver 1.9.5.x5
[linux-2.6.git] / drivers / scsi / megaraid / megaraid_mm.c
index 8a6bc93..e12024d 100644 (file)
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_mm.c
- * Version     : v2.20.2.0 (August 19 2004)
+ * Version     : v2.20.2.5 (Jan 21 2005)
  *
  * Common management module
  */
@@ -58,14 +58,15 @@ MODULE_PARM_DESC(dlevel, "Debug level (default=0)");
 
 EXPORT_SYMBOL(mraid_mm_register_adp);
 EXPORT_SYMBOL(mraid_mm_unregister_adp);
+EXPORT_SYMBOL(mraid_mm_adapter_app_handle);
 
 static int majorno;
-static uint32_t drvr_ver       = 0x02200100;
+static uint32_t drvr_ver       = 0x02200201;
 
 static int adapters_count_g;
 static struct list_head adapters_list_g;
 
-wait_queue_head_t wait_q;
+static wait_queue_head_t wait_q;
 
 static struct file_operations lsi_fops = {
        .open   = mraid_mm_open,
@@ -155,6 +156,17 @@ mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
                return rval;
        }
 
+       /*
+        * Check if adapter can accept ioctl. We may have marked it offline
+        * if any previous kioc had timedout on this controller.
+        */
+       if (!adp->quiescent) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid cmm: controller cannot accept cmds due to "
+                       "earlier errors\n" ));
+               return -EFAULT;
+       }
+
        /*
         * The following call will block till a kioc is available
         */
@@ -171,10 +183,15 @@ mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
        kioc->done = ioctl_done;
 
        /*
-        * Issue the IOCTL to the low level driver
+        * Issue the IOCTL to the low level driver. After the IOCTL completes
+        * release the kioc if and only if it was _not_ timedout. If it was
+        * timedout, that means that resources are still with low level driver.
         */
        if ((rval = lld_ioctl(adp, kioc))) {
-               mraid_mm_dealloc_kioc(adp, kioc);
+
+               if (!kioc->timedout)
+                       mraid_mm_dealloc_kioc(adp, kioc);
+
                return rval;
        }
 
@@ -581,6 +598,7 @@ mraid_mm_alloc_kioc(mraid_mmadp_t *adp)
        kioc->user_data         = NULL;
        kioc->user_data_len     = 0;
        kioc->user_pthru        = NULL;
+       kioc->timedout          = 0;
 
        return kioc;
 }
@@ -597,23 +615,27 @@ mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc)
        mm_dmapool_t    *pool;
        unsigned long   flags;
 
-       pool = &adp->dma_pool_list[kioc->pool_index];
+       if (kioc->pool_index != -1) {
+               pool = &adp->dma_pool_list[kioc->pool_index];
 
-       /* This routine may be called in non-isr context also */
-       spin_lock_irqsave(&pool->lock, flags);
-
-       /*
-        * While attaching the dma buffer, if we didn't get the required
-        * buffer from the pool, we would have allocated it at the run time
-        * and set the free_buf flag. We must free that buffer. Otherwise,
-        * just mark that the buffer is not in use
-        */
-       if (kioc->free_buf == 1)
-               pci_pool_free(pool->handle, kioc->buf_vaddr, kioc->buf_paddr);
-       else
-               pool->in_use = 0;
+               /* This routine may be called in non-isr context also */
+               spin_lock_irqsave(&pool->lock, flags);
 
-       spin_unlock_irqrestore(&pool->lock, flags);
+               /*
+                * While attaching the dma buffer, if we didn't get the 
+                * required buffer from the pool, we would have allocated 
+                * it at the run time and set the free_buf flag. We must 
+                * free that buffer. Otherwise, just mark that the buffer is 
+                * not in use
+                */
+               if (kioc->free_buf == 1)
+                       pci_pool_free(pool->handle, kioc->buf_vaddr, 
+                                                       kioc->buf_paddr);
+               else
+                       pool->in_use = 0;
+
+               spin_unlock_irqrestore(&pool->lock, flags);
+       }
 
        /* Return the kioc to the free pool */
        spin_lock_irqsave(&adp->kioc_pool_lock, flags);
@@ -667,6 +689,14 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
                del_timer_sync(tp);
        }
 
+       /*
+        * If the command had timedout, we mark the controller offline
+        * before returning
+        */
+       if (kioc->timedout) {
+               adp->quiescent = 0;
+       }
+
        return kioc->status;
 }
 
@@ -679,6 +709,10 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
 static void
 ioctl_done(uioc_t *kioc)
 {
+       uint32_t        adapno;
+       int             iterator;
+       mraid_mmadp_t*  adapter;
+
        /*
         * When the kioc returns from driver, make sure it still doesn't
         * have ENODATA in status. Otherwise, driver will hang on wait_event
@@ -691,7 +725,32 @@ ioctl_done(uioc_t *kioc)
                kioc->status = -EINVAL;
        }
 
-       wake_up(&wait_q);
+       /*
+        * Check if this kioc was timedout before. If so, nobody is waiting
+        * on this kioc. We don't have to wake up anybody. Instead, we just
+        * have to free the kioc
+        */
+       if (kioc->timedout) {
+               iterator        = 0;
+               adapter         = NULL;
+               adapno          = kioc->adapno;
+
+               con_log(CL_ANN, ( KERN_WARNING "megaraid cmm: completed "
+                                       "ioctl that was timedout before\n"));
+
+               list_for_each_entry(adapter, &adapters_list_g, list) {
+                       if (iterator++ == adapno) break;
+               }
+
+               kioc->timedout = 0;
+
+               if (adapter) {
+                       mraid_mm_dealloc_kioc( adapter, kioc );
+               }
+       }
+       else {
+               wake_up(&wait_q);
+       }
 }
 
 
@@ -706,6 +765,7 @@ lld_timedout(unsigned long ptr)
        uioc_t *kioc    = (uioc_t *)ptr;
 
        kioc->status    = -ETIME;
+       kioc->timedout  = 1;
 
        con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n"));
 
@@ -850,6 +910,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
        adapter->issue_uioc     = lld_adp->issue_uioc;
        adapter->timeout        = lld_adp->timeout;
        adapter->max_kioc       = lld_adp->max_kioc;
+       adapter->quiescent      = 1;
 
        /*
         * Allocate single blocks of memory for all required kiocs,
@@ -947,6 +1008,40 @@ memalloc_error:
        return rval;
 }
 
+
+/**
+ * mraid_mm_adapter_app_handle - return the application handle for this adapter
+ *
+ * For the given driver data, locate the adadpter in our global list and
+ * return the corresponding handle, which is also used by applications to
+ * uniquely identify an adapter.
+ *
+ * @param unique_id : adapter unique identifier
+ *
+ * @return adapter handle if found in the list
+ * @return 0 if adapter could not be located, should never happen though
+ */
+uint32_t
+mraid_mm_adapter_app_handle(uint32_t unique_id)
+{
+       mraid_mmadp_t   *adapter;
+       mraid_mmadp_t   *tmp;
+       int             index = 0;
+
+       list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) {
+
+               if (adapter->unique_id == unique_id) {
+
+                       return MKADAP(index);
+               }
+
+               index++;
+       }
+
+       return 0;
+}
+
+
 /**
  * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter
  *
@@ -1120,9 +1215,7 @@ mraid_mm_init(void)
 
        INIT_LIST_HEAD(&adapters_list_g);
 
-#ifdef CONFIG_COMPAT
        register_ioctl32_conversion(MEGAIOCCMD, mraid_mm_compat_ioctl);
-#endif
 
        return 0;
 }