linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / s390 / scsi / zfcp_scsi.c
index c489dec..9e6d07d 100644 (file)
@@ -1,8 +1,18 @@
 /* 
- * This file is part of the zfcp device driver for
- * FCP adapters for IBM System z9 and zSeries.
+ * 
+ * linux/drivers/s390/scsi/zfcp_scsi.c
+ * 
+ * FCP adapter driver for IBM eServer zSeries 
+ * 
+ * (C) Copyright IBM Corp. 2002, 2004
  *
- * (C) Copyright IBM Corp. 2002, 2006
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com> 
+ *            Raimund Schroeder <raimund.schroeder@de.ibm.com> 
+ *            Aron Zeh
+ *            Wolfgang Taphorn
+ *            Stefan Bader <stefan.bader@de.ibm.com> 
+ *            Heiko Carstens <heiko.carstens@de.ibm.com> 
+ *            Andreas Herrmann <aherrman@de.ibm.com>
  * 
  * This program is free software; you can redistribute it and/or modify 
  * it under the terms of the GNU General Public License as published by 
@@ -30,12 +40,13 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *,
                                  void (*done) (struct scsi_cmnd *));
 static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *);
 static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *);
+static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *);
 static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *);
 static int zfcp_task_management_function(struct zfcp_unit *, u8,
                                         struct scsi_cmnd *);
 
-static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int,
-                                         unsigned int, unsigned int);
+static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t,
+                                         scsi_lun_t);
 
 static struct device_attribute *zfcp_sysfs_sdev_attrs[];
 
@@ -43,24 +54,33 @@ struct scsi_transport_template *zfcp_transport_template;
 
 struct zfcp_data zfcp_data = {
        .scsi_host_template = {
-               .name                   = ZFCP_NAME,
-               .proc_name              = "zfcp",
-               .slave_alloc            = zfcp_scsi_slave_alloc,
-               .slave_configure        = zfcp_scsi_slave_configure,
-               .slave_destroy          = zfcp_scsi_slave_destroy,
-               .queuecommand           = zfcp_scsi_queuecommand,
-               .eh_abort_handler       = zfcp_scsi_eh_abort_handler,
-               .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
-               .eh_bus_reset_handler   = zfcp_scsi_eh_host_reset_handler,
-               .eh_host_reset_handler  = zfcp_scsi_eh_host_reset_handler,
-               .can_queue              = 4096,
-               .this_id                = -1,
-               .sg_tablesize           = ZFCP_MAX_SBALES_PER_REQ,
-               .cmd_per_lun            = 1,
-               .use_clustering         = 1,
-               .sdev_attrs             = zfcp_sysfs_sdev_attrs,
+             name:                    ZFCP_NAME,
+             proc_name:               "zfcp",
+             proc_info:               NULL,
+             detect:                  NULL,
+             slave_alloc:             zfcp_scsi_slave_alloc,
+             slave_configure:         zfcp_scsi_slave_configure,
+             slave_destroy:           zfcp_scsi_slave_destroy,
+             queuecommand:            zfcp_scsi_queuecommand,
+             eh_abort_handler:        zfcp_scsi_eh_abort_handler,
+             eh_device_reset_handler: zfcp_scsi_eh_device_reset_handler,
+             eh_bus_reset_handler:    zfcp_scsi_eh_bus_reset_handler,
+             eh_host_reset_handler:   zfcp_scsi_eh_host_reset_handler,
+                                      /* FIXME(openfcp): Tune */
+             can_queue:               4096,
+             this_id:                 -1,
+             /*
+              * FIXME:
+              * one less? can zfcp_create_sbale cope with it?
+              */
+             sg_tablesize:            ZFCP_MAX_SBALES_PER_REQ,
+             cmd_per_lun:             1,
+             unchecked_isa_dma:       0,
+             use_clustering:          1,
+             sdev_attrs:              zfcp_sysfs_sdev_attrs,
        },
        .driver_version = ZFCP_VERSION,
+       /* rest initialised with zeros */
 };
 
 /* Find start of Response Information in FCP response unit*/
@@ -141,6 +161,14 @@ set_driver_byte(u32 * result, char status)
        set_byte(result, status, 3);
 }
 
+/*
+ * function:   zfcp_scsi_slave_alloc
+ *
+ * purpose:
+ *
+ * returns:
+ */
+
 static int
 zfcp_scsi_slave_alloc(struct scsi_device *sdp)
 {
@@ -167,14 +195,16 @@ zfcp_scsi_slave_alloc(struct scsi_device *sdp)
        return retval;
 }
 
-/**
- * zfcp_scsi_slave_destroy - called when scsi device is removed
+/*
+ * function:   zfcp_scsi_slave_destroy
+ *
+ * purpose:
  *
- * Remove reference to associated scsi device for an zfcp_unit.
- * Mark zfcp_unit as failed. The scsi device might be deleted via sysfs
- * or a scan for this device might have failed.
+ * returns:
  */
-static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
+
+static void
+zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 {
        struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
 
@@ -182,7 +212,6 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
                atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
                sdpnt->hostdata = NULL;
                unit->device = NULL;
-               zfcp_erp_unit_failed(unit);
                zfcp_unit_put(unit);
        } else {
                ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at "
@@ -302,7 +331,7 @@ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt,
                       struct timer_list *timer)
 {
        int ret;
-       DECLARE_COMPLETION_ONSTACK(wait);
+       DECLARE_COMPLETION(wait);
 
        scpnt->SCp.ptr = (void *) &wait;  /* silent re-use */
        scpnt->scsi_done = zfcp_scsi_command_sync_handler;
@@ -345,9 +374,18 @@ zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
        return zfcp_scsi_command_async(adapter, unit, scpnt, NULL);
 }
 
