include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / s390 / scsi / zfcp_scsi.c
index 5b11386..174b6d5 100644 (file)
@@ -3,38 +3,55 @@
  *
  * Interface to Linux SCSI midlayer.
  *
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #define KMSG_COMPONENT "zfcp"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
-#include "zfcp_ext.h"
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <scsi/fc/fc_fcp.h>
 #include <asm/atomic.h>
+#include "zfcp_ext.h"
+#include "zfcp_dbf.h"
+#include "zfcp_fc.h"
+#include "zfcp_reqlist.h"
 
-/* Find start of Sense Information in FCP response unit*/
-char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
-{
-       char *fcp_sns_info_ptr;
-
-       fcp_sns_info_ptr = (unsigned char *) &fcp_rsp_iu[1];
-       if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)
-               fcp_sns_info_ptr += fcp_rsp_iu->fcp_rsp_len;
+static unsigned int default_depth = 32;
+module_param_named(queue_depth, default_depth, uint, 0600);
+MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");
 
-       return fcp_sns_info_ptr;
+static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
+                                       int reason)
+{
+       switch (reason) {
+       case SCSI_QDEPTH_DEFAULT:
+               scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+               break;
+       case SCSI_QDEPTH_QFULL:
+               scsi_track_queue_full(sdev, depth);
+               break;
+       case SCSI_QDEPTH_RAMP_UP:
+               scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return sdev->queue_depth;
 }
 
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 {
        struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
        unit->device = NULL;
-       zfcp_unit_put(unit);
+       put_device(&unit->dev);
 }
 
 static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
 {
        if (sdp->tagged_supported)
-               scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32);
+               scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth);
        else
                scsi_adjust_queue_depth(sdp, 0, 1);
        return 0;
@@ -42,12 +59,11 @@ static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
 
 static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
 {
+       struct zfcp_adapter *adapter =
+               (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
+
        set_host_byte(scpnt, result);
-       if ((scpnt->device != NULL) && (scpnt->device->host != NULL))
-               zfcp_scsi_dbf_event_result("fail", 4,
-                       (struct zfcp_adapter*) scpnt->device->host->hostdata[0],
-                       scpnt, NULL);
-       /* return directly */
+       zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt);
        scpnt->scsi_done(scpnt);
 }
 
@@ -71,27 +87,33 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
        adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
        unit = scpnt->device->hostdata;
 
-       BUG_ON(!adapter || (adapter != unit->port->adapter));
-       BUG_ON(!scpnt->scsi_done);
-
-       if (unlikely(!unit)) {
-               zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT);
-               return 0;
-       }
-
        scsi_result = fc_remote_port_chkready(rport);
        if (unlikely(scsi_result)) {
                scpnt->result = scsi_result;
-               zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL);
+               zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt);
                scpnt->scsi_done(scpnt);
                return 0;
        }
 
        status = atomic_read(&unit->status);
-       if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
-                    !(status & ZFCP_STATUS_COMMON_RUNNING))) {
+       if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) &&
+                    !(atomic_read(&unit->port->status) &
+                      ZFCP_STATUS_COMMON_ERP_FAILED)) {
+               /* only unit access denied, but port is good
+                * not covered by FC transport, have to fail here */
                zfcp_scsi_command_fail(scpnt, DID_ERROR);
-               return 0;;
+               return 0;
+       }
+
+       if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) {
+               /* This could be either
+                * open unit pending: this is temporary, will result in
+                *      open unit or ERP_FAILED, so retry command
+                * call to rport_delete pending: mimic retry from
+                *      fc_remote_port_chkready until rport is BLOCKED
+                */
+               zfcp_scsi_command_fail(scpnt, DID_IMM_RETRY);
+               return 0;
        }
 
        ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
@@ -104,49 +126,44 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
 }
 
 static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter,
-                                         int channel, unsigned int id,
-                                         unsigned int lun)
+                                         unsigned int id, u64 lun)
 {
+       unsigned long flags;
        struct zfcp_port *port;
-       struct zfcp_unit *unit;
-       int scsi_lun;
+       struct zfcp_unit *unit = NULL;
 
-       list_for_each_entry(port, &adapter->port_list_head, list) {
+       read_lock_irqsave(&adapter->port_list_lock, flags);
+       list_for_each_entry(port, &adapter->port_list, list) {
                if (!port->rport || (id != port->rport->scsi_target_id))
                        continue;
-               list_for_each_entry(unit, &port->unit_list_head, list) {
-                       scsi_lun = scsilun_to_int(
-                               (struct scsi_lun *)&unit->fcp_lun);
-                       if (lun == scsi_lun)
-                               return unit;
-               }
+               unit = zfcp_get_unit_by_lun(port, lun);
+               if (unit)
+                       break;
        }
+       read_unlock_irqrestore(&adapter->port_list_lock, flags);
 
-       return NULL;
+       return unit;
 }
 
 static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
 {
        struct zfcp_adapter *adapter;
        struct zfcp_unit *unit;
-       unsigned long flags;
-       int retval = -ENXIO;
+       u64 lun;
 
        adapter = (struct zfcp_adapter *) sdp->host->hostdata[0];
        if (!adapter)
                goto out;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun);
+       int_to_scsilun(sdp->lun, (struct scsi_lun *)&lun);
+       unit = zfcp_unit_lookup(adapter, sdp->id, lun);
        if (unit) {
                sdp->hostdata = unit;
                unit->device = sdp;
-               zfcp_unit_get(unit);
-               retval = 0;
+               return 0;
        }
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 out:
-       return retval;
+       return -ENXIO;
 }
 
 static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
@@ -157,21 +174,20 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        struct zfcp_unit *unit = scpnt->device->hostdata;
        struct zfcp_fsf_req *old_req, *abrt_req;
        unsigned long flags;
-       unsigned long old_req_id = (unsigned long) scpnt->host_scribble;
+       unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
        int retval = SUCCESS;
        int retry = 3;
+       char *dbf_tag;
 
        /* avoid race condition between late normal completion and abort */
        write_lock_irqsave(&adapter->abort_lock, flags);
 
-       spin_lock(&adapter->req_list_lock);
-       old_req = zfcp_reqlist_find(adapter, old_req_id);
-       spin_unlock(&adapter->req_list_lock);
+       old_req = zfcp_reqlist_find(adapter->req_list, old_reqid);
        if (!old_req) {
                write_unlock_irqrestore(&adapter->abort_lock, flags);
-               zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
-                                         old_req_id);
-               return SUCCESS;
+               zfcp_dbf_scsi_abort("lte1", adapter->dbf, scpnt, NULL,
+                                   old_reqid);
+               return FAILED; /* completion could be in progress */
        }
        old_req->data = NULL;
 
@@ -179,32 +195,33 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        write_unlock_irqrestore(&adapter->abort_lock, flags);
 
        while (retry--) {
-               abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
+               abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit);
                if (abrt_req)
                        break;
 
                zfcp_erp_wait(adapter);
+               fc_block_scsi_eh(scpnt);
                if (!(atomic_read(&adapter->status) &
                      ZFCP_STATUS_COMMON_RUNNING)) {
-                       zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
-                                                 old_req_id);
+                       zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
+                                           old_reqid);
                        return SUCCESS;
                }
        }
        if (!abrt_req)
                return FAILED;
 
-       wait_event(abrt_req->completion_wq,
-                  abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+       wait_for_completion(&abrt_req->completion);
 
        if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
-               zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
+               dbf_tag = "okay";
        else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
-               zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
+               dbf_tag = "lte2";
        else {
-               zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
+               dbf_tag = "fail";
                retval = FAILED;
        }
+       zfcp_dbf_scsi_abort(dbf_tag, adapter->dbf, scpnt, abrt_req, old_reqid);
        zfcp_fsf_req_free(abrt_req);
        return retval;
 }
@@ -213,7 +230,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
 {
        struct zfcp_unit *unit = scpnt->device->hostdata;
        struct zfcp_adapter *adapter = unit->port->adapter;
-       struct zfcp_fsf_req *fsf_req;
+       struct zfcp_fsf_req *fsf_req = NULL;
        int retval = SUCCESS;
        int retry = 3;
 
@@ -223,27 +240,23 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
                        break;
 
                zfcp_erp_wait(adapter);
+               fc_block_scsi_eh(scpnt);
                if (!(atomic_read(&adapter->status) &
                      ZFCP_STATUS_COMMON_RUNNING)) {
-                       zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit,
-                                                    scpnt);
+                       zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
                        return SUCCESS;
                }
        }
        if (!fsf_req)
                return FAILED;
 
