[SCSI] mpt fusion: update MAINTAINERS (fusion part)
[safe/jmp/linux-2.6] / drivers / message / fusion / mptctl.c
index fe10cc0..58e6c31 100644 (file)
@@ -4,8 +4,8 @@
  *      For use with LSI Logic PCI chip/adapters
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2005 LSI Logic Corporation
- *  (mailto:mpt_linux_developer@lsil.com)
+ *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -66,7 +66,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 
-#define COPYRIGHT      "Copyright (c) 1999-2005 LSI Logic Corporation"
+#define COPYRIGHT      "Copyright (c) 1999-2007 LSI Logic Corporation"
 #define MODULEAUTHOR   "LSI Logic Corporation"
 #include "mptbase.h"
 #include "mptctl.h"
@@ -79,6 +79,7 @@
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
@@ -136,6 +137,12 @@ static void mptctl_free_tm_flags(MPT_ADAPTER *ioc);
  */
 static int  mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);
 
+/*
+ * Event Handler function
+ */
+static int mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+static struct fasync_struct *async_queue=NULL;
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  * Scatter gather list (SGL) sizes and limits...
@@ -306,7 +313,7 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
                 */
                dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
                         ioctl->ioc->name));
-               mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);
+               mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
        }
        return;
 
@@ -354,7 +361,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
                        ioctl->ioc->name, mf));
 
        pScsiTm = (SCSITaskMgmt_t *) mf;
-       pScsiTm->TargetID = ioctl->target;
+       pScsiTm->TargetID = ioctl->id;
        pScsiTm->Bus = hd->port;        /* 0 */
        pScsiTm->ChainOffset = 0;
        pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