+/*
+ * function:    zfcp_unit_lookup
+ *
+ * purpose:
+ *
+ * returns:
+ *
+ * context:    
+ */
 static struct zfcp_unit *
-zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
-                unsigned int lun)
+zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id,
+                scsi_lun_t lun)
 {
        struct zfcp_port *port;
        struct zfcp_unit *unit, *retval = NULL;
@@ -453,6 +491,13 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        return retval;
 }
 
+/*
+ * function:   zfcp_scsi_eh_device_reset_handler
+ *
+ * purpose:
+ *
+ * returns:
+ */
 int
 zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
 {
@@ -547,42 +592,46 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
 }
 
 /**
- * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
- *
- * If ERP is already running it will be stopped.
+ * zfcp_scsi_eh_bus_reset_handler - reset bus (reopen adapter)
  */
-int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+int
+zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
 {
-       struct zfcp_unit *unit;
-       struct zfcp_adapter *adapter;
-       unsigned long flags;
-
-       unit = (struct zfcp_unit*) scpnt->device->hostdata;
-       adapter = unit->port->adapter;
+       struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata;
+       struct zfcp_adapter *adapter = unit->port->adapter;
 
-       ZFCP_LOG_NORMAL("host/bus reset because of problems with "
+       ZFCP_LOG_NORMAL("bus reset because of problems with "
                        "unit 0x%016Lx\n", unit->fcp_lun);
+       zfcp_erp_adapter_reopen(adapter, 0);
+       zfcp_erp_wait(adapter);
 
-       write_lock_irqsave(&adapter->erp_lock, flags);
-       if (atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
-                            &adapter->status)) {
-               zfcp_erp_modify_adapter_status(adapter,
-                      ZFCP_STATUS_COMMON_UNBLOCKED|ZFCP_STATUS_COMMON_OPEN,
-                      ZFCP_CLEAR);
-               zfcp_erp_action_dismiss_adapter(adapter);
-               write_unlock_irqrestore(&adapter->erp_lock, flags);
-               zfcp_fsf_req_dismiss_all(adapter);
-               adapter->fsf_req_seq_no = 0;
-               zfcp_erp_adapter_reopen(adapter, 0);
-       } else {
-               write_unlock_irqrestore(&adapter->erp_lock, flags);
-               zfcp_erp_adapter_reopen(adapter, 0);
-               zfcp_erp_wait(adapter);
-       }
+       return SUCCESS;
+}
+
+/**
+ * zfcp_scsi_eh_host_reset_handler - reset host (reopen adapter)
+ */
+int
+zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+{
+       struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata;
+       struct zfcp_adapter *adapter = unit->port->adapter;
+
+       ZFCP_LOG_NORMAL("host reset because of problems with "
+                       "unit 0x%016Lx\n", unit->fcp_lun);
+       zfcp_erp_adapter_reopen(adapter, 0);
+       zfcp_erp_wait(adapter);
 
        return SUCCESS;
 }
 
+/*
+ * function:   
+ *
+ * purpose:    
+ *
+ * returns:
+ */
 int
 zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
 {
@@ -608,6 +657,10 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
        adapter->scsi_host->unique_id = unique_id++;    /* FIXME */
        adapter->scsi_host->max_cmd_len = ZFCP_MAX_SCSI_CMND_LENGTH;
        adapter->scsi_host->transportt = zfcp_transport_template;
+       /*
+        * Reverse mapping of the host number to avoid race condition
+        */
+       adapter->scsi_host_no = adapter->scsi_host->host_no;
 
        /*
         * save a pointer to our own adapter data structure within
@@ -625,6 +678,13 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
        return retval;
 }
 
+/*
+ * function:   
+ *
+ * purpose:    
+ *
+ * returns:
+ */
 void
 zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
 {
@@ -643,6 +703,7 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
        scsi_remove_host(shost);
        scsi_host_put(shost);
        adapter->scsi_host = NULL;
+       adapter->scsi_host_no = 0;
        atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
 
        return;
@@ -756,9 +817,10 @@ zfcp_get_fc_host_stats(struct Scsi_Host *shost)
        if (!fc_stats)
                return NULL;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return NULL;
+       memset(data, 0, sizeof(*data));
 
        ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
        if (ret) {
@@ -786,9 +848,10 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
        int ret;
 
        adapter = (struct zfcp_adapter *)shost->hostdata[0];
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return;
+       memset(data, 0, sizeof(*data));
 
        ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
        if (ret == 0) {
@@ -800,18 +863,11 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
        }
 }
 
-static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
-{
-       rport->dev_loss_tmo = timeout;
-}
-
 struct fc_function_template zfcp_transport_functions = {
        .show_starget_port_id = 1,
        .show_starget_port_name = 1,
        .show_starget_node_name = 1,
        .show_rport_supported_classes = 1,
-       .show_rport_maxframe_size = 1,
-       .show_rport_dev_loss_tmo = 1,
        .show_host_node_name = 1,
        .show_host_port_name = 1,
        .show_host_permanent_port_name = 1,
@@ -821,7 +877,6 @@ struct fc_function_template zfcp_transport_functions = {
        .show_host_serial_number = 1,
        .get_fc_host_stats = zfcp_get_fc_host_stats,
        .reset_fc_host_stats = zfcp_reset_fc_host_stats,
-       .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo,
        /* no functions registered for following dynamic attributes but
           directly set by LLDD */
        .show_host_port_type = 1,