-       wait_event(fsf_req->completion_wq,
-                  fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+       wait_for_completion(&fsf_req->completion);
 
        if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
-               zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt);
-               retval = FAILED;
-       } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) {
-               zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt);
+               zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt);
                retval = FAILED;
        } else
-               zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt);
+               zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt);
 
        zfcp_fsf_req_free(fsf_req);
        return retval;
@@ -251,12 +264,12 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
 
 static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
 {
-       return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET);
+       return zfcp_task_mgmt_function(scpnt, FCP_TMF_LUN_RESET);
 }
 
 static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt)
 {
-       return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET);
+       return zfcp_task_mgmt_function(scpnt, FCP_TMF_TGT_RESET);
 }
 
 static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
@@ -266,6 +279,7 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 
        zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
        zfcp_erp_wait(adapter);
+       fc_block_scsi_eh(scpnt);
 
        return SUCCESS;
 }
@@ -293,7 +307,7 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
        adapter->scsi_host->max_lun = 1;
        adapter->scsi_host->max_channel = 0;
        adapter->scsi_host->unique_id = dev_id.devno;
-       adapter->scsi_host->max_cmd_len = 255;
+       adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */
        adapter->scsi_host->transportt = zfcp_data.scsi_transport_template;
 
        adapter->scsi_host->hostdata[0] = (unsigned long) adapter;
@@ -315,12 +329,11 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
        if (!shost)
                return;
 
-       read_lock_irq(&zfcp_data.config_lock);
-       list_for_each_entry(port, &adapter->port_list_head, list)
-               if (port->rport)
-                       port->rport = NULL;
+       read_lock_irq(&adapter->port_list_lock);
+       list_for_each_entry(port, &adapter->port_list, list)
+               port->rport = NULL;
+       read_unlock_irq(&adapter->port_list_lock);
 
-       read_unlock_irq(&zfcp_data.config_lock);
        fc_remove_host(shost);
        scsi_remove_host(shost);
        scsi_host_put(shost);
@@ -338,7 +351,7 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter)
                fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL);
                if (!fc_stats)
                        return NULL;
-               adapter->fc_stats = fc_stats; /* freed in adater_dequeue */
+               adapter->fc_stats = fc_stats; /* freed in adapter_release */
        }
        memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats));
        return adapter->fc_stats;
@@ -418,7 +431,7 @@ static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host)
        if (!data)
                return NULL;
 
-       ret = zfcp_fsf_exchange_port_data_sync(adapter, data);
+       ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data);
        if (ret) {
                kfree(data);
                return NULL;
@@ -447,14 +460,14 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
        if (!data)
                return;
 
-       ret = zfcp_fsf_exchange_port_data_sync(adapter, data);
+       ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data);
        if (ret)
                kfree(data);
        else {
                adapter->stats_reset = jiffies/HZ;
                kfree(adapter->stats_reset_data);
                adapter->stats_reset_data = data; /* finally freed in
-                                                    adapter_dequeue */
+                                                    adapter_release */
        }
 }
 
@@ -481,31 +494,26 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
 }
 
 /**
- * zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport
- * @rport: The rport that is about to be deleted.
- */
-static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport)
-{
-       struct zfcp_port *port = rport->dd_data;
-
-       write_lock_irq(&zfcp_data.config_lock);
-       port->rport = NULL;
-       write_unlock_irq(&zfcp_data.config_lock);
-}
-
-/**
  * zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport
  * @rport: The FC rport where to teminate I/O
  *
  * Abort all pending SCSI commands for a port by closing the
- * port. Using a reopen for avoids a conflict with a shutdown
+ * port. Using a reopen avoiding a conflict with a shutdown
  * overwriting a reopen.
  */
 static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
 {
-       struct zfcp_port *port = rport->dd_data;
+       struct zfcp_port *port;
+       struct Scsi_Host *shost = rport_to_shost(rport);
+       struct zfcp_adapter *adapter =
+               (struct zfcp_adapter *)shost->hostdata[0];
 
-       zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
+       port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
+
+       if (port) {
+               zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
+               put_device(&port->dev);
+       }
 }
 
 static void zfcp_scsi_rport_register(struct zfcp_port *port)
@@ -513,6 +521,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
        struct fc_rport_identifiers ids;
        struct fc_rport *rport;
 