@@ -472,6 +479,69 @@ mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* ASYNC Event Notification Support */
+static int
+mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+       u8 event;
+
+       event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+       dctlprintk(("%s() called\n", __FUNCTION__));
+       if(async_queue == NULL)
+               return 1;
+
+       /* Raise SIGIO for persistent events.
+        * TODO - this define is not in MPI spec yet,
+        * but they plan to set it to 0x21
+        */
+        if (event == 0x21 ) {
+               ioc->aen_event_read_flag=1;
+               dctlprintk(("Raised SIGIO to application\n"));
+               devtverboseprintk(("Raised SIGIO to application\n"));
+               kill_fasync(&async_queue, SIGIO, POLL_IN);
+               return 1;
+        }
+
+       /* This flag is set after SIGIO was raised, and
+        * remains set until the application has read
+        * the event log via ioctl=MPTEVENTREPORT
+        */
+       if(ioc->aen_event_read_flag)
+               return 1;
+
+       /* Signal only for the events that are
+        * requested for by the application
+        */
+       if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
+               ioc->aen_event_read_flag=1;
+               dctlprintk(("Raised SIGIO to application\n"));
+               devtverboseprintk(("Raised SIGIO to application\n"));
+               kill_fasync(&async_queue, SIGIO, POLL_IN);
+       }
+       return 1;
+}
+
+static int
+mptctl_fasync(int fd, struct file *filep, int mode)
+{
+       MPT_ADAPTER     *ioc;
+
+       list_for_each_entry(ioc, &ioc_list, list)
+               ioc->aen_event_read_flag=0;
+
+       dctlprintk(("%s() called\n", __FUNCTION__));
+       return fasync_helper(fd, filep, mode, &async_queue);
+}
+
+static int
+mptctl_release(struct inode *inode, struct file *filep)
+{
+       dctlprintk(("%s() called\n", __FUNCTION__));
+       return fasync_helper(-1, filep, 0, &async_queue);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  MPT ioctl handler
  *  cmd - specify the particular IOCTL command to be issued
@@ -1089,15 +1159,12 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
        struct mpt_ioctl_iocinfo *karg;
        MPT_ADAPTER             *ioc;
        struct pci_dev          *pdev;
-       struct Scsi_Host        *sh;
-       MPT_SCSI_HOST           *hd;
        int                     iocnum;
-       int                     numDevices = 0;
-       unsigned int            max_id;
-       int                     ii;
        unsigned int            port;
        int                     cim_rev;
        u8                      revision;
+       struct scsi_device      *sdev;
+       VirtDevice              *vdev;
 
        dctlprintk((": mptctl_getiocinfo called.\n"));
        /* Add of PCI INFO results in unaligned access for
@@ -1187,23 +1254,16 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 
        /* Get number of devices
          */
-       if ((sh = ioc->sh) != NULL) {
-                /* sh->max_id = maximum target ID + 1
-                */
-               max_id = sh->max_id - 1;
-               hd = (MPT_SCSI_HOST *) sh->hostdata;
-
-               /* Check all of the target structures and
-                * keep a counter.
-                */
-               if (hd && hd->Targets) {
-                       for (ii = 0; ii <= max_id; ii++) {
-                               if (hd->Targets[ii])
-                                       numDevices++;
-                       }
+       karg->numDevices = 0;
+       if (ioc->sh) {
+               shost_for_each_device(sdev, ioc->sh) {
+                       vdev = sdev->hostdata;
+                       if (vdev->vtarget->tflags &
+                           MPT_TARGET_FLAGS_RAID_COMPONENT)
+                               continue;
+                       karg->numDevices++;
                }
        }
-       karg->numDevices = numDevices;
 
        /* Set the BIOS and FW Version
         */
@@ -1249,21 +1309,16 @@ mptctl_gettargetinfo (unsigned long arg)
        struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
        struct mpt_ioctl_targetinfo karg;
        MPT_ADAPTER             *ioc;
-       struct Scsi_Host        *sh;
-       MPT_SCSI_HOST           *hd;
-       VirtTarget              *vdev;
+       VirtDevice              *vdev;
        char                    *pmem;
        int                     *pdata;
-       IOCPage2_t              *pIoc2;
-       IOCPage3_t              *pIoc3;
        int                     iocnum;
        int                     numDevices = 0;
-       unsigned int            max_id;
-       int                     id, jj, indexed_lun, lun_index;
-       u32                     lun;
+       int                     lun;
        int                     maxWordsLeft;
        int                     numBytes;
-       u8                      port, devType, bus_id;
+       u8                      port;
+       struct scsi_device      *sdev;
 
        dctlprintk(("mptctl_gettargetinfo called.\n"));
        if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
@@ -1319,74 +1374,22 @@ mptctl_gettargetinfo (unsigned long arg)
 
        /* Get number of devices
          */
-       if ((sh = ioc->sh) != NULL) {
-
-               max_id = sh->max_id - 1;
-               hd = (MPT_SCSI_HOST *) sh->hostdata;
-
-               /* Check all of the target structures.
-                * Save the Id and increment the counter,
-                * if ptr non-null.
-                * sh->max_id = maximum target ID + 1
-                */
-               if (hd && hd->Targets) {
-                       mpt_findImVolumes(ioc);
-                       pIoc2 = ioc->raid_data.pIocPg2;
-                       for ( id = 0; id <= max_id; ) {
-                               if ( pIoc2 && pIoc2->NumActiveVolumes ) {
-                                       if ( id == pIoc2->RaidVolume[0].VolumeID ) {
-                                               if (maxWordsLeft <= 0) {
-                                                       printk(KERN_ERR "mptctl_gettargetinfo - "
-                       "buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices);
-                                                       goto data_space_full;
-                                               }
-                                               if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 )
-                                                       devType = 0x80;
-                                               else
-                                                       devType = 0xC0;
-                                               bus_id = pIoc2->RaidVolume[0].VolumeBus;
-                                               numDevices++;
-                                               *pdata = ( (devType << 24) | (bus_id << 8) | id );
-                                               dctlprintk((KERN_ERR "mptctl_gettargetinfo - "
-               "volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata));
-                                               pdata++;
-                                               --maxWordsLeft;
-                                               goto next_id;
-                                       } else {
-                                               pIoc3 = ioc->raid_data.pIocPg3;
-                                               for ( jj = 0; jj < pIoc3->NumPhysDisks; jj++ ) {
-                                                       if ( pIoc3->PhysDisk[jj].PhysDiskID == id )
-                                                               goto next_id;
-                                               }
-                                       }
-                               }
-                               if ( (vdev = hd->Targets[id]) ) {
-                                       for (jj = 0; jj <= MPT_LAST_LUN; jj++) {
-                                               lun_index = (jj >> 5);
-                                               indexed_lun = (jj % 32);
-                                               lun = (1 << indexed_lun);
-                                               if (vdev->luns[lun_index] & lun) {
-                                                       if (maxWordsLeft <= 0) {
-                                                               printk(KERN_ERR "mptctl_gettargetinfo - "
-                       "buffer is full but more targets are available on ioc %d numDevices=%d\n", iocnum, numDevices);
-                                                               goto data_space_full;
-                                                       }
-                                                       bus_id = vdev->bus_id;
-                                                       numDevices++;
-                                                       *pdata = ( (jj << 16) | (bus_id << 8) | id );
-                                                       dctlprintk((KERN_ERR "mptctl_gettargetinfo - "
-               "target ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata));
-                                                       pdata++;
-                                                       --maxWordsLeft;
-                                               }
-                                       }
-                               }
-next_id:
-                               id++;
-                       }
+       if (ioc->sh){
+               shost_for_each_device(sdev, ioc->sh) {
+                       if (!maxWordsLeft)
+                               continue;
+                       vdev = sdev->hostdata;
+                       if (vdev->vtarget->tflags &
+                           MPT_TARGET_FLAGS_RAID_COMPONENT)
+                               continue;
+                       lun = (vdev->vtarget->raidVolume) ? 0x80 : vdev->lun;
+                       *pdata = (((u8)lun << 16) + (vdev->vtarget->channel << 8) +
+                           (vdev->vtarget->id ));
+                       pdata++;
+                       numDevices++;
+                       --maxWordsLeft;
                }
        }
-data_space_full:
        karg.numDevices = numDevices;
 
        /* Copy part of the data from kernel memory to user memory
@@ -1603,6 +1606,9 @@ mptctl_eventreport (unsigned long arg)
        if ((max < 1) || !ioc->events)
                return -ENODATA;
 
+       /* reset this flag so SIGIO can restart */
+       ioc->aen_event_read_flag=0;
+
        /* Copy the data from kernel memory to user memory
         */
        numBytes = max * sizeof(MPT_IOCTL_EVENTS);
@@ -1748,6 +1754,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        int             msgContext;
        u16             req_idx;
        ulong           timeout;
+       struct scsi_device *sdev;
 
        dctlprintk(("mptctl_do_mpt_command called.\n"));
        bufIn.kptr = bufOut.kptr = NULL;
@@ -1829,14 +1836,13 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        case MPI_FUNCTION_SCSI_IO_REQUEST:
                if (ioc->sh) {
                        SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
-                       VirtTarget      *pTarget = NULL;
-                       MPT_SCSI_HOST   *hd = NULL;
                        int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
                        int scsidir = 0;
-                       int target = (int) pScsiReq->TargetID;
                        int dataSize;
+                       u32 id;
 
-                       if ((target < 0) || (target >= ioc->sh->max_id)) {
+                       id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
+                       if (pScsiReq->TargetID > id) {
                                printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
                                        "Target ID out of bounds. \n",
                                        __FILE__, __LINE__);
@@ -1844,6 +1850,14 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                goto done_free_mem;
                        }
 
+                       if (pScsiReq->Bus >= ioc->number_of_buses) {
+                               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                                       "Target Bus out of bounds. \n",
+                                       __FILE__, __LINE__);
+                               rc = -ENODEV;
+                               goto done_free_mem;
+                       }
+
                        pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
                        pScsiReq->MsgFlags |= mpt_msg_flags();
 
@@ -1863,13 +1877,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                cpu_to_le32(ioc->sense_buf_low_dma
                                   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
 
-                       if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
-                               if (hd->Targets)
-                                       pTarget = hd->Targets[target];
-                       }
+                       shost_for_each_device(sdev, ioc->sh) {
+                               struct scsi_target *starget = scsi_target(sdev);
+                               VirtTarget *vtarget = starget->hostdata;
 
-                       if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
-                               qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+                               if ((pScsiReq->TargetID == vtarget->id) &&
+                                   (pScsiReq->Bus == vtarget->channel) &&
+                                   (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+                                       qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+                       }
 
                        /* Have the IOCTL driver set the direction based
                         * on the dataOutSize (ordering issue with Sparc).
@@ -1886,7 +1902,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        pScsiReq->DataLength = cpu_to_le32(dataSize);
 
                        ioc->ioctl->reset = MPTCTL_RESET_OK;
-                       ioc->ioctl->target = target;
+                       ioc->ioctl->id = pScsiReq->TargetID;
 
                } else {
                        printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
@@ -1965,7 +1981,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        pScsiReq->DataLength = cpu_to_le32(dataSize);
 
                        ioc->ioctl->reset = MPTCTL_RESET_OK;
-                       ioc->ioctl->target = pScsiReq->TargetID;
+                       ioc->ioctl->id = pScsiReq->TargetID;
                } else {
                        printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
                                "SCSI driver is not loaded. \n",
@@ -2260,7 +2276,7 @@ done_free_mem:
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* Prototype Routine for the HP HOST INFO command.
+/* Prototype Routine for the HOST INFO command.
  *
  * Outputs:    None.
  * Return:     0 if successful
@@ -2496,7 +2512,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* Prototype Routine for the HP TARGET INFO command.
+/* Prototype Routine for the TARGET INFO command.
  *
  * Outputs:    None.
  * Return:     0 if successful
@@ -2646,9 +2662,11 @@ mptctl_hp_targetinfo(unsigned long arg)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-static struct file_operations mptctl_fops = {
+static const struct file_operations mptctl_fops = {
        .owner =        THIS_MODULE,
        .llseek =       no_llseek,
+       .release =      mptctl_release,
+       .fasync =       mptctl_fasync,
        .unlocked_ioctl = mptctl_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = compat_mpctl_ioctl,
@@ -2893,6 +2911,11 @@ static int __init mptctl_init(void)
                /* FIXME! */
        }
 
+       if (mpt_event_register(mptctl_id, mptctl_event_process) == 0) {
+               devtverboseprintk((KERN_INFO MYNAM
+                 ": Registered for IOC event notifications\n"));
+       }
+
        return 0;
 
 out_fail: