Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[sfrench/cifs-2.6.git] / drivers / scsi / qla2xxx / qla_os.c
index b78919a318e2b2ee87dc9170c676e2f64de2b6a1..b5a77b0c0deb6d5f7d3b7e878b986bc76f4cb400 100644 (file)
@@ -29,14 +29,13 @@ static struct kmem_cache *srb_cachep;
 /*
  * Ioctl related information.
  */
-static int num_hosts;
-
+int num_hosts;
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
                "Login timeout value in seconds.");
 
-int qlport_down_retry = 30;
+int qlport_down_retry;
 module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(qlport_down_retry,
                "Maximum number of command retries to a port that returns "
@@ -112,7 +111,7 @@ static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
 static int qla2x00_change_queue_depth(struct scsi_device *, int);
 static int qla2x00_change_queue_type(struct scsi_device *, int);
 
-static struct scsi_host_template qla2x00_driver_template = {
+struct scsi_host_template qla2x00_driver_template = {
        .module                 = THIS_MODULE,
        .name                   = QLA2XXX_DRIVER_NAME,
        .queuecommand           = qla2x00_queuecommand,
@@ -143,7 +142,7 @@ static struct scsi_host_template qla2x00_driver_template = {
        .shost_attrs            = qla2x00_host_attrs,
 };
 
-static struct scsi_host_template qla24xx_driver_template = {
+struct scsi_host_template qla24xx_driver_template = {
        .module                 = THIS_MODULE,
        .name                   = QLA2XXX_DRIVER_NAME,
        .queuecommand           = qla24xx_queuecommand,
@@ -171,21 +170,21 @@ static struct scsi_host_template qla24xx_driver_template = {
 };
 
 static struct scsi_transport_template *qla2xxx_transport_template = NULL;
+struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
 
 /* TODO Convert to inlines
  *
  * Timer routines
  */
-#define        WATCH_INTERVAL          1       /* number of seconds */
 
-static void qla2x00_timer(scsi_qla_host_t *);
+void qla2x00_timer(scsi_qla_host_t *);
 
-static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,
+__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
     void *, unsigned long);
 static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
-static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
 
-static inline void
+__inline__ void
 qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
 {
        init_timer(&ha->timer);
@@ -202,7 +201,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
        mod_timer(&ha->timer, jiffies + interval * HZ);
 }
 
-static __inline__ void
+__inline__ void
 qla2x00_stop_timer(scsi_qla_host_t *ha)
 {
        del_timer_sync(&ha->timer);
@@ -213,8 +212,8 @@ static int qla2x00_do_dpc(void *data);
 
 static void qla2x00_rst_aen(scsi_qla_host_t *);
 
-static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-static void qla2x00_mem_free(scsi_qla_host_t *ha);
+uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+void qla2x00_mem_free(scsi_qla_host_t *ha);
 static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
 static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
 static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
@@ -438,6 +437,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
        srb_t *sp;
        int rval;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        rval = fc_remote_port_chkready(rport);
        if (rval) {
@@ -453,7 +453,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
-                   atomic_read(&ha->loop_state) == LOOP_DEAD) {
+                   atomic_read(&pha->loop_state) == LOOP_DEAD) {
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
                }
@@ -462,7 +462,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 
        spin_unlock_irq(ha->host->host_lock);
 
-       sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
+       sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
        if (!sp)
                goto qc24_host_busy_lock;
 
@@ -475,8 +475,8 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        return 0;
 
 qc24_host_busy_free_sp:
-       qla2x00_sp_free_dma(ha, sp);
-       mempool_free(sp, ha->srb_mempool);
+       qla2x00_sp_free_dma(pha, sp);
+       mempool_free(sp, pha->srb_mempool);
 
 qc24_host_busy_lock:
        spin_lock_irq(ha->host->host_lock);
@@ -548,16 +548,17 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
 {
        int             return_status;
        unsigned long   wait_online;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
-       while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||
-           test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
-           test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||
-           ha->dpc_active) && time_before(jiffies, wait_online)) {
+       while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
+           test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
+           test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
+           pha->dpc_active) && time_before(jiffies, wait_online)) {
 
                msleep(1000);
        }
-       if (ha->flags.online)
+       if (pha->flags.online)
                return_status = QLA_SUCCESS;
        else
                return_status = QLA_FUNCTION_FAILED;
@@ -588,14 +589,15 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
 {
        int      return_status = QLA_SUCCESS;
        unsigned long loop_timeout ;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        /* wait for 5 min at the max for loop to be ready */
        loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
 
-       while ((!atomic_read(&ha->loop_down_timer) &&
-           atomic_read(&ha->loop_state) == LOOP_DOWN) ||
-           atomic_read(&ha->loop_state) != LOOP_READY) {
-               if (atomic_read(&ha->loop_state) == LOOP_DEAD) {
+       while ((!atomic_read(&pha->loop_down_timer) &&
+           atomic_read(&pha->loop_state) == LOOP_DOWN) ||
+           atomic_read(&pha->loop_state) != LOOP_READY) {
+               if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
                        return_status = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -650,6 +652,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        unsigned long serial;
        unsigned long flags;
        int wait = 0;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        qla2x00_block_error_handler(cmd);
 
@@ -663,9 +666,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        serial = cmd->serial_number;
 
        /* Check active list for command command. */
-       spin_lock_irqsave(&ha->hardware_lock, flags);
+       spin_lock_irqsave(&pha->hardware_lock, flags);
        for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
-               sp = ha->outstanding_cmds[i];
+               sp = pha->outstanding_cmds[i];
 
                if (sp == NULL)
                        continue;
@@ -677,7 +680,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                    __func__, ha->host_no, sp, serial));
                DEBUG3(qla2x00_print_scsi_cmd(cmd));
 
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               spin_unlock_irqrestore(&pha->hardware_lock, flags);
                if (ha->isp_ops.abort_command(ha, sp)) {
                        DEBUG2(printk("%s(%ld): abort_command "
                            "mbx failed.\n", __func__, ha->host_no));
@@ -686,11 +689,11 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                            "mbx success.\n", __func__, ha->host_no));
                        wait = 1;
                }
-               spin_lock_irqsave(&ha->hardware_lock, flags);
+               spin_lock_irqsave(&pha->hardware_lock, flags);
 
                break;
        }
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       spin_unlock_irqrestore(&pha->hardware_lock, flags);
 
        /* Wait for the command to be returned. */
        if (wait) {
@@ -731,6 +734,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
        srb_t           *sp;
        struct scsi_cmnd *cmd;
        unsigned long flags;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        status = 0;
 
@@ -739,19 +743,20 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
         * array
         */
        for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-               spin_lock_irqsave(&ha->hardware_lock, flags);
-               sp = ha->outstanding_cmds[cnt];
+               spin_lock_irqsave(&pha->hardware_lock, flags);
+               sp = pha->outstanding_cmds[cnt];
                if (sp) {
                        cmd = sp->cmd;
-                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-                       if (cmd->device->id == t) {
+                       spin_unlock_irqrestore(&pha->hardware_lock, flags);
+                       if (cmd->device->id == t &&
+                           ha->vp_idx == sp->ha->vp_idx) {
                                if (!qla2x00_eh_wait_on_command(ha, cmd)) {
                                        status = 1;
                                        break;
                                }
                        }
                } else {
-                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+                       spin_unlock_irqrestore(&pha->hardware_lock, flags);
                }
        }
        return (status);
@@ -782,14 +787,12 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-       int ret;
+       int ret = FAILED;
        unsigned int id, lun;
        unsigned long serial;
 
        qla2x00_block_error_handler(cmd);
 
-       ret = FAILED;
-
        id = cmd->device->id;
        lun = cmd->device->lun;
        serial = cmd->serial_number;
@@ -912,15 +915,14 @@ static int
 qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *pha = to_qla_parent(ha);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-       int ret;
+       int ret = FAILED;
        unsigned int id, lun;
        unsigned long serial;
 
        qla2x00_block_error_handler(cmd);
 
-       ret = FAILED;
-
        id = cmd->device->id;
        lun = cmd->device->lun;
        serial = cmd->serial_number;
@@ -944,7 +946,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
                goto eh_bus_reset_done;
 
        /* Flush outstanding commands. */
-       if (!qla2x00_eh_wait_for_pending_commands(ha))
+       if (!qla2x00_eh_wait_for_pending_commands(pha))
                ret = FAILED;
 
 eh_bus_reset_done:
@@ -974,14 +976,13 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-       int ret;
+       int ret = FAILED;
        unsigned int id, lun;
        unsigned long serial;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        qla2x00_block_error_handler(cmd);
 
-       ret = FAILED;
-
        id = cmd->device->id;
        lun = cmd->device->lun;
        serial = cmd->serial_number;
@@ -1004,21 +1005,24 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
         * while dpc is stuck for the mailbox to complete.
         */
        qla2x00_wait_for_loop_ready(ha);
-       set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
-       if (qla2x00_abort_isp(ha)) {
-               clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+       set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
+       if (qla2x00_abort_isp(pha)) {
+               clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
                /* failed. schedule dpc to try */
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+               set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
 
                if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
                        goto eh_host_reset_lock;
        }
-       clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+       clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
 
        /* Waiting for our command in done_queue to be returned to OS.*/
-       if (qla2x00_eh_wait_for_pending_commands(ha))
+       if (qla2x00_eh_wait_for_pending_commands(pha))
                ret = SUCCESS;
 
+       if (ha->parent)
+               qla2x00_vp_abort_isp(ha);
+
 eh_host_reset_lock:
        qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
            (ret == FAILED) ? "failed" : "succeded");
@@ -1435,6 +1439,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->host = host;
        ha->host_no = host->host_no;
        sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
+       ha->parent = NULL;
 
        /* Set ISP-type information. */
        qla2x00_set_isp_flags(ha);
@@ -1452,7 +1457,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ha->prev_topology = 0;
        ha->init_cb_size = sizeof(init_cb_t);
-       ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
+       ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
        ha->link_data_rate = PORT_SPEED_UNKNOWN;
        ha->optrom_size = OPTROM_SIZE_2300;
 
@@ -1524,8 +1529,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
                ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
                ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
-               ha->init_cb_size = sizeof(struct init_cb_24xx);
-               ha->mgmt_svr_loop_id = 10;
+               ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+               ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
                ha->isp_ops.pci_config = qla24xx_pci_config;
                ha->isp_ops.reset_chip = qla24xx_reset_chip;
                ha->isp_ops.chip_diag = qla24xx_chip_diag;
@@ -1563,10 +1568,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->instance = num_hosts;
 
        init_MUTEX(&ha->mbx_cmd_sem);
+       init_MUTEX(&ha->vport_sem);
        init_MUTEX_LOCKED(&ha->mbx_intr_sem);
 
        INIT_LIST_HEAD(&ha->list);
        INIT_LIST_HEAD(&ha->fcports);
+       INIT_LIST_HEAD(&ha->vp_list);
+
+       set_bit(0, (unsigned long *) ha->vp_idx_map);
 
        qla2x00_config_dma_addressing(ha);
        if (qla2x00_mem_alloc(ha)) {
@@ -1577,9 +1586,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                goto probe_failed;
        }
 
-       if (qla2x00_initialize_adapter(ha) &&
-           !(ha->device_flags & DFLG_NO_CABLE)) {
-
+       if (qla2x00_initialize_adapter(ha)) {
                qla_printk(KERN_WARNING, ha,
                    "Failed to initialize adapter\n");
 
@@ -1791,7 +1798,8 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
 void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
     int do_login, int defer)
 {
-       if (atomic_read(&fcport->state) == FCS_ONLINE)
+       if (atomic_read(&fcport->state) == FCS_ONLINE &&
+           ha->vp_idx == fcport->vp_idx)
                qla2x00_schedule_rport_del(ha, fcport, defer);
 
        /*
@@ -1842,19 +1850,23 @@ void
 qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 {
        fc_port_t *fcport;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
-       list_for_each_entry(fcport, &ha->fcports, list) {
-               if (fcport->port_type != FCT_TARGET)
+       list_for_each_entry(fcport, &pha->fcports, list) {
+               if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
                        continue;
-
                /*
                 * No point in marking the device as lost, if the device is
                 * already DEAD.
                 */
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
                        continue;
-               if (atomic_read(&fcport->state) == FCS_ONLINE)
-                       qla2x00_schedule_rport_del(ha, fcport, defer);
+               if (atomic_read(&fcport->state) == FCS_ONLINE) {
+                       if (defer)
+                               qla2x00_schedule_rport_del(ha, fcport, defer);
+                       else if (ha->vp_idx == fcport->vp_idx)
+                               qla2x00_schedule_rport_del(ha, fcport, defer);
+               }
                atomic_set(&fcport->state, FCS_DEVICE_LOST);
        }
 
@@ -1870,7 +1882,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 *      0  = success.
 *      1  = failure.
 */
-static uint8_t
+uint8_t
 qla2x00_mem_alloc(scsi_qla_host_t *ha)
 {
        char    name[16];
@@ -1922,33 +1934,33 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
                        continue;
                }
 
-               snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
-                   ha->host_no);
-               ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
-                   DMA_POOL_SIZE, 8, 0);
-               if (ha->s_dma_pool == NULL) {
+               /* get consistent memory allocated for init control block */
+               ha->init_cb = dma_alloc_coherent(&ha->pdev->dev,
+                   ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL);
+               if (ha->init_cb == NULL) {
                        qla_printk(KERN_WARNING, ha,
-                           "Memory Allocation failed - s_dma_pool\n");
+                           "Memory Allocation failed - init_cb\n");
 
                        qla2x00_mem_free(ha);
                        msleep(100);
 
                        continue;
                }
+               memset(ha->init_cb, 0, ha->init_cb_size);
 
-               /* get consistent memory allocated for init control block */
-               ha->init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
-                   &ha->init_cb_dma);
-               if (ha->init_cb == NULL) {
+               snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
+                   ha->host_no);
+               ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+                   DMA_POOL_SIZE, 8, 0);
+               if (ha->s_dma_pool == NULL) {
                        qla_printk(KERN_WARNING, ha,
-                           "Memory Allocation failed - init_cb\n");
+                           "Memory Allocation failed - s_dma_pool\n");
 
                        qla2x00_mem_free(ha);
                        msleep(100);
 
                        continue;
                }
-               memset(ha->init_cb, 0, ha->init_cb_size);
 
                if (qla2x00_allocate_sp_pool(ha)) {
                        qla_printk(KERN_WARNING, ha,
@@ -2054,7 +2066,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
 * Input:
 *      ha = adapter block pointer.
 */
-static void
+void
 qla2x00_mem_free(scsi_qla_host_t *ha)
 {
        struct list_head        *fcpl, *fcptemp;
@@ -2090,12 +2102,13 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
        if (ha->ms_iocb)
                dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
 
-       if (ha->init_cb)
-               dma_pool_free(ha->s_dma_pool, ha->init_cb, ha->init_cb_dma);
-
        if (ha->s_dma_pool)
                dma_pool_destroy(ha->s_dma_pool);
 
+       if (ha->init_cb)
+               dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
+                   ha->init_cb, ha->init_cb_dma);
+
        if (ha->gid_list)
                dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
                    ha->gid_list_dma);
@@ -2201,6 +2214,7 @@ qla2x00_free_sp_pool( scsi_qla_host_t *ha)
 static int
 qla2x00_do_dpc(void *data)
 {
+       int             rval;
        scsi_qla_host_t *ha;
        fc_port_t       *fcport;
        uint8_t         status;
@@ -2349,7 +2363,7 @@ qla2x00_do_dpc(void *data)
                        if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
                            &ha->dpc_flags))) {
 
-                               qla2x00_loop_resync(ha);
+                               rval = qla2x00_loop_resync(ha);
 
                                clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
                        }
@@ -2376,6 +2390,8 @@ qla2x00_do_dpc(void *data)
                if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
                        ha->isp_ops.beacon_blink(ha);
 
+               qla2x00_do_dpc_all_vps(ha);
+
                ha->dpc_active = 0;
        } /* End of while(1) */
 
@@ -2428,13 +2444,7 @@ qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp)
        struct scsi_cmnd *cmd = sp->cmd;
 
        if (sp->flags & SRB_DMA_VALID) {
-               if (cmd->use_sg) {
-                       dma_unmap_sg(&ha->pdev->dev, cmd->request_buffer,
-                           cmd->use_sg, cmd->sc_data_direction);
-               } else if (cmd->request_bufflen) {
-                       dma_unmap_single(&ha->pdev->dev, sp->dma_handle,
-                           cmd->request_bufflen, cmd->sc_data_direction);
-               }
+               scsi_dma_unmap(cmd);
                sp->flags &= ~SRB_DMA_VALID;
        }
        CMD_SP(cmd) = NULL;
@@ -2460,7 +2470,7 @@ qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp)
 *
 * Context: Interrupt
 ***************************************************************************/
-static void
+void
 qla2x00_timer(scsi_qla_host_t *ha)
 {
        unsigned long   cpu_flags = 0;
@@ -2469,6 +2479,7 @@ qla2x00_timer(scsi_qla_host_t *ha)
        int             index;
        srb_t           *sp;
        int             t;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        /*
         * Ports - Port down timer.
@@ -2514,23 +2525,29 @@ qla2x00_timer(scsi_qla_host_t *ha)
                                atomic_set(&ha->loop_state, LOOP_DEAD);
 
                        /* Schedule an ISP abort to return any tape commands. */
-                       spin_lock_irqsave(&ha->hardware_lock, cpu_flags);
-                       for (index = 1; index < MAX_OUTSTANDING_COMMANDS;
-                           index++) {
-                               fc_port_t *sfcp;
+                       /* NPIV - scan physical port only */
+                       if (!ha->parent) {
+                               spin_lock_irqsave(&ha->hardware_lock,
+                                   cpu_flags);
+                               for (index = 1;
+                                   index < MAX_OUTSTANDING_COMMANDS;
+                                   index++) {
+                                       fc_port_t *sfcp;
+
+                                       sp = ha->outstanding_cmds[index];
+                                       if (!sp)
+                                               continue;
+                                       sfcp = sp->fcport;
+                                       if (!(sfcp->flags & FCF_TAPE_PRESENT))
+                                               continue;
 
-                               sp = ha->outstanding_cmds[index];
-                               if (!sp)
-                                       continue;
-                               sfcp = sp->fcport;
-                               if (!(sfcp->flags & FCF_TAPE_PRESENT))
-                                       continue;
-
-                               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
-                               break;
+                                       set_bit(ISP_ABORT_NEEDED,
+                                           &ha->dpc_flags);
+                                       break;
+                               }
+                               spin_unlock_irqrestore(&ha->hardware_lock,
+                                   cpu_flags);
                        }
-                       spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags);
-
                        set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
                        start_dpc++;
                }
@@ -2574,8 +2591,9 @@ qla2x00_timer(scsi_qla_host_t *ha)
            test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
            test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
            test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
+           test_bit(VP_DPC_NEEDED, &ha->dpc_flags) ||
            test_bit(RELOGIN_NEEDED, &ha->dpc_flags)))
-               qla2xxx_wake_dpc(ha);
+               qla2xxx_wake_dpc(pha);
 
        qla2x00_restart_timer(ha, WATCH_INTERVAL);
 }
@@ -2592,7 +2610,7 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
                        return 0;
                if (msleep_interruptible(step))
                        break;
-       } while (--iterations >= 0);
+       } while (--iterations > 0);
 
        return -ETIMEDOUT;
 }
@@ -2719,14 +2737,24 @@ qla2x00_module_init(void)
 
        qla2xxx_transport_template =
            fc_attach_transport(&qla2xxx_transport_functions);
-       if (!qla2xxx_transport_template)
+       if (!qla2xxx_transport_template) {
+               kmem_cache_destroy(srb_cachep);
                return -ENODEV;
+       }
+       qla2xxx_transport_vport_template =
+           fc_attach_transport(&qla2xxx_transport_vport_functions);
+       if (!qla2xxx_transport_vport_template) {
+               kmem_cache_destroy(srb_cachep);
+               fc_release_transport(qla2xxx_transport_template);
+               return -ENODEV;
+       }
 
        printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
        ret = pci_register_driver(&qla2xxx_pci_driver);
        if (ret) {
                kmem_cache_destroy(srb_cachep);
                fc_release_transport(qla2xxx_transport_template);
+               fc_release_transport(qla2xxx_transport_vport_template);
        }
        return ret;
 }
@@ -2741,6 +2769,7 @@ qla2x00_module_exit(void)
        qla2x00_release_firmware();
        kmem_cache_destroy(srb_cachep);
        fc_release_transport(qla2xxx_transport_template);
+       fc_release_transport(qla2xxx_transport_vport_template);
 }
 
 module_init(qla2x00_module_init);