block: unify request timeout handling
[safe/jmp/linux-2.6] / drivers / scsi / ibmvscsi / ibmvscsi.c
index 2e9be83..87e09f3 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <asm/firmware.h>
 #include <asm/vio.h>
+#include <asm/firmware.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_srp.h>
 #include "ibmvscsi.h"
 
 /* The values below are somewhat arbitrary default values, but 
 static int max_id = 64;
 static int max_channel = 3;
 static int init_timeout = 5;
-static int max_requests = 50;
+static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
+
+static struct scsi_transport_template *ibmvscsi_transport_template;
 
 #define IBMVSCSI_VERSION "1.5.8"
 
+static struct ibmvscsi_ops *ibmvscsi_ops;
+
 MODULE_DESCRIPTION("IBM Virtual SCSI");
 MODULE_AUTHOR("Dave Boutcher");
 MODULE_LICENSE("GPL");
@@ -121,10 +128,9 @@ static int initialize_event_pool(struct event_pool *pool,
 
        pool->size = size;
        pool->next = 0;
-       pool->events = kmalloc(pool->size * sizeof(*pool->events), GFP_KERNEL);
+       pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL);
        if (!pool->events)
                return -ENOMEM;
-       memset(pool->events, 0x00, pool->size * sizeof(*pool->events));
 
        pool->iu_storage =
            dma_alloc_coherent(hostdata->dev,
@@ -174,9 +180,8 @@ static void release_event_pool(struct event_pool *pool,
                }
        }
        if (in_use)
-               printk(KERN_WARNING
-                      "ibmvscsi: releasing event pool with %d "
-                      "events still in use?\n", in_use);
+               dev_warn(hostdata->dev, "releasing event pool with %d "
+                        "events still in use?\n", in_use);
        kfree(pool->events);
        dma_free_coherent(hostdata->dev,
                          pool->size * sizeof(*pool->iu_storage),
@@ -211,15 +216,13 @@ static void free_event_struct(struct event_pool *pool,
                                       struct srp_event_struct *evt)
 {
        if (!valid_event_struct(pool, evt)) {
-               printk(KERN_ERR
-                      "ibmvscsi: Freeing invalid event_struct %p "
-                      "(not in pool %p)\n", evt, pool->events);
+               dev_err(evt->hostdata->dev, "Freeing invalid event_struct %p "
+                       "(not in pool %p)\n", evt, pool->events);
                return;
        }
        if (atomic_inc_return(&evt->free) != 1) {
-               printk(KERN_ERR
-                      "ibmvscsi: Freeing event_struct %p "
-                      "which is not in use!\n", evt);
+               dev_err(evt->hostdata->dev, "Freeing event_struct %p "
+                       "which is not in use!\n", evt);
                return;
        }
 }
@@ -354,20 +357,19 @@ static void unmap_cmd_data(struct srp_cmd *cmd,
        }
 }
 
-static int map_sg_list(int num_entries, 
-                      struct scatterlist *sg,
+static int map_sg_list(struct scsi_cmnd *cmd, int nseg,
                       struct srp_direct_buf *md)
 {
        int i;
+       struct scatterlist *sg;
        u64 total_length = 0;
 
-       for (i = 0; i < num_entries; ++i) {
+       scsi_for_each_sg(cmd, sg, nseg, i) {
                struct srp_direct_buf *descr = md + i;
-               struct scatterlist *sg_entry = &sg[i];
-               descr->va = sg_dma_address(sg_entry);
-               descr->len = sg_dma_len(sg_entry);
+               descr->va = sg_dma_address(sg);
+               descr->len = sg_dma_len(sg);
                descr->key = 0;
-               total_length += sg_dma_len(sg_entry);
+               total_length += sg_dma_len(sg);
        }
        return total_length;
 }
@@ -388,40 +390,31 @@ static int map_sg_data(struct scsi_cmnd *cmd,
 
        int sg_mapped;
        u64 total_length = 0;
-       struct scatterlist *sg = cmd->request_buffer;
        struct srp_direct_buf *data =
                (struct srp_direct_buf *) srp_cmd->add_data;
        struct srp_indirect_buf *indirect =
                (struct srp_indirect_buf *) data;
 
-       sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL);
-
-       if (sg_mapped == 0)
+       sg_mapped = scsi_dma_map(cmd);
+       if (!sg_mapped)
+               return 1;
+       else if (sg_mapped < 0)
                return 0;
 
        set_srp_direction(cmd, srp_cmd, sg_mapped);
 
        /* special case; we can use a single direct descriptor */
        if (sg_mapped == 1) {
-               data->va = sg_dma_address(&sg[0]);
-               data->len = sg_dma_len(&sg[0]);
-               data->key = 0;
+               map_sg_list(cmd, sg_mapped, data);
                return 1;
        }
 
-       if (sg_mapped > SG_ALL) {
-               printk(KERN_ERR
-                      "ibmvscsi: More than %d mapped sg entries, got %d\n",
-                      SG_ALL, sg_mapped);
-               return 0;
-       }
-
        indirect->table_desc.va = 0;
        indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf);
        indirect->table_desc.key = 0;
 
        if (sg_mapped <= MAX_INDIRECT_BUFS) {
-               total_length = map_sg_list(sg_mapped, sg,
+               total_length = map_sg_list(cmd, sg_mapped,
                                           &indirect->desc_list[0]);
                indirect->len = total_length;
                return 1;
@@ -430,61 +423,29 @@ static int map_sg_data(struct scsi_cmnd *cmd,
        /* get indirect table */
        if (!evt_struct->ext_list) {
                evt_struct->ext_list = (struct srp_direct_buf *)
-                       dma_alloc_coherent(dev, 
+                       dma_alloc_coherent(dev,
                                           SG_ALL * sizeof(struct srp_direct_buf),
                                           &evt_struct->ext_list_token, 0);
                if (!evt_struct->ext_list) {
-                       printk(KERN_ERR
-                              "ibmvscsi: Can't allocate memory for indirect table\n");
+                       if (!firmware_has_feature(FW_FEATURE_CMO))
+                               sdev_printk(KERN_ERR, cmd->device,
+                                           "Can't allocate memory "
+                                           "for indirect table\n");
                        return 0;
-                       
                }
        }
 
-       total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list);        
+       total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list);
 
        indirect->len = total_length;
        indirect->table_desc.va = evt_struct->ext_list_token;
        indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]);
        memcpy(indirect->desc_list, evt_struct->ext_list,
               MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
-       
        return 1;
 }
 
 /**
- * map_single_data: - Maps memory and initializes memory decriptor fields
- * @cmd:       struct scsi_cmnd with the memory to be mapped
- * @srp_cmd:   srp_cmd that contains the memory descriptor
- * @dev:       device for which to map dma memory
- *
- * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
- * Returns 1 on success.
-*/
-static int map_single_data(struct scsi_cmnd *cmd,
-                          struct srp_cmd *srp_cmd, struct device *dev)
-{
-       struct srp_direct_buf *data =
-               (struct srp_direct_buf *) srp_cmd->add_data;
-
-       data->va =
-               dma_map_single(dev, cmd->request_buffer,
-                              cmd->request_bufflen,
-                              DMA_BIDIRECTIONAL);
-       if (dma_mapping_error(data->va)) {
-               printk(KERN_ERR
-                      "ibmvscsi: Unable to map request_buffer for command!\n");
-               return 0;
-       }
-       data->len = cmd->request_bufflen;
-       data->key = 0;
-
-       set_srp_direction(cmd, srp_cmd, 1);
-
-       return 1;
-}
-
-/**
  * map_data_for_srp_cmd: - Calls functions to map data for srp cmds
  * @cmd:       struct scsi_cmnd with the memory to be mapped
  * @srp_cmd:   srp_cmd that contains the memory descriptor
@@ -504,23 +465,83 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
        case DMA_NONE:
                return 1;
        case DMA_BIDIRECTIONAL:
-               printk(KERN_ERR
-                      "ibmvscsi: Can't map DMA_BIDIRECTIONAL to read/write\n");
+               sdev_printk(KERN_ERR, cmd->device,
+                           "Can't map DMA_BIDIRECTIONAL to read/write\n");
                return 0;
        default:
-               printk(KERN_ERR
-                      "ibmvscsi: Unknown data direction 0x%02x; can't map!\n",
-                      cmd->sc_data_direction);
+               sdev_printk(KERN_ERR, cmd->device,
+                           "Unknown data direction 0x%02x; can't map!\n",
+                           cmd->sc_data_direction);
                return 0;
        }
 
-       if (!cmd->request_buffer)
-               return 1;
-       if (cmd->use_sg)
-               return map_sg_data(cmd, evt_struct, srp_cmd, dev);
-       return map_single_data(cmd, srp_cmd, dev);
+       return map_sg_data(cmd, evt_struct, srp_cmd, dev);
 }
 
+/**
+ * purge_requests: Our virtual adapter just shut down.  purge any sent requests
+ * @hostdata:    the adapter
+ */
+static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
+{
+       struct srp_event_struct *tmp_evt, *pos;
+       unsigned long flags;
+
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
+               list_del(&tmp_evt->list);
+               del_timer(&tmp_evt->timer);
+               if (tmp_evt->cmnd) {
+                       tmp_evt->cmnd->result = (error_code << 16);
+                       unmap_cmd_data(&tmp_evt->iu.srp.cmd,
+                                      tmp_evt,
+                                      tmp_evt->hostdata->dev);
+                       if (tmp_evt->cmnd_done)
+                               tmp_evt->cmnd_done(tmp_evt->cmnd);
+               } else if (tmp_evt->done)
+                       tmp_evt->done(tmp_evt);
+               free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+       }
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+}
+
+/**
+ * ibmvscsi_reset_host - Reset the connection to the server
+ * @hostdata:  struct ibmvscsi_host_data to reset
+*/
+static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
+{
+       scsi_block_requests(hostdata->host);
+       atomic_set(&hostdata->request_limit, 0);
+
+       purge_requests(hostdata, DID_ERROR);
+       if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
+           (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) ||
+           (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
+               atomic_set(&hostdata->request_limit, -1);
+               dev_err(hostdata->dev, "error after reset\n");
+       }
+
+       scsi_unblock_requests(hostdata->host);
+}
+
+/**
+ * ibmvscsi_timeout - Internal command timeout handler
+ * @evt_struct:        struct srp_event_struct that timed out
+ *
+ * Called when an internally generated command times out
+*/
+static void ibmvscsi_timeout(struct srp_event_struct *evt_struct)
+{
+       struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+
+       dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
+               evt_struct->iu.srp.cmd.opcode);
+
+       ibmvscsi_reset_host(hostdata);
+}
+
+
 /* ------------------------------------------------------------
  * Routines for sending and receiving SRPs
  */
@@ -528,24 +549,65 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
  * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
  * @evt_struct:        evt_struct to be sent
  * @hostdata:  ibmvscsi_host_data of host
+ * @timeout:   timeout in seconds - 0 means do not time command
  *
  * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
  * Note that this routine assumes that host_lock is held for synchronization
 */
 static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
-                                  struct ibmvscsi_host_data *hostdata)
+                                  struct ibmvscsi_host_data *hostdata,
+                                  unsigned long timeout)
 {
        u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
+       int request_status = 0;
        int rc;
 
-       /* If we have exhausted our request limit, just fail this request.
+       /* If we have exhausted our request limit, just fail this request,
+        * unless it is for a reset or abort.
         * Note that there are rare cases involving driver generated requests 
         * (such as task management requests) that the mid layer may think we
         * can handle more requests (can_queue) when we actually can't
         */
-       if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) &&
-           (atomic_dec_if_positive(&hostdata->request_limit) < 0))
-               goto send_error;
+       if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
+               request_status =
+                       atomic_dec_if_positive(&hostdata->request_limit);
+               /* If request limit was -1 when we started, it is now even
+                * less than that
+                */
+               if (request_status < -1)
+                       goto send_error;
+               /* Otherwise, we may have run out of requests. */
+               /* If request limit was 0 when we started the adapter is in the
+                * process of performing a login with the server adapter, or
+                * we may have run out of requests.
+                */
+               else if (request_status == -1 &&
+                        evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
+                       goto send_busy;
+               /* Abort and reset calls should make it through.
+                * Nothing except abort and reset should use the last two
+                * slots unless we had two or less to begin with.
+                */
+               else if (request_status < 2 &&
+                        evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) {
+                       /* In the case that we have less than two requests
+                        * available, check the server limit as a combination
+                        * of the request limit and the number of requests
+                        * in-flight (the size of the send list).  If the
+                        * server limit is greater than 2, return busy so
+                        * that the last two are reserved for reset and abort.
+                        */
+                       int server_limit = request_status;
+                       struct srp_event_struct *tmp_evt;
+
+                       list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+                               server_limit++;
+                       }
+
+                       if (server_limit > 2)
+                               goto send_busy;
+               }
+       }
 
        /* Copy the IU into the transfer area */
        *evt_struct->xfer_iu = evt_struct->iu;
@@ -557,22 +619,55 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
         */
        list_add_tail(&evt_struct->list, &hostdata->sent);
 
+       init_timer(&evt_struct->timer);
+       if (timeout) {
+               evt_struct->timer.data = (unsigned long) evt_struct;
+               evt_struct->timer.expires = jiffies + (timeout * HZ);
+               evt_struct->timer.function = (void (*)(unsigned long))ibmvscsi_timeout;
+               add_timer(&evt_struct->timer);
+       }
+
        if ((rc =
-            ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
+            ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
                list_del(&evt_struct->list);
+               del_timer(&evt_struct->timer);
 
-               printk(KERN_ERR "ibmvscsi: send error %d\n",
-                      rc);
+               /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
+                * Firmware will send a CRQ with a transport event (0xFF) to
+                * tell this client what has happened to the transport.  This
+                * will be handled in ibmvscsi_handle_crq()
+                */
+               if (rc == H_CLOSED) {
+                       dev_warn(hostdata->dev, "send warning. "
+                                "Receive queue closed, will retry.\n");
+                       goto send_busy;
+               }
+               dev_err(hostdata->dev, "send error %d\n", rc);
+               atomic_inc(&hostdata->request_limit);
                goto send_error;
        }
 
        return 0;
 
+ send_busy:
+       unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
+
+       free_event_struct(&hostdata->pool, evt_struct);
+       if (request_status != -1)
+               atomic_inc(&hostdata->request_limit);
+       return SCSI_MLQUEUE_HOST_BUSY;
+
  send_error:
        unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
 
+       if (evt_struct->cmnd != NULL) {
+               evt_struct->cmnd->result = DID_ERROR << 16;
+               evt_struct->cmnd_done(evt_struct->cmnd);
+       } else if (evt_struct->done)
+               evt_struct->done(evt_struct);
+
        free_event_struct(&hostdata->pool, evt_struct);
-       return SCSI_MLQUEUE_HOST_BUSY;
+       return 0;
 }
 
 /**
@@ -589,13 +684,12 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
 
        if (unlikely(rsp->opcode != SRP_RSP)) {
                if (printk_ratelimit())
-                       printk(KERN_WARNING 
-                              "ibmvscsi: bad SRP RSP type %d\n",
-                              rsp->opcode);
+                       dev_warn(evt_struct->hostdata->dev,
+                                "bad SRP RSP type %d\n", rsp->opcode);
        }
        
        if (cmnd) {
-               cmnd->result = rsp->status;
+               cmnd->result |= rsp->status;
                if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
                        memcpy(cmnd->sense_buffer,
                               rsp->data,
@@ -605,9 +699,9 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
                               evt_struct->hostdata->dev);
 
                if (rsp->flags & SRP_RSP_FLAG_DOOVER)
-                       cmnd->resid = rsp->data_out_res_cnt;
+                       scsi_set_resid(cmnd, rsp->data_out_res_cnt);
                else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
-                       cmnd->resid = rsp->data_in_res_cnt;
+                       scsi_set_resid(cmnd, rsp->data_in_res_cnt);
        }
 
        if (evt_struct->cmnd_done)
@@ -635,11 +729,11 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        struct srp_cmd *srp_cmd;
        struct srp_event_struct *evt_struct;
        struct srp_indirect_buf *indirect;
-       struct ibmvscsi_host_data *hostdata =
-               (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata;
+       struct ibmvscsi_host_data *hostdata = shost_priv(cmnd->device->host);
        u16 lun = lun_from_dev(cmnd->device);
        u8 out_fmt, in_fmt;
 
+       cmnd->result = (DID_OK << 16);
        evt_struct = get_event_struct(&hostdata->pool);
        if (!evt_struct)
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -648,11 +742,13 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        srp_cmd = &evt_struct->iu.srp.cmd;
        memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
        srp_cmd->opcode = SRP_CMD;
-       memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
+       memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
        srp_cmd->lun = ((u64) lun) << 48;
 
        if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
-               printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n");
+               if (!firmware_has_feature(FW_FEATURE_CMO))
+                       sdev_printk(KERN_ERR, cmnd->device,
+                                   "couldn't convert cmd to srp_cmd\n");
                free_event_struct(&hostdata->pool, evt_struct);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
@@ -660,7 +756,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        init_event_struct(evt_struct,
                          handle_cmd_rsp,
                          VIOSRP_SRP_FORMAT,
-                         cmnd->timeout_per_command/HZ);
+                         cmnd->request->timeout/HZ);
 
        evt_struct->cmnd = cmnd;
        evt_struct->cmnd_done = done;
@@ -677,7 +773,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
                        offsetof(struct srp_indirect_buf, desc_list);
        }
 
-       return ibmvscsi_send_srp_event(evt_struct, hostdata);
+       return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
 }
 
 /* ------------------------------------------------------------
@@ -699,16 +795,16 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
                         DMA_BIDIRECTIONAL);
 
        if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
-               printk("ibmvscsi: error %d getting adapter info\n",
-                      evt_struct->xfer_iu->mad.adapter_info.common.status);
+               dev_err(hostdata->dev, "error %d getting adapter info\n",
+                       evt_struct->xfer_iu->mad.adapter_info.common.status);
        } else {
-               printk("ibmvscsi: host srp version: %s, "
-                      "host partition %s (%d), OS %d, max io %u\n",
-                      hostdata->madapter_info.srp_version,
-                      hostdata->madapter_info.partition_name,
-                      hostdata->madapter_info.partition_number,
-                      hostdata->madapter_info.os_type,
-                      hostdata->madapter_info.port_max_txu[0]);
+               dev_info(hostdata->dev, "host srp version: %s, "
+                        "host partition %s (%d), OS %d, max io %u\n",
+                        hostdata->madapter_info.srp_version,
+                        hostdata->madapter_info.partition_name,
+                        hostdata->madapter_info.partition_number,
+                        hostdata->madapter_info.os_type,
+                        hostdata->madapter_info.port_max_txu[0]);
                
                if (hostdata->madapter_info.port_max_txu[0]) 
                        hostdata->host->max_sectors = 
@@ -716,11 +812,10 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
                
                if (hostdata->madapter_info.os_type == 3 &&
                    strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
-                       printk("ibmvscsi: host (Ver. %s) doesn't support large"
-                              "transfers\n",
-                              hostdata->madapter_info.srp_version);
-                       printk("ibmvscsi: limiting scatterlists to %d\n",
-                              MAX_INDIRECT_BUFS);
+                       dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
+                               hostdata->madapter_info.srp_version);
+                       dev_err(hostdata->dev, "limiting scatterlists to %d\n",
+                               MAX_INDIRECT_BUFS);
                        hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
                }
        }
@@ -739,19 +834,20 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
 {
        struct viosrp_adapter_info *req;
        struct srp_event_struct *evt_struct;
+       unsigned long flags;
        dma_addr_t addr;
 
        evt_struct = get_event_struct(&hostdata->pool);
        if (!evt_struct) {
-               printk(KERN_ERR "ibmvscsi: couldn't allocate an event "
-                      "for ADAPTER_INFO_REQ!\n");
+               dev_err(hostdata->dev,
+                       "couldn't allocate an event for ADAPTER_INFO_REQ!\n");
                return;
        }
 
        init_event_struct(evt_struct,
                          adapter_info_rsp,
                          VIOSRP_MAD_FORMAT,
-                         init_timeout * HZ);
+                         init_timeout);
        
        req = &evt_struct->iu.mad.adapter_info;
        memset(req, 0x00, sizeof(*req));
@@ -763,21 +859,24 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
                                            sizeof(hostdata->madapter_info),
                                            DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(req->buffer)) {
-               printk(KERN_ERR
-                      "ibmvscsi: Unable to map request_buffer "
-                      "for adapter_info!\n");
+       if (dma_mapping_error(hostdata->dev, req->buffer)) {
+               if (!firmware_has_feature(FW_FEATURE_CMO))
+                       dev_err(hostdata->dev,
+                               "Unable to map request_buffer for "
+                               "adapter_info!\n");
                free_event_struct(&hostdata->pool, evt_struct);
                return;
        }
        
-       if (ibmvscsi_send_srp_event(evt_struct, hostdata)) {
-               printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n");
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       if (ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2)) {
+               dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
                dma_unmap_single(hostdata->dev,
                                 addr,
                                 sizeof(hostdata->madapter_info),
                                 DMA_BIDIRECTIONAL);
        }
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
 };
 
 /**
@@ -794,39 +893,31 @@ static void login_rsp(struct srp_event_struct *evt_struct)
        case SRP_LOGIN_RSP:     /* it worked! */
                break;
        case SRP_LOGIN_REJ:     /* refused! */
-               printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n",
-                      evt_struct->xfer_iu->srp.login_rej.reason);
+               dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
+                        evt_struct->xfer_iu->srp.login_rej.reason);
                /* Login failed.  */
                atomic_set(&hostdata->request_limit, -1);
                return;
        default:
-               printk(KERN_ERR
-                      "ibmvscsi: Invalid login response typecode 0x%02x!\n",
-                      evt_struct->xfer_iu->srp.login_rsp.opcode);
+               dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
+                       evt_struct->xfer_iu->srp.login_rsp.opcode);
                /* Login failed.  */
                atomic_set(&hostdata->request_limit, -1);
                return;
        }
 
-       printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
+       dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
 
-       if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta >
-           (max_requests - 2))
-               evt_struct->xfer_iu->srp.login_rsp.req_lim_delta =
-                   max_requests - 2;
+       if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0)
+               dev_err(hostdata->dev, "Invalid request_limit.\n");
 
-       /* Now we know what the real request-limit is */
+       /* Now we know what the real request-limit is.
+        * This value is set rather than added to request_limit because
+        * request_limit could have been set to -1 by this client.
+        */
        atomic_set(&hostdata->request_limit,
                   evt_struct->xfer_iu->srp.login_rsp.req_lim_delta);
 
-       hostdata->host->can_queue =
-           evt_struct->xfer_iu->srp.login_rsp.req_lim_delta - 2;
-
-       if (hostdata->host->can_queue < 1) {
-               printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n");
-               return;
-       }
-
        /* If we had any pending I/Os, kick them */
        scsi_unblock_requests(hostdata->host);
 
@@ -847,15 +938,14 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
        struct srp_login_req *login;
        struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
        if (!evt_struct) {
-               printk(KERN_ERR
-                      "ibmvscsi: couldn't allocate an event for login req!\n");
+               dev_err(hostdata->dev, "couldn't allocate an event for login req!\n");
                return FAILED;
        }
 
        init_event_struct(evt_struct,
                          login_rsp,
                          VIOSRP_SRP_FORMAT,
-                         init_timeout * HZ);
+                         init_timeout);
 
        login = &evt_struct->iu.srp.login_req;
        memset(login, 0x00, sizeof(struct srp_login_req));
@@ -864,14 +954,15 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
        login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
        
        spin_lock_irqsave(hostdata->host->host_lock, flags);
-       /* Start out with a request limit of 1, since this is negotiated in
-        * the login request we are just sending
+       /* Start out with a request limit of 0, since this is negotiated in
+        * the login request we are just sending and login requests always
+        * get sent by the driver regardless of request_limit.
         */
-       atomic_set(&hostdata->request_limit, 1);
+       atomic_set(&hostdata->request_limit, 0);
 
-       rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-       printk("ibmvscsic: sent SRP login\n");
+       dev_info(hostdata->dev, "sent SRP login\n");
        return rc;
 };
 
@@ -896,8 +987,7 @@ static void sync_completion(struct srp_event_struct *evt_struct)
  */
 static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
 {
-       struct ibmvscsi_host_data *hostdata =
-           (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+       struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
        struct srp_tsk_mgmt *tsk_mgmt;
        struct srp_event_struct *evt;
        struct srp_event_struct *tmp_evt, *found_evt;
@@ -905,65 +995,81 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
        int rsp_rc;
        unsigned long flags;
        u16 lun = lun_from_dev(cmd->device);
+       unsigned long wait_switch = 0;
 
        /* First, find this command in our sent list so we can figure
         * out the correct tag
         */
        spin_lock_irqsave(hostdata->host->host_lock, flags);
-       found_evt = NULL;
-       list_for_each_entry(tmp_evt, &hostdata->sent, list) {
-               if (tmp_evt->cmnd == cmd) {
-                       found_evt = tmp_evt;
-                       break;
+       wait_switch = jiffies + (init_timeout * HZ);
+       do {
+               found_evt = NULL;
+               list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+                       if (tmp_evt->cmnd == cmd) {
+                               found_evt = tmp_evt;
+                               break;
+                       }
                }
-       }
 
-       if (!found_evt) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               return FAILED;
-       }
+               if (!found_evt) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       return SUCCESS;
+               }
 
-       evt = get_event_struct(&hostdata->pool);
-       if (evt == NULL) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n");
-               return FAILED;
-       }
+               evt = get_event_struct(&hostdata->pool);
+               if (evt == NULL) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       sdev_printk(KERN_ERR, cmd->device,
+                               "failed to allocate abort event\n");
+                       return FAILED;
+               }
        
-       init_event_struct(evt,
-                         sync_completion,
-                         VIOSRP_SRP_FORMAT,
-                         init_timeout * HZ);
+               init_event_struct(evt,
+                                 sync_completion,
+                                 VIOSRP_SRP_FORMAT,
+                                 init_timeout);
 
-       tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+               tsk_mgmt = &evt->iu.srp.tsk_mgmt;
        
-       /* Set up an abort SRP command */
-       memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-       tsk_mgmt->opcode = SRP_TSK_MGMT;
-       tsk_mgmt->lun = ((u64) lun) << 48;
-       tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
-       tsk_mgmt->task_tag = (u64) found_evt;
-
-       printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n",
-              tsk_mgmt->lun, tsk_mgmt->task_tag);
-
-       evt->sync_srp = &srp_rsp;
-       init_completion(&evt->comp);
-       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+               /* Set up an abort SRP command */
+               memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+               tsk_mgmt->opcode = SRP_TSK_MGMT;
+               tsk_mgmt->lun = ((u64) lun) << 48;
+               tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
+               tsk_mgmt->task_tag = (u64) found_evt;
+
+               evt->sync_srp = &srp_rsp;
+
+               init_completion(&evt->comp);
+               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+
+               if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
+                       break;
+
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+               msleep(10);
+               spin_lock_irqsave(hostdata->host->host_lock, flags);
+       } while (time_before(jiffies, wait_switch));
+
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
        if (rsp_rc != 0) {
-               printk(KERN_ERR "ibmvscsi: failed to send abort() event\n");
+               sdev_printk(KERN_ERR, cmd->device,
+                           "failed to send abort() event. rc=%d\n", rsp_rc);
                return FAILED;
        }
 
+       sdev_printk(KERN_INFO, cmd->device,
+                    "aborting command. lun 0x%lx, tag 0x%lx\n",
+                   (((u64) lun) << 48), (u64) found_evt);
+
        wait_for_completion(&evt->comp);
 
        /* make sure we got a good response */
        if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
                if (printk_ratelimit())
-                       printk(KERN_WARNING 
-                              "ibmvscsi: abort bad SRP RSP type %d\n",
-                              srp_rsp.srp.rsp.opcode);
+                       sdev_printk(KERN_WARNING, cmd->device, "abort bad SRP RSP type %d\n",
+                                   srp_rsp.srp.rsp.opcode);
                return FAILED;
        }
 
@@ -974,10 +1080,9 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
 
        if (rsp_rc) {
                if (printk_ratelimit())
-                       printk(KERN_WARNING 
-                              "ibmvscsi: abort code %d for task tag 0x%lx\n",
-                              rsp_rc,
-                              tsk_mgmt->task_tag);
+                       sdev_printk(KERN_WARNING, cmd->device,
+                                   "abort code %d for task tag 0x%lx\n",
+                                   rsp_rc, tsk_mgmt->task_tag);
                return FAILED;
        }
 
@@ -996,15 +1101,13 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
 
        if (found_evt == NULL) {
                spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               printk(KERN_INFO
-                      "ibmvscsi: aborted task tag 0x%lx completed\n",
-                      tsk_mgmt->task_tag);
+               sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%lx completed\n",
+                           tsk_mgmt->task_tag);
                return SUCCESS;
        }
 
-       printk(KERN_INFO
-              "ibmvscsi: successfully aborted task tag 0x%lx\n",
-              tsk_mgmt->task_tag);
+       sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%lx\n",
+                   tsk_mgmt->task_tag);
 
        cmd->result = (DID_ABORT << 16);
        list_del(&found_evt->list);
@@ -1023,9 +1126,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
  */
 static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
 {
-       struct ibmvscsi_host_data *hostdata =
-           (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
-
+       struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
        struct srp_tsk_mgmt *tsk_mgmt;
        struct srp_event_struct *evt;
        struct srp_event_struct *tmp_evt, *pos;
@@ -1033,48 +1134,63 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
        int rsp_rc;
        unsigned long flags;
        u16 lun = lun_from_dev(cmd->device);
+       unsigned long wait_switch = 0;
 
        spin_lock_irqsave(hostdata->host->host_lock, flags);
-       evt = get_event_struct(&hostdata->pool);
-       if (evt == NULL) {
-               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-               printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n");
-               return FAILED;
-       }
+       wait_switch = jiffies + (init_timeout * HZ);
+       do {
+               evt = get_event_struct(&hostdata->pool);
+               if (evt == NULL) {
+                       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+                       sdev_printk(KERN_ERR, cmd->device,
+                               "failed to allocate reset event\n");
+                       return FAILED;
+               }
        
-       init_event_struct(evt,
-                         sync_completion,
-                         VIOSRP_SRP_FORMAT,
-                         init_timeout * HZ);
+               init_event_struct(evt,
+                                 sync_completion,
+                                 VIOSRP_SRP_FORMAT,
+                                 init_timeout);
 
-       tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+               tsk_mgmt = &evt->iu.srp.tsk_mgmt;
 
-       /* Set up a lun reset SRP command */
-       memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-       tsk_mgmt->opcode = SRP_TSK_MGMT;
-       tsk_mgmt->lun = ((u64) lun) << 48;
-       tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
+               /* Set up a lun reset SRP command */
+               memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+               tsk_mgmt->opcode = SRP_TSK_MGMT;
+               tsk_mgmt->lun = ((u64) lun) << 48;
+               tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
+
+               evt->sync_srp = &srp_rsp;
 
-       printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n",
-              tsk_mgmt->lun);
+               init_completion(&evt->comp);
+               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+
+               if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
+                       break;
+
+               spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+               msleep(10);
+               spin_lock_irqsave(hostdata->host->host_lock, flags);
+       } while (time_before(jiffies, wait_switch));
 
-       evt->sync_srp = &srp_rsp;
-       init_completion(&evt->comp);
-       rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
        if (rsp_rc != 0) {
-               printk(KERN_ERR "ibmvscsi: failed to send reset event\n");
+               sdev_printk(KERN_ERR, cmd->device,
+                           "failed to send reset event. rc=%d\n", rsp_rc);
                return FAILED;
        }
 
+       sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+                   (((u64) lun) << 48));
+
        wait_for_completion(&evt->comp);
 
        /* make sure we got a good response */
        if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
                if (printk_ratelimit())
-                       printk(KERN_WARNING 
-                              "ibmvscsi: reset bad SRP RSP type %d\n",
-                              srp_rsp.srp.rsp.opcode);
+                       sdev_printk(KERN_WARNING, cmd->device, "reset bad SRP RSP type %d\n",
+                                   srp_rsp.srp.rsp.opcode);
                return FAILED;
        }
 
@@ -1085,9 +1201,9 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
 
        if (rsp_rc) {
                if (printk_ratelimit())
-                       printk(KERN_WARNING 
-                              "ibmvscsi: reset code %d for task tag 0x%lx\n",
-                              rsp_rc, tsk_mgmt->task_tag);
+                       sdev_printk(KERN_WARNING, cmd->device,
+                                   "reset code %d for task tag 0x%lx\n",
+                                   rsp_rc, tsk_mgmt->task_tag);
                return FAILED;
        }
 
@@ -1116,32 +1232,29 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
 }
 
 /**
- * purge_requests: Our virtual adapter just shut down.  purge any sent requests
- * @hostdata:    the adapter
- */
-static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
+ * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
+ * @cmd:       struct scsi_cmnd having problems
+*/
+static int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
 {
-       struct srp_event_struct *tmp_evt, *pos;
-       unsigned long flags;
+       unsigned long wait_switch = 0;
+       struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
 
-       spin_lock_irqsave(hostdata->host->host_lock, flags);
-       list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
-               list_del(&tmp_evt->list);
-               if (tmp_evt->cmnd) {
-                       tmp_evt->cmnd->result = (error_code << 16);
-                       unmap_cmd_data(&tmp_evt->iu.srp.cmd, 
-                                      tmp_evt, 
-                                      tmp_evt->hostdata->dev);
-                       if (tmp_evt->cmnd_done)
-                               tmp_evt->cmnd_done(tmp_evt->cmnd);
-               } else {
-                       if (tmp_evt->done) {
-                               tmp_evt->done(tmp_evt);
-                       }
-               }
-               free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+       dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
+
+       ibmvscsi_reset_host(hostdata);
+
+       for (wait_switch = jiffies + (init_timeout * HZ);
+            time_before(jiffies, wait_switch) &&
+                    atomic_read(&hostdata->request_limit) < 2;) {
+
+               msleep(10);
        }
-       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
+       if (atomic_read(&hostdata->request_limit) <= 0)
+               return FAILED;
+
+       return SUCCESS;
 }
 
 /**
@@ -1153,6 +1266,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
 void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                         struct ibmvscsi_host_data *hostdata)
 {
+       long rc;
        unsigned long flags;
        struct srp_event_struct *evt_struct =
            (struct srp_event_struct *)crq->IU_data_ptr;
@@ -1160,61 +1274,63 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
        case 0xC0:              /* initialization */
                switch (crq->format) {
                case 0x01:      /* Initialization message */
-                       printk(KERN_INFO "ibmvscsi: partner initialized\n");
+                       dev_info(hostdata->dev, "partner initialized\n");
                        /* Send back a response */
-                       if (ibmvscsi_send_crq(hostdata,
-                                             0xC002000000000000LL, 0) == 0) {
+                       if ((rc = ibmvscsi_ops->send_crq(hostdata,
+                                                        0xC002000000000000LL, 0)) == 0) {
                                /* Now login */
                                send_srp_login(hostdata);
                        } else {
-                               printk(KERN_ERR
-                                      "ibmvscsi: Unable to send init rsp\n");
+                               dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
                        }
 
                        break;
                case 0x02:      /* Initialization response */
-                       printk(KERN_INFO
-                              "ibmvscsi: partner initialization complete\n");
+                       dev_info(hostdata->dev, "partner initialization complete\n");
 
                        /* Now login */
                        send_srp_login(hostdata);
                        break;
                default:
-                       printk(KERN_ERR "ibmvscsi: unknown crq message type\n");
+                       dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
                }
                return;
        case 0xFF:      /* Hypervisor telling us the connection is closed */
                scsi_block_requests(hostdata->host);
+               atomic_set(&hostdata->request_limit, 0);
                if (crq->format == 0x06) {
                        /* We need to re-setup the interpartition connection */
-                       printk(KERN_INFO
-                              "ibmvscsi: Re-enabling adapter!\n");
-                       atomic_set(&hostdata->request_limit, -1);
+                       dev_info(hostdata->dev, "Re-enabling adapter!\n");
                        purge_requests(hostdata, DID_REQUEUE);
-                       if (ibmvscsi_reenable_crq_queue(&hostdata->queue,
-                                                       hostdata) == 0)
-                               if (ibmvscsi_send_crq(hostdata,
-                                                     0xC001000000000000LL, 0))
-                                       printk(KERN_ERR
-                                              "ibmvscsi: transmit error after"
-                                              " enable\n");
+                       if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
+                                                             hostdata)) ||
+                           (ibmvscsi_ops->send_crq(hostdata,
+                                                   0xC001000000000000LL, 0))) {
+                                       atomic_set(&hostdata->request_limit,
+                                                  -1);
+                                       dev_err(hostdata->dev, "error after enable\n");
+                       }
                } else {
-                       printk(KERN_INFO
-                              "ibmvscsi: Virtual adapter failed rc %d!\n",
-                              crq->format);
+                       dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
+                               crq->format);
 
-                       atomic_set(&hostdata->request_limit, -1);
                        purge_requests(hostdata, DID_ERROR);
-                       ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+                       if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
+                                                          hostdata)) ||
+                           (ibmvscsi_ops->send_crq(hostdata,
+                                                   0xC001000000000000LL, 0))) {
+                                       atomic_set(&hostdata->request_limit,
+                                                  -1);
+                                       dev_err(hostdata->dev, "error after reset\n");
+                       }
                }
                scsi_unblock_requests(hostdata->host);
                return;
        case 0x80:              /* real payload */
                break;
        default:
-               printk(KERN_ERR
-                      "ibmvscsi: got an invalid message type 0x%02x\n",
-                      crq->valid);
+               dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
+                       crq->valid);
                return;
        }
 
@@ -1223,16 +1339,14 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
         * actually sent
         */
        if (!valid_event_struct(&hostdata->pool, evt_struct)) {
-               printk(KERN_ERR
-                      "ibmvscsi: returned correlation_token 0x%p is invalid!\n",
+               dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n",
                       (void *)crq->IU_data_ptr);
                return;
        }
 
        if (atomic_read(&evt_struct->free)) {
-               printk(KERN_ERR
-                      "ibmvscsi: received duplicate  correlation_token 0x%p!\n",
-                      (void *)crq->IU_data_ptr);
+               dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n",
+                       (void *)crq->IU_data_ptr);
                return;
        }
 
@@ -1240,11 +1354,14 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
                           &hostdata->request_limit);
 
+       del_timer(&evt_struct->timer);
+
+       if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd)
+               evt_struct->cmnd->result = DID_ERROR << 16;
        if (evt_struct->done)
                evt_struct->done(evt_struct);
        else
-               printk(KERN_ERR
-                      "ibmvscsi: returned done() is NULL; not running it!\n");
+               dev_err(hostdata->dev, "returned done() is NULL; not running it!\n");
 
        /*
         * Lock the host_lock before messing with these structures, since we
@@ -1265,20 +1382,20 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
 {
        struct viosrp_host_config *host_config;
        struct srp_event_struct *evt_struct;
+       unsigned long flags;
        dma_addr_t addr;
        int rc;
 
        evt_struct = get_event_struct(&hostdata->pool);
        if (!evt_struct) {
-               printk(KERN_ERR
-                      "ibmvscsi: could't allocate event for HOST_CONFIG!\n");
+               dev_err(hostdata->dev, "couldn't allocate event for HOST_CONFIG!\n");
                return -1;
        }
 
        init_event_struct(evt_struct,
                          sync_completion,
                          VIOSRP_MAD_FORMAT,
-                         init_timeout * HZ);
+                         init_timeout);
 
        host_config = &evt_struct->iu.mad.host_config;
 
@@ -1290,15 +1407,18 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
                                                    length,
                                                    DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(host_config->buffer)) {
-               printk(KERN_ERR
-                      "ibmvscsi: dma_mapping error " "getting host config\n");
+       if (dma_mapping_error(hostdata->dev, host_config->buffer)) {
+               if (!firmware_has_feature(FW_FEATURE_CMO))
+                       dev_err(hostdata->dev,
+                               "dma_mapping error getting host config\n");
                free_event_struct(&hostdata->pool, evt_struct);
                return -1;
        }
 
        init_completion(&evt_struct->comp);
-       rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
        if (rc == 0)
                wait_for_completion(&evt_struct->comp);
        dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
@@ -1306,14 +1426,54 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
        return rc;
 }
 
+/**
+ * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
+ * @sdev:      struct scsi_device device to configure
+ *
+ * Enable allow_restart for a device if it is a disk.  Adjust the
+ * queue_depth here also as is required by the documentation for
+ * struct scsi_host_template.
+ */
+static int ibmvscsi_slave_configure(struct scsi_device *sdev)
+{
+       struct Scsi_Host *shost = sdev->host;
+       unsigned long lock_flags = 0;
+
+       spin_lock_irqsave(shost->host_lock, lock_flags);
+       if (sdev->type == TYPE_DISK) {
+               sdev->allow_restart = 1;
+               sdev->timeout = 60 * HZ;
+       }
+       scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
+       spin_unlock_irqrestore(shost->host_lock, lock_flags);
+       return 0;
+}
+
+/**
+ * ibmvscsi_change_queue_depth - Change the device's queue depth
+ * @sdev:      scsi device struct
+ * @qdepth:    depth to set
+ *
+ * Return value:
+ *     actual depth set
+ **/
+static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+       if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
+               qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
+
+       scsi_adjust_queue_depth(sdev, 0, qdepth);
+       return sdev->queue_depth;
+}
+
 /* ------------------------------------------------------------
  * sysfs attributes
  */