+       if (port->rport)
+               return;
+
        ids.node_name = port->wwnn;
        ids.port_name = port->wwpn;
        ids.port_id = port->d_id;
@@ -526,7 +537,6 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
                return;
        }
 
-       rport->dd_data = port;
        rport->maxframe_size = port->maxframe_size;
        rport->supported_classes = port->supported_classes;
        port->rport = rport;
@@ -534,34 +544,44 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
 
 static void zfcp_scsi_rport_block(struct zfcp_port *port)
 {
-       if (port->rport)
-               fc_remote_port_delete(port->rport);
+       struct fc_rport *rport = port->rport;
+
+       if (rport) {
+               fc_remote_port_delete(rport);
+               port->rport = NULL;
+       }
 }
 
 void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
 {
-       zfcp_port_get(port);
+       get_device(&port->dev);
        port->rport_task = RPORT_ADD;
 
-       if (!queue_work(zfcp_data.work_queue, &port->rport_work))
-               zfcp_port_put(port);
+       if (!queue_work(port->adapter->work_queue, &port->rport_work))
+               put_device(&port->dev);
 }
 
 void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
 {
-       zfcp_port_get(port);
+       get_device(&port->dev);
        port->rport_task = RPORT_DEL;
 
-       if (!queue_work(zfcp_data.work_queue, &port->rport_work))
-               zfcp_port_put(port);
+       if (port->rport && queue_work(port->adapter->work_queue,
+                                     &port->rport_work))
+               return;
+
+       put_device(&port->dev);
 }
 
 void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
 {
+       unsigned long flags;
        struct zfcp_port *port;
 
-       list_for_each_entry(port, &adapter->port_list_head, list)
+       read_lock_irqsave(&adapter->port_list_lock, flags);
+       list_for_each_entry(port, &adapter->port_list, list)
                zfcp_scsi_schedule_rport_block(port);
+       read_unlock_irqrestore(&adapter->port_list_lock, flags);
 }
 
 void zfcp_scsi_rport_work(struct work_struct *work)
@@ -579,7 +599,7 @@ void zfcp_scsi_rport_work(struct work_struct *work)
                }
        }
 
-       zfcp_port_put(port);
+       put_device(&port->dev);
 }
 
 
@@ -597,7 +617,7 @@ void zfcp_scsi_scan(struct work_struct *work)
                                 scsilun_to_int((struct scsi_lun *)
                                                &unit->fcp_lun), 0);
 
-       zfcp_unit_put(unit);
+       put_device(&unit->dev);
 }
 
 struct fc_function_template zfcp_transport_functions = {
@@ -611,6 +631,7 @@ struct fc_function_template zfcp_transport_functions = {
        .show_host_port_name = 1,
        .show_host_permanent_port_name = 1,
        .show_host_supported_classes = 1,
+       .show_host_supported_fc4s = 1,
        .show_host_supported_speeds = 1,
        .show_host_maxframe_size = 1,
        .show_host_serial_number = 1,
@@ -618,15 +639,18 @@ struct fc_function_template zfcp_transport_functions = {
        .reset_fc_host_stats = zfcp_reset_fc_host_stats,
        .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo,
        .get_host_port_state = zfcp_get_host_port_state,
-       .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk,
        .terminate_rport_io = zfcp_scsi_terminate_rport_io,
        .show_host_port_state = 1,
+       .show_host_active_fc4s = 1,
+       .bsg_request = zfcp_fc_exec_bsg_job,
+       .bsg_timeout = zfcp_fc_timeout_bsg_job,
        /* no functions registered for following dynamic attributes but
           directly set by LLDD */
        .show_host_port_type = 1,
        .show_host_speed = 1,
        .show_host_port_id = 1,
        .disable_target_scan = 1,
+       .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els),
 };
 
 struct zfcp_data zfcp_data = {
@@ -634,6 +658,7 @@ struct zfcp_data zfcp_data = {
                .name                    = "zfcp",
                .module                  = THIS_MODULE,
                .proc_name               = "zfcp",
+               .change_queue_depth      = zfcp_scsi_change_queue_depth,
                .slave_alloc             = zfcp_scsi_slave_alloc,
                .slave_configure         = zfcp_scsi_slave_configure,
                .slave_destroy           = zfcp_scsi_slave_destroy,