-static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf)
+static ssize_t show_host_srp_version(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
-       struct ibmvscsi_host_data *hostdata =
-           (struct ibmvscsi_host_data *)shost->hostdata;
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
        len = snprintf(buf, PAGE_SIZE, "%s\n",
@@ -1321,7 +1481,7 @@ static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf)
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_srp_version = {
+static struct device_attribute ibmvscsi_host_srp_version = {
        .attr = {
                 .name = "srp_version",
                 .mode = S_IRUGO,
@@ -1329,12 +1489,12 @@ static struct class_device_attribute ibmvscsi_host_srp_version = {
        .show = show_host_srp_version,
 };
 
-static ssize_t show_host_partition_name(struct class_device *class_dev,
+static ssize_t show_host_partition_name(struct device *dev,
+                                       struct device_attribute *attr,
                                        char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
-       struct ibmvscsi_host_data *hostdata =
-           (struct ibmvscsi_host_data *)shost->hostdata;
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
        len = snprintf(buf, PAGE_SIZE, "%s\n",
@@ -1342,7 +1502,7 @@ static ssize_t show_host_partition_name(struct class_device *class_dev,
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_partition_name = {
+static struct device_attribute ibmvscsi_host_partition_name = {
        .attr = {
                 .name = "partition_name",
                 .mode = S_IRUGO,
@@ -1350,12 +1510,12 @@ static struct class_device_attribute ibmvscsi_host_partition_name = {
        .show = show_host_partition_name,
 };
 
-static ssize_t show_host_partition_number(struct class_device *class_dev,
+static ssize_t show_host_partition_number(struct device *dev,
+                                         struct device_attribute *attr,
                                          char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
-       struct ibmvscsi_host_data *hostdata =
-           (struct ibmvscsi_host_data *)shost->hostdata;
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
        len = snprintf(buf, PAGE_SIZE, "%d\n",
@@ -1363,7 +1523,7 @@ static ssize_t show_host_partition_number(struct class_device *class_dev,
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_partition_number = {
+static struct device_attribute ibmvscsi_host_partition_number = {
        .attr = {
                 .name = "partition_number",
                 .mode = S_IRUGO,
@@ -1371,11 +1531,11 @@ static struct class_device_attribute ibmvscsi_host_partition_number = {
        .show = show_host_partition_number,
 };
 
-static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf)
+static ssize_t show_host_mad_version(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
-       struct ibmvscsi_host_data *hostdata =
-           (struct ibmvscsi_host_data *)shost->hostdata;
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
        len = snprintf(buf, PAGE_SIZE, "%d\n",
@@ -1383,7 +1543,7 @@ static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf)
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_mad_version = {
+static struct device_attribute ibmvscsi_host_mad_version = {
        .attr = {
                 .name = "mad_version",
                 .mode = S_IRUGO,
@@ -1391,18 +1551,18 @@ static struct class_device_attribute ibmvscsi_host_mad_version = {
        .show = show_host_mad_version,
 };
 
-static ssize_t show_host_os_type(struct class_device *class_dev, char *buf)
+static ssize_t show_host_os_type(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
-       struct ibmvscsi_host_data *hostdata =
-           (struct ibmvscsi_host_data *)shost->hostdata;
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
        int len;
 
        len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
        return len;
 }
 
-static struct class_device_attribute ibmvscsi_host_os_type = {
+static struct device_attribute ibmvscsi_host_os_type = {
        .attr = {
                 .name = "os_type",
                 .mode = S_IRUGO,
@@ -1410,11 +1570,11 @@ static struct class_device_attribute ibmvscsi_host_os_type = {
        .show = show_host_os_type,
 };
 
-static ssize_t show_host_config(struct class_device *class_dev, char *buf)
+static ssize_t show_host_config(struct device *dev,
+                               struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(class_dev);
-       struct ibmvscsi_host_data *hostdata =
-           (struct ibmvscsi_host_data *)shost->hostdata;
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 
        /* returns null-terminated host config data */
        if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
@@ -1423,7 +1583,7 @@ static ssize_t show_host_config(struct class_device *class_dev, char *buf)
                return 0;
 }
 
-static struct class_device_attribute ibmvscsi_host_config = {
+static struct device_attribute ibmvscsi_host_config = {
        .attr = {
                 .name = "config",
                 .mode = S_IRUGO,
@@ -1431,7 +1591,7 @@ static struct class_device_attribute ibmvscsi_host_config = {
        .show = show_host_config,
 };
 
-static struct class_device_attribute *ibmvscsi_attrs[] = {
+static struct device_attribute *ibmvscsi_attrs[] = {
        &ibmvscsi_host_srp_version,
        &ibmvscsi_host_partition_name,
        &ibmvscsi_host_partition_number,
@@ -1451,8 +1611,11 @@ static struct scsi_host_template driver_template = {
        .queuecommand = ibmvscsi_queuecommand,
        .eh_abort_handler = ibmvscsi_eh_abort_handler,
        .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
-       .cmd_per_lun = 16,
-       .can_queue = 1,         /* Updated after SRP_LOGIN */
+       .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
+       .slave_configure = ibmvscsi_slave_configure,
+       .change_queue_depth = ibmvscsi_change_queue_depth,
+       .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
+       .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
        .this_id = -1,
        .sg_tablesize = SG_ALL,
        .use_clustering = ENABLE_CLUSTERING,
@@ -1460,6 +1623,26 @@ static struct scsi_host_template driver_template = {
 };
 
 /**
+ * ibmvscsi_get_desired_dma - Calculate IO memory desired by the driver
+ *
+ * @vdev: struct vio_dev for the device whose desired IO mem is to be returned
+ *
+ * Return value:
+ *     Number of bytes of IO data the driver will need to perform well.
+ */
+static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
+{
+       /* iu_storage data allocated in initialize_event_pool */
+       unsigned long desired_io = max_requests * sizeof(union viosrp_iu);
+
+       /* add io space for sg data */
+       desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 *
+                            IBMVSCSI_CMDS_PER_LUN_DEFAULT);
+
+       return desired_io;
+}
+
+/**
  * Called by bus code for each adapter
  */
 static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
@@ -1467,31 +1650,36 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        struct ibmvscsi_host_data *hostdata;
        struct Scsi_Host *host;
        struct device *dev = &vdev->dev;
+       struct srp_rport_identifiers ids;
+       struct srp_rport *rport;
        unsigned long wait_switch = 0;
+       int rc;
 
        vdev->dev.driver_data = NULL;
 
+       driver_template.can_queue = max_requests;
        host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
        if (!host) {
-               printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n");
+               dev_err(&vdev->dev, "couldn't allocate host data\n");
                goto scsi_host_alloc_failed;
        }
 
-       hostdata = (struct ibmvscsi_host_data *)host->hostdata;
+       host->transportt = ibmvscsi_transport_template;
+       hostdata = shost_priv(host);
        memset(hostdata, 0x00, sizeof(*hostdata));
        INIT_LIST_HEAD(&hostdata->sent);
        hostdata->host = host;
        hostdata->dev = dev;
        atomic_set(&hostdata->request_limit, -1);
-       hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
+       hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
 
-       if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata,
-                                   max_requests) != 0) {
-               printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n");
+       rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
+       if (rc != 0 && rc != H_RESOURCE) {
+               dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
                goto init_crq_failed;
        }
        if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) {
-               printk(KERN_ERR "ibmvscsi: couldn't initialize event pool\n");
+               dev_err(&vdev->dev, "couldn't initialize event pool\n");
                goto init_pool_failed;
        }
 
@@ -1502,11 +1690,20 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        if (scsi_add_host(hostdata->host, hostdata->dev))
                goto add_host_failed;
 
+       /* we don't have a proper target_port_id so let's use the fake one */
+       memcpy(ids.port_id, hostdata->madapter_info.partition_name,
+              sizeof(ids.port_id));
+       ids.roles = SRP_RPORT_ROLE_TARGET;
+       rport = srp_rport_add(host, &ids);
+       if (IS_ERR(rport))
+               goto add_srp_port_failed;
+
        /* Try to send an initialization message.  Note that this is allowed
         * to fail if the other end is not acive.  In that case we don't
         * want to scan
         */
-       if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) {
+       if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0
+           || rc == H_RESOURCE) {
                /*
                 * Wait around max init_timeout secs for the adapter to finish
                 * initializing. When we are done initializing, we will have a
@@ -1528,10 +1725,12 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        vdev->dev.driver_data = hostdata;
        return 0;
 
+      add_srp_port_failed:
+       scsi_remove_host(hostdata->host);
       add_host_failed:
        release_event_pool(&hostdata->pool, hostdata);
       init_pool_failed:
-       ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests);
+       ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests);
       init_crq_failed:
        scsi_host_put(host);
       scsi_host_alloc_failed:
@@ -1542,9 +1741,10 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
 {
        struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
        release_event_pool(&hostdata->pool, hostdata);
-       ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
-                                  max_requests);
-       
+       ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
+                                       max_requests);
+
+       srp_remove_host(hostdata->host);
        scsi_remove_host(hostdata->host);
        scsi_host_put(hostdata->host);
 
@@ -1565,20 +1765,42 @@ static struct vio_driver ibmvscsi_driver = {
        .id_table = ibmvscsi_device_table,
        .probe = ibmvscsi_probe,
        .remove = ibmvscsi_remove,
+       .get_desired_dma = ibmvscsi_get_desired_dma,
        .driver = {
                .name = "ibmvscsi",
                .owner = THIS_MODULE,
        }
 };
 
+static struct srp_function_template ibmvscsi_transport_functions = {
+};
+
 int __init ibmvscsi_module_init(void)
 {
-       return vio_register_driver(&ibmvscsi_driver);
+       int ret;
+
+       if (firmware_has_feature(FW_FEATURE_ISERIES))
+               ibmvscsi_ops = &iseriesvscsi_ops;
+       else if (firmware_has_feature(FW_FEATURE_VIO))
+               ibmvscsi_ops = &rpavscsi_ops;
+       else
+               return -ENODEV;
+
+       ibmvscsi_transport_template =
+               srp_attach_transport(&ibmvscsi_transport_functions);
+       if (!ibmvscsi_transport_template)
+               return -ENOMEM;
+
+       ret = vio_register_driver(&ibmvscsi_driver);
+       if (ret)
+               srp_release_transport(ibmvscsi_transport_template);
+       return ret;
 }
 
 void __exit ibmvscsi_module_exit(void)
 {
        vio_unregister_driver(&ibmvscsi_driver);
+       srp_release_transport(ibmvscsi_transport_template);
 }
 
 module_init(ibmvscsi_module_init);