From c9615858a81d2424c78b10a2f689ba24b156937c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 6 May 2008 11:00:05 +0200 Subject: [SCSI] zfcp: Track fabric and channel latencies provided by FCP adapter Add the infrastructure to retrieve the fabric and channel latencies from FSF commands for each SCSI command that has been processed. For each unit, the sum, min, max and number of requests is tracked. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 8 ++++++++ drivers/s390/scsi/zfcp_def.h | 20 ++++++++++++++++++++ drivers/s390/scsi/zfcp_fsf.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_fsf.h | 11 ++++++++++- 4 files changed, 82 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 8c7e2b778ef1..d23027a2f2f0 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -847,6 +847,14 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) /* mark unit unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); + spin_lock_init(&unit->latencies.lock); + unit->latencies.write.channel.min = 0xFFFFFFFF; + unit->latencies.write.fabric.min = 0xFFFFFFFF; + unit->latencies.read.channel.min = 0xFFFFFFFF; + unit->latencies.read.fabric.min = 0xFFFFFFFF; + unit->latencies.cmd.channel.min = 0xFFFFFFFF; + unit->latencies.cmd.fabric.min = 0xFFFFFFFF; + if (device_register(&unit->sysfs_device)) { kfree(unit); return NULL; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index bda8c77b22da..306fcd0cae31 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -708,6 +708,24 @@ struct zfcp_erp_action { struct timer_list timer; }; +struct fsf_latency_record { + u32 min; + u32 max; + u64 sum; +}; + +struct latency_cont { + struct fsf_latency_record channel; + struct fsf_latency_record fabric; + u64 counter; +}; + +struct zfcp_latencies { + struct latency_cont read; + struct latency_cont write; + struct latency_cont cmd; + spinlock_t lock; +}; struct zfcp_adapter { struct list_head list; /* list of adapters */ @@ -723,6 +741,7 @@ struct zfcp_adapter { u32 adapter_features; /* FCP channel features */ u32 connection_features; /* host connection features */ u32 hardware_version; /* of FCP channel */ + u16 timer_ticks; /* time int for a tick */ struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ struct list_head port_list_head; /* remote port list */ struct list_head port_remove_lh; /* head of ports to be @@ -822,6 +841,7 @@ struct zfcp_unit { struct scsi_device *device; /* scsi device struct pointer */ struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; + struct zfcp_latencies latencies; }; /* FSF request */ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b2ea4ea051f5..1e7136483c1b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -2005,6 +2005,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; adapter->hydra_version = bottom->adapter_type; + adapter->timer_ticks = bottom->timer_interval; if (fc_host_permanent_port_name(shost) == -1) fc_host_permanent_port_name(shost) = fc_host_port_name(shost); @@ -3649,6 +3650,46 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, return fsf_req; } +static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat) +{ + lat_rec->sum += lat; + if (lat_rec->min > lat) + lat_rec->min = lat; + if (lat_rec->max < lat) + lat_rec->max = lat; +} + +static void zfcp_fsf_req_latency(struct zfcp_fsf_req *fsf_req) +{ + struct fsf_qual_latency_info *lat_inf; + struct latency_cont *lat; + struct zfcp_unit *unit; + unsigned long flags; + + lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info; + unit = fsf_req->unit; + + switch (fsf_req->qtcb->bottom.io.data_direction) { + case FSF_DATADIR_READ: + lat = &unit->latencies.read; + break; + case FSF_DATADIR_WRITE: + lat = &unit->latencies.write; + break; + case FSF_DATADIR_CMND: + lat = &unit->latencies.cmd; + break; + default: + return; + } + + spin_lock_irqsave(&unit->latencies.lock, flags); + zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat); + zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat); + lat->counter++; + spin_unlock_irqrestore(&unit->latencies.lock, flags); +} + /* * function: zfcp_fsf_send_fcp_command_handler * @@ -3922,6 +3963,9 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) fcp_rsp_iu->fcp_sns_len); } + if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) + zfcp_fsf_req_latency(fsf_req); + /* check FCP_RSP_INFO */ if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { ZFCP_LOG_DEBUG("rsp_len is valid\n"); diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 099970b27001..8b1a7d9c840f 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -323,11 +323,18 @@ struct fsf_link_down_info { u8 vendor_specific_code; } __attribute__ ((packed)); +struct fsf_qual_latency_info { + u32 channel_lat; + u32 fabric_lat; + u8 res1[8]; +} __attribute__ ((packed)); + union fsf_prot_status_qual { u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; struct fsf_qual_version_error version_error; struct fsf_qual_sequence_error sequence_error; struct fsf_link_down_info link_down_info; + struct fsf_qual_latency_info latency_info; } __attribute__ ((packed)); struct fsf_qtcb_prefix { @@ -437,7 +444,9 @@ struct fsf_qtcb_bottom_config { u32 fc_link_speed; u32 adapter_type; u32 peer_d_id; - u8 res2[12]; + u8 res1[2]; + u16 timer_interval; + u8 res2[8]; u32 s_id; struct fsf_nport_serv_param nport_serv_param; u8 reserved_nport_serv_param[16]; -- cgit v1.2.3 From 3a0d9e92356feb60ee4e978355f712366a93f4ef Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 6 May 2008 11:00:06 +0200 Subject: [SCSI] zfcp: sysfs attributes for fabric and channel latencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The latency information is provided on a SCSI device level (LUN) which can be found at the following location  /sys/class/scsi_device//device/cmd_latency  /sys/class/scsi_device//device/read_latency  /sys/class/scsi_device//device/write_latency Each sysfs attribute provides the available data: min, max and sum for fabric and channel latency and the number of requests processed. An overrun of the variables is neither detected nor treated. The file has to be read twice to make a meaningful statement, because only the differences of the values between the two reads can be used. A reset of the values can be achieved by writing to the attribute. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_scsi.c | 65 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 01687559dc06..4b0c85acb0f0 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -778,6 +778,68 @@ struct fc_function_template zfcp_transport_functions = { .disable_target_scan = 1, }; +#define ZFCP_DEFINE_LATENCY_ATTR(_name) \ +static ssize_t \ +zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) { \ + struct scsi_device *sdev = to_scsi_device(dev); \ + struct zfcp_unit *unit = sdev->hostdata; \ + struct zfcp_latencies *lat = &unit->latencies; \ + struct zfcp_adapter *adapter = unit->port->adapter; \ + unsigned long flags; \ + unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \ + \ + spin_lock_irqsave(&lat->lock, flags); \ + fsum = lat->_name.fabric.sum * adapter->timer_ticks; \ + fmin = lat->_name.fabric.min * adapter->timer_ticks; \ + fmax = lat->_name.fabric.max * adapter->timer_ticks; \ + csum = lat->_name.channel.sum * adapter->timer_ticks; \ + cmin = lat->_name.channel.min * adapter->timer_ticks; \ + cmax = lat->_name.channel.max * adapter->timer_ticks; \ + cc = lat->_name.counter; \ + spin_unlock_irqrestore(&lat->lock, flags); \ + \ + do_div(fsum, 1000); \ + do_div(fmin, 1000); \ + do_div(fmax, 1000); \ + do_div(csum, 1000); \ + do_div(cmin, 1000); \ + do_div(cmax, 1000); \ + \ + return sprintf(buf, "%llu %llu %llu %llu %llu %llu %llu\n", \ + fmin, fmax, fsum, cmin, cmax, csum, cc); \ +} \ +static ssize_t \ +zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct scsi_device *sdev = to_scsi_device(dev); \ + struct zfcp_unit *unit = sdev->hostdata; \ + struct zfcp_latencies *lat = &unit->latencies; \ + unsigned long flags; \ + \ + spin_lock_irqsave(&lat->lock, flags); \ + lat->_name.fabric.sum = 0; \ + lat->_name.fabric.min = 0xFFFFFFFF; \ + lat->_name.fabric.max = 0; \ + lat->_name.channel.sum = 0; \ + lat->_name.channel.min = 0xFFFFFFFF; \ + lat->_name.channel.max = 0; \ + lat->_name.counter = 0; \ + spin_unlock_irqrestore(&lat->lock, flags); \ + \ + return (ssize_t) count; \ +} \ +static DEVICE_ATTR(_name##_latency, S_IWUSR | S_IRUGO, \ + zfcp_sysfs_unit_##_name##_latency_show, \ + zfcp_sysfs_unit_##_name##_latency_store); + +ZFCP_DEFINE_LATENCY_ATTR(read); +ZFCP_DEFINE_LATENCY_ATTR(write); +ZFCP_DEFINE_LATENCY_ATTR(cmd); + /** * ZFCP_DEFINE_SCSI_ATTR * @_name: name of show attribute @@ -808,6 +870,9 @@ static struct device_attribute *zfcp_sysfs_sdev_attrs[] = { &dev_attr_fcp_lun, &dev_attr_wwpn, &dev_attr_hba_id, + &dev_attr_read_latency, + &dev_attr_write_latency, + &dev_attr_cmd_latency, NULL }; -- cgit v1.2.3 From d26ab06ede83287f99067fee3034c5455a75faf9 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Mon, 19 May 2008 12:17:37 +0200 Subject: [SCSI] zfcp: receiving an unsolicted status can lead to I/O stall Processing of an unsolicted status request can lead to a locking race of the request_queue's queue_lock during the recreation of the used up status read request while still in interrupt context of the response handler. Detaching the 'refill' of the long running status read requests from the handler to a scheduled work is solving this issue. In addition, each refill-run is trying to re-establish the full amount of status read requests, which might have failed in earlier runs. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 23 +++++++++++++++++++++++ drivers/s390/scsi/zfcp_dbf.c | 2 +- drivers/s390/scsi/zfcp_def.h | 4 ++-- drivers/s390/scsi/zfcp_erp.c | 19 ++----------------- drivers/s390/scsi/zfcp_ext.h | 1 + drivers/s390/scsi/zfcp_fsf.c | 18 +++--------------- 6 files changed, 32 insertions(+), 35 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index d23027a2f2f0..41635b13ccb1 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -970,6 +970,27 @@ static void zfcp_dummy_release(struct device *dev) return; } +int zfcp_status_read_refill(struct zfcp_adapter *adapter) +{ + while (atomic_read(&adapter->stat_miss) > 0) + if (zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL)) + break; + else + atomic_dec(&adapter->stat_miss); + + if (ZFCP_STATUS_READS_RECOM <= atomic_read(&adapter->stat_miss)) { + zfcp_erp_adapter_reopen(adapter, 0, 103, NULL); + return 1; + } + return 0; +} + +static void _zfcp_status_read_scheduler(struct work_struct *work) +{ + zfcp_status_read_refill(container_of(work, struct zfcp_adapter, + stat_work)); +} + /* * Enqueues an adapter at the end of the adapter list in the driver data. * All adapter internal structures are set up. @@ -1063,6 +1084,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) /* initialize lock of associated request queue */ rwlock_init(&adapter->request_queue.queue_lock); + INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); /* mark adapter unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); @@ -1123,6 +1145,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) int retval = 0; unsigned long flags; + cancel_work_sync(&adapter->stat_work); zfcp_adapter_scsi_unregister(adapter); device_unregister(&adapter->generic_services); zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index c8bad675dbd1..1710c12a32c4 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -268,7 +268,7 @@ void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); - rec->u.status.failed = adapter->status_read_failed; + rec->u.status.failed = atomic_read(&adapter->stat_miss); if (status_buffer != NULL) { rec->u.status.status_type = status_buffer->status_type; rec->u.status.status_subtype = status_buffer->status_subtype; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 306fcd0cae31..adfbbb07448a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -136,7 +136,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) #define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION /* ATTENTION: value must not be used by hardware */ #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 -#define ZFCP_STATUS_READ_FAILED_THRESHOLD 3 #define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM /* Do 1st retry in 1 second, then double the timeout for each following retry */ @@ -759,7 +758,8 @@ struct zfcp_adapter { rwlock_t abort_lock; /* Protects against SCSI stack abort/command completion races */ - u16 status_read_failed; /* # failed status reads */ + atomic_t stat_miss; /* # missing status reads*/ + struct work_struct stat_work; atomic_t status; /* status of this adapter */ struct list_head erp_ready_head; /* error recovery for this adapter/devices */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 805484658dd9..55a4fdc42626 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -2139,25 +2139,10 @@ static int zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action *erp_action) { - int retval = ZFCP_ERP_SUCCEEDED; - int temp_ret; struct zfcp_adapter *adapter = erp_action->adapter; - int i; - adapter->status_read_failed = 0; - for (i = 0; i < ZFCP_STATUS_READS_RECOM; i++) { - temp_ret = zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL); - if (temp_ret < 0) { - ZFCP_LOG_INFO("error: set-up of unsolicited status " - "notification failed on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - retval = ZFCP_ERP_FAILED; - i--; - break; - } - } - - return retval; + atomic_set(&adapter->stat_miss, 16); + return zfcp_status_read_refill(adapter); } /* diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 6abf178fda5d..250565794fa5 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -92,6 +92,7 @@ extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); +extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, unsigned long *, struct zfcp_fsf_req **); extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 1e7136483c1b..b344e8a72f1f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1029,21 +1029,9 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) * FIXME: * allocation failure possible? (Is this code needed?) */ - retval = zfcp_fsf_status_read(adapter, 0); - if (retval < 0) { - ZFCP_LOG_INFO("Failed to create unsolicited status read " - "request for the adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); - /* temporary fix to avoid status read buffer shortage */ - adapter->status_read_failed++; - if ((ZFCP_STATUS_READS_RECOM - adapter->status_read_failed) - < ZFCP_STATUS_READ_FAILED_THRESHOLD) { - ZFCP_LOG_INFO("restart adapter %s due to status read " - "buffer shortage\n", - zfcp_get_busid_by_adapter(adapter)); - zfcp_erp_adapter_reopen(adapter, 0, 103, fsf_req); - } - } + + atomic_inc(&adapter->stat_miss); + schedule_work(&adapter->stat_work); out: return retval; } -- cgit v1.2.3 From 9dfe1cc36be27040144238d30da05053db71beb1 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 19 May 2008 12:17:38 +0200 Subject: [SCSI] zfcp: Fix mempool pointer for GID_PN request allocation When allocating memory for GID_PN nameserver requests, the allocation function stores the pointer to the mempool, but then overwrites the pointer via memset. Later, the wrong function to free the memory will be called, since this is based on the stored pointer. Fix this by first initializing the struct and then storing the pointer. Signed-off-by: Christof Schmitt Signed-off-by: Martin Peschke Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 41635b13ccb1..9a3c138ec50c 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -1533,19 +1533,16 @@ zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool) { struct zfcp_gid_pn_data *data; - if (pool != NULL) { + if (pool) data = mempool_alloc(pool, GFP_ATOMIC); - if (likely(data != NULL)) { - data->ct.pool = pool; - } - } else { + else data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC); - } if (NULL == data) return -ENOMEM; memset(data, 0, sizeof(*data)); + data->ct.pool = pool; sg_init_table(&data->req , 1); sg_init_table(&data->resp , 1); data->ct.req = &data->req; -- cgit v1.2.3 From b21417820f8f659a6b73cc937ab39bf77d350ce6 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 19 May 2008 12:17:39 +0200 Subject: [SCSI] zfcp: Fix fsf_status_read return code handling If allocation of a status buffer failed the function incorrectly returned 0 instead of -ENOMEM. Signed-off-by: Heiko Carstens Signed-off-by: Martin Peschke Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b344e8a72f1f..2f27d03e61c2 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -712,7 +712,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) struct fsf_status_read_buffer *status_buffer; unsigned long lock_flags; volatile struct qdio_buffer_element *sbale; - int retval = 0; + int retval; /* setup new FSF request */ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, @@ -731,12 +731,11 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; fsf_req->sbale_curr = 2; + retval = -ENOMEM; status_buffer = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); - if (!status_buffer) { - ZFCP_LOG_NORMAL("bug: could not get some buffer\n"); + if (!status_buffer) goto failed_buf; - } memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer)); fsf_req->data = (unsigned long) status_buffer; -- cgit v1.2.3 From 5c9a6890de80ed9222e6920f5930c272800f75ad Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 19 May 2008 12:17:40 +0200 Subject: [SCSI] zfcp: Remove some sparse warnings Remove some sparse warnings by telling sparse that zfcp_req_create acquires the lock for the request queue. Signed-off-by: Christof Schmitt Signed-off-by: Martin Peschke Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ext.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 250565794fa5..16213cbbc4ba 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -94,7 +94,8 @@ extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, - unsigned long *, struct zfcp_fsf_req **); + unsigned long *, struct zfcp_fsf_req **) + __acquires(adapter->request_queue.queue_lock); extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, struct zfcp_erp_action *); extern int zfcp_fsf_send_els(struct zfcp_send_els *); -- cgit v1.2.3 From 0f83b110f0cf6aef59e66184d5a1513318d654b5 Mon Sep 17 00:00:00 2001 From: Martin Peschke Date: Mon, 19 May 2008 12:17:41 +0200 Subject: [SCSI] zfcp: Remove field sbal_last from trace record. This field is not needed, because it designates an index with a fix offset from sbal_first. It's name is confusing anyway. Signed-off-by: Martin Peschke Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 2 -- drivers/s390/scsi/zfcp_dbf.h | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 1710c12a32c4..efd60c4af4c6 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -187,7 +187,6 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) response->fsf_req_status = fsf_req->status; response->sbal_first = fsf_req->sbal_first; response->sbal_curr = fsf_req->sbal_curr; - response->sbal_last = fsf_req->sbal_last; response->pool = fsf_req->pool != NULL; response->erp_action = (unsigned long)fsf_req->erp_action; @@ -356,7 +355,6 @@ static void zfcp_hba_dbf_view_response(char **p, zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); zfcp_dbf_out(p, "sbal_curr", "0x%02x", r->sbal_curr); - zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); zfcp_dbf_out(p, "pool", "0x%02x", r->pool); switch (r->fsf_command) { diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 54c34e483457..66b8754840b2 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -98,7 +98,6 @@ struct zfcp_hba_dbf_record_response { u32 fsf_req_status; u8 sbal_first; u8 sbal_curr; - u8 sbal_last; u8 pool; u64 erp_action; union { -- cgit v1.2.3 From d01d51beee4dd9f7ff9caf7491aa1727a318e665 Mon Sep 17 00:00:00 2001 From: Martin Peschke Date: Mon, 19 May 2008 12:17:42 +0200 Subject: [SCSI] zfcp: Rename sbal_last. sbal_last is confusing, as it is not the last one actually used, but just a limit. sbal_limit is a better name. Signed-off-by: Martin Peschke Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 2 +- drivers/s390/scsi/zfcp_qdio.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index adfbbb07448a..fdd5520eb3d2 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -851,7 +851,7 @@ struct zfcp_fsf_req { struct zfcp_adapter *adapter; /* adapter request belongs to */ u8 sbal_number; /* nr of SBALs free for use */ u8 sbal_first; /* first SBAL for this request */ - u8 sbal_last; /* last possible SBAL for + u8 sbal_limit; /* last possible SBAL for this reuest */ u8 sbal_curr; /* current SBAL during creation of request */ diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 8ca5f074c687..b6b6b36c6f20 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -432,9 +432,9 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) { int count = atomic_read(&fsf_req->adapter->request_queue.free_count); count = min(count, max_sbals); - fsf_req->sbal_last = fsf_req->sbal_first; - fsf_req->sbal_last += (count - 1); - fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; + fsf_req->sbal_limit = fsf_req->sbal_first; + fsf_req->sbal_limit += (count - 1); + fsf_req->sbal_limit %= QDIO_MAX_BUFFERS_PER_Q; } /** @@ -455,7 +455,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) sbale->flags |= SBAL_FLAGS_LAST_ENTRY; /* don't exceed last allowed SBAL */ - if (fsf_req->sbal_curr == fsf_req->sbal_last) + if (fsf_req->sbal_curr == fsf_req->sbal_limit) return NULL; /* set chaining flag in first SBALE of current SBAL */ -- cgit v1.2.3 From e891bffe927f39718cf84c35b380d6edb189848b Mon Sep 17 00:00:00 2001 From: Martin Peschke Date: Mon, 19 May 2008 12:17:43 +0200 Subject: [SCSI] zfcp: Rename sbal_curr to sbal_last. sbal_last is more appropriate, because it matches sbal_first. Signed-off-by: Martin Peschke Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 4 ++-- drivers/s390/scsi/zfcp_dbf.h | 2 +- drivers/s390/scsi/zfcp_def.h | 3 +-- drivers/s390/scsi/zfcp_fsf.c | 36 ++++++++++++++++++------------------ drivers/s390/scsi/zfcp_qdio.c | 16 ++++++++-------- 5 files changed, 30 insertions(+), 31 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index efd60c4af4c6..0a2ffc635c77 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -186,7 +186,7 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); response->fsf_req_status = fsf_req->status; response->sbal_first = fsf_req->sbal_first; - response->sbal_curr = fsf_req->sbal_curr; + response->sbal_last = fsf_req->sbal_last; response->pool = fsf_req->pool != NULL; response->erp_action = (unsigned long)fsf_req->erp_action; @@ -354,7 +354,7 @@ static void zfcp_hba_dbf_view_response(char **p, FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE); zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); - zfcp_dbf_out(p, "sbal_curr", "0x%02x", r->sbal_curr); + zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); zfcp_dbf_out(p, "pool", "0x%02x", r->pool); switch (r->fsf_command) { diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 66b8754840b2..212622ca2e80 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -97,7 +97,7 @@ struct zfcp_hba_dbf_record_response { u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; u32 fsf_req_status; u8 sbal_first; - u8 sbal_curr; + u8 sbal_last; u8 pool; u64 erp_action; union { diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index fdd5520eb3d2..210273d97f00 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -851,10 +851,9 @@ struct zfcp_fsf_req { struct zfcp_adapter *adapter; /* adapter request belongs to */ u8 sbal_number; /* nr of SBALs free for use */ u8 sbal_first; /* first SBAL for this request */ + u8 sbal_last; /* last SBAL for this request */ u8 sbal_limit; /* last possible SBAL for this reuest */ - u8 sbal_curr; /* current SBAL during creation - of request */ u8 sbale_curr; /* current SBALE during creation of request */ wait_queue_head_t completion_wq; /* can be used by a routine diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 2f27d03e61c2..01f9b27daa8c 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -726,7 +726,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) goto failed_req_create; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; fsf_req->sbale_curr = 2; @@ -1075,7 +1075,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, &unit->status))) goto unit_blocked; - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1295,7 +1295,7 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, goto failed_req; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); if (zfcp_use_one_sbal(ct->req, ct->req_count, ct->resp, ct->resp_count)){ /* both request buffer and response buffer @@ -1593,7 +1593,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) goto port_blocked; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); if (zfcp_use_one_sbal(els->req, els->req_count, els->resp, els->resp_count)){ /* both request buffer and response buffer @@ -1657,7 +1657,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT; fsf_req->data = (unsigned long) els; - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); zfcp_san_dbf_event_els_request(fsf_req); @@ -1872,7 +1872,7 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) return retval; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1925,7 +1925,7 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, return retval; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2187,7 +2187,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) return retval; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2249,7 +2249,7 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, if (data) fsf_req->data = (unsigned long) data; - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2359,7 +2359,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2591,7 +2591,7 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2720,7 +2720,7 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2915,7 +2915,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -3230,7 +3230,7 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -3613,7 +3613,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, fsf_req->qtcb->bottom.io.fcp_cmnd_length = sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t); - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -4238,7 +4238,7 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter, goto unlock_queue_lock; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale[0].flags |= direction; bottom = &fsf_req->qtcb->bottom.support; @@ -4590,14 +4590,14 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, } fsf_req->sbal_number = 1; fsf_req->sbal_first = req_queue->free_index; - fsf_req->sbal_curr = req_queue->free_index; + fsf_req->sbal_last = req_queue->free_index; fsf_req->sbale_curr = 1; if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) { fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); /* setup common SBALE fields */ sbale[0].addr = (void *) fsf_req->req_id; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index b6b6b36c6f20..8c83cdc73d98 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -415,7 +415,7 @@ zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) volatile struct qdio_buffer_element * zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) { - return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, + return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, fsf_req->sbale_curr); } @@ -443,7 +443,7 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) * @fsf_req: zfcp_fsf_req to be processed * @sbtype: SBAL flags which have to be set in first SBALE of new SBAL * - * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req. + * This function changes sbal_last, sbale_curr, sbal_number of fsf_req. */ static volatile struct qdio_buffer_element * zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) @@ -455,16 +455,16 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) sbale->flags |= SBAL_FLAGS_LAST_ENTRY; /* don't exceed last allowed SBAL */ - if (fsf_req->sbal_curr == fsf_req->sbal_limit) + if (fsf_req->sbal_last == fsf_req->sbal_limit) return NULL; /* set chaining flag in first SBALE of current SBAL */ - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale->flags |= SBAL_FLAGS0_MORE_SBALS; /* calculate index of next SBAL */ - fsf_req->sbal_curr++; - fsf_req->sbal_curr %= QDIO_MAX_BUFFERS_PER_Q; + fsf_req->sbal_last++; + fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; /* keep this requests number of SBALs up-to-date */ fsf_req->sbal_number++; @@ -523,7 +523,7 @@ static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req) { return zfcp_qdio_sbals_zero(&fsf_req->adapter->request_queue, - fsf_req->sbal_first, fsf_req->sbal_curr); + fsf_req->sbal_first, fsf_req->sbal_last); } @@ -601,7 +601,7 @@ zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, zfcp_qdio_sbal_limit(fsf_req, max_sbals); /* set storage-block type for current SBAL */ - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); sbale->flags |= sbtype; /* process all segements of scatter-gather list */ -- cgit v1.2.3 From c3baa9a26c5ac7e8d801093d55d33620d8bc2fe2 Mon Sep 17 00:00:00 2001 From: Martin Peschke Date: Mon, 19 May 2008 12:17:44 +0200 Subject: [SCSI] zfcp: Add information about interrupt to trace. Store the index of the buffer in the inbound queue used to report request completion in trace record for request coompletion. This piece of information allows to better compare qdio and zfcp traces. Signed-off-by: Martin Peschke Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 2 ++ drivers/s390/scsi/zfcp_dbf.h | 1 + drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_qdio.c | 5 +++-- 4 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 0a2ffc635c77..2bad934a67af 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -187,6 +187,7 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) response->fsf_req_status = fsf_req->status; response->sbal_first = fsf_req->sbal_first; response->sbal_last = fsf_req->sbal_last; + response->sbal_response = fsf_req->sbal_response; response->pool = fsf_req->pool != NULL; response->erp_action = (unsigned long)fsf_req->erp_action; @@ -355,6 +356,7 @@ static void zfcp_hba_dbf_view_response(char **p, zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); + zfcp_dbf_out(p, "sbal_response", "0x%02x", r->sbal_response); zfcp_dbf_out(p, "pool", "0x%02x", r->pool); switch (r->fsf_command) { diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 212622ca2e80..f71176acfab8 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -98,6 +98,7 @@ struct zfcp_hba_dbf_record_response { u32 fsf_req_status; u8 sbal_first; u8 sbal_last; + u8 sbal_response; u8 pool; u64 erp_action; union { diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 210273d97f00..fc61a8ed52d3 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -856,6 +856,7 @@ struct zfcp_fsf_req { this reuest */ u8 sbale_curr; /* current SBALE during creation of request */ + u8 sbal_response; /* SBAL used in interrupt */ wait_queue_head_t completion_wq; /* can be used by a routine to wait for completion */ volatile u32 status; /* status of this request */ diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 8c83cdc73d98..e71547357f62 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -235,7 +235,7 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device, * zfcp_qdio_reqid_check - checks for valid reqids. */ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, - unsigned long req_id) + unsigned long req_id, int sbal) { struct zfcp_fsf_req *fsf_req; unsigned long flags; @@ -255,6 +255,7 @@ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, atomic_dec(&adapter->reqs_active); spin_unlock_irqrestore(&adapter->req_list_lock, flags); + fsf_req->sbal_response = sbal; /* finish the FSF request */ zfcp_fsf_req_complete(fsf_req); } @@ -321,7 +322,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, /* look for QDIO request identifiers in SB */ buffere = &buffer->element[buffere_index]; zfcp_qdio_reqid_check(adapter, - (unsigned long) buffere->addr); + (unsigned long) buffere->addr, i); /* * A single used SBALE per inbound SBALE has been -- cgit v1.2.3 From 70c665405151bc0fdb73ea47c85eb9d0254770b0 Mon Sep 17 00:00:00 2001 From: Martin Peschke Date: Mon, 19 May 2008 12:17:45 +0200 Subject: [SCSI] zfcp: Refine trace levels of some recovery related events. This change better spreads trace levels of recovery related events. There was an overlap of traces for some recovery triggers and the processing of recovery actions. Signed-off-by: Martin Peschke Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 2bad934a67af..e908c0631ace 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -696,7 +696,7 @@ void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter, int lock) r->u.thread.total = total; r->u.thread.ready = ready; r->u.thread.running = running; - debug_event(adapter->rec_dbf, 5, r, sizeof(*r)); + debug_event(adapter->rec_dbf, 6, r, sizeof(*r)); spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); } @@ -823,7 +823,7 @@ void zfcp_rec_dbf_event_action(u8 id2, struct zfcp_erp_action *erp_action) r->u.action.status = erp_action->status; r->u.action.step = erp_action->step; r->u.action.fsf_req = (unsigned long)erp_action->fsf_req; - debug_event(adapter->rec_dbf, 4, r, sizeof(*r)); + debug_event(adapter->rec_dbf, 5, r, sizeof(*r)); spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); } -- cgit v1.2.3 From 7337891f381f856a63595392d7e79f2580912bf7 Mon Sep 17 00:00:00 2001 From: Martin Peschke Date: Mon, 19 May 2008 12:17:46 +0200 Subject: [SCSI] zfcp: remove some __attribute__ ((packed)) There is no need to pack data structures which describe the contents of records in the new recovery trace. lcrash currently depends on the binary format for the other traces, removing the packed attribute from all traces would break trace debugging with lcrash. Signed-off-by: Martin Peschke Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index f71176acfab8..d04aea604974 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -38,7 +38,7 @@ struct zfcp_rec_dbf_record_thread { u32 total; u32 ready; u32 running; -} __attribute__ ((packed)); +}; struct zfcp_rec_dbf_record_target { u64 ref; @@ -47,7 +47,7 @@ struct zfcp_rec_dbf_record_target { u64 wwpn; u64 fcp_lun; u32 erp_count; -} __attribute__ ((packed)); +}; struct zfcp_rec_dbf_record_trigger { u8 want; @@ -59,14 +59,14 @@ struct zfcp_rec_dbf_record_trigger { u64 action; u64 wwpn; u64 fcp_lun; -} __attribute__ ((packed)); +}; struct zfcp_rec_dbf_record_action { u32 status; u32 step; u64 action; u64 fsf_req; -} __attribute__ ((packed)); +}; struct zfcp_rec_dbf_record { u8 id; @@ -77,7 +77,7 @@ struct zfcp_rec_dbf_record { struct zfcp_rec_dbf_record_target target; struct zfcp_rec_dbf_record_trigger trigger; } u; -} __attribute__ ((packed)); +}; enum { ZFCP_REC_DBF_ID_ACTION, -- cgit v1.2.3 From aa0fec62391cd429385e7f3f9fc4a1fb8e2d1218 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 19 May 2008 12:17:47 +0200 Subject: [SCSI] zfcp: Fix sparse warning by providing new entry in dbf drivers/s390/scsi/zfcp_dbf.c:692:2: warning: context imbalance in 'zfcp_rec_dbf_event_thread' - different lock contexts for basic block Replace the parameter indicating if the lock is held with a new entry function that only acquires the lock. This makes the lock handling more visible and removes the sparse warning. Signed-off-by: Christof Schmitt Signed-off-by: Martin Peschke Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 23 +++++++++++++++++------ drivers/s390/scsi/zfcp_erp.c | 18 +++++++++--------- drivers/s390/scsi/zfcp_ext.h | 4 ++-- 3 files changed, 28 insertions(+), 17 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index e908c0631ace..558dae9639f3 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -670,24 +670,20 @@ static struct debug_view zfcp_rec_dbf_view = { * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation * @id2: identifier for event * @adapter: adapter - * @lock: non-zero value indicates that erp_lock has not yet been acquired + * This function assumes that the caller is holding erp_lock. */ -void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter, int lock) +void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter) { struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; unsigned long flags = 0; struct list_head *entry; unsigned ready = 0, running = 0, total; - if (lock) - read_lock_irqsave(&adapter->erp_lock, flags); list_for_each(entry, &adapter->erp_ready_head) ready++; list_for_each(entry, &adapter->erp_running_head) running++; total = adapter->erp_total_count; - if (lock) - read_unlock_irqrestore(&adapter->erp_lock, flags); spin_lock_irqsave(&adapter->rec_dbf_lock, flags); memset(r, 0, sizeof(*r)); @@ -700,6 +696,21 @@ void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter, int lock) spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); } +/** + * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation + * @id2: identifier for event + * @adapter: adapter + * This function assumes that the caller does not hold erp_lock. + */ +void zfcp_rec_dbf_event_thread_lock(u8 id2, struct zfcp_adapter *adapter) +{ + unsigned long flags; + + read_lock_irqsave(&adapter->erp_lock, flags); + zfcp_rec_dbf_event_thread(id2, adapter); + read_unlock_irqrestore(&adapter->erp_lock, flags); +} + static void zfcp_rec_dbf_event_target(u8 id2, void *ref, struct zfcp_adapter *adapter, atomic_t *status, atomic_t *erp_count, diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 55a4fdc42626..d05b37054897 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -783,7 +783,7 @@ zfcp_erp_action_ready(struct zfcp_erp_action *erp_action) zfcp_erp_action_to_ready(erp_action); up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread(2, adapter, 0); + zfcp_rec_dbf_event_thread(2, adapter); } /* @@ -995,7 +995,7 @@ zfcp_erp_thread_kill(struct zfcp_adapter *adapter) atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread(2, adapter, 1); + zfcp_rec_dbf_event_thread_lock(2, adapter); wait_event(adapter->erp_thread_wqh, !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, @@ -1050,9 +1050,9 @@ zfcp_erp_thread(void *data) * no action in 'ready' queue to be processed and * thread is not to be killed */ - zfcp_rec_dbf_event_thread(4, adapter, 1); + zfcp_rec_dbf_event_thread_lock(4, adapter); down_interruptible(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread(5, adapter, 1); + zfcp_rec_dbf_event_thread_lock(5, adapter); } atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); @@ -2062,9 +2062,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) * _must_ be the one belonging to the 'exchange config * data' request. */ - zfcp_rec_dbf_event_thread(6, adapter, 1); + zfcp_rec_dbf_event_thread_lock(6, adapter); down(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread(7, adapter, 1); + zfcp_rec_dbf_event_thread_lock(7, adapter); if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { ZFCP_LOG_INFO("error: exchange of configuration data " "for adapter %s timed out\n", @@ -2118,9 +2118,9 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) } ret = ZFCP_ERP_SUCCEEDED; - zfcp_rec_dbf_event_thread(8, adapter, 1); + zfcp_rec_dbf_event_thread_lock(8, adapter); down(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread(9, adapter, 1); + zfcp_rec_dbf_event_thread_lock(9, adapter); if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { ZFCP_LOG_INFO("error: exchange port data timed out (adapter " "%s)\n", zfcp_get_busid_by_adapter(adapter)); @@ -2876,7 +2876,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, /* finally put it into 'ready' queue and kick erp thread */ list_add_tail(&erp_action->list, &adapter->erp_ready_head); up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread(1, adapter, 0); + zfcp_rec_dbf_event_thread(1, adapter); retval = 0; out: zfcp_rec_dbf_event_trigger(id, ref, want, need, erp_action, diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 16213cbbc4ba..e47ab8d05b67 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -169,8 +169,8 @@ extern void zfcp_erp_port_access_changed(struct zfcp_port *, u8, void *); extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *); /******************************** AUX ****************************************/ -extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter, - int lock); +extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter); +extern void zfcp_rec_dbf_event_thread_lock(u8 id, struct zfcp_adapter *adapter); extern void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *); extern void zfcp_rec_dbf_event_port(u8 id, void *ref, struct zfcp_port *port); extern void zfcp_rec_dbf_event_unit(u8 id, void *ref, struct zfcp_unit *unit); -- cgit v1.2.3 From 24073b475d6d2bad8880434a16343ee1da816ea5 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 10 Jun 2008 18:20:54 +0200 Subject: [SCSI] zfcp: Move FC code to new file Move all Fibre Channel related code to new file and cleanup the code while doing so. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/Makefile | 2 +- drivers/s390/scsi/zfcp_aux.c | 518 ------------------------------------------- drivers/s390/scsi/zfcp_dbf.c | 4 +- drivers/s390/scsi/zfcp_def.h | 8 +- drivers/s390/scsi/zfcp_erp.c | 188 +--------------- drivers/s390/scsi/zfcp_ext.h | 12 +- drivers/s390/scsi/zfcp_fc.c | 305 +++++++++++++++++++++++++ drivers/s390/scsi/zfcp_fsf.c | 8 +- 8 files changed, 319 insertions(+), 726 deletions(-) create mode 100644 drivers/s390/scsi/zfcp_fc.c (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index d6a78f1a2f16..f775f9e6030c 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -4,6 +4,6 @@ zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ - zfcp_sysfs_unit.o zfcp_sysfs_driver.o + zfcp_sysfs_unit.o zfcp_sysfs_driver.o zfcp_fc.o obj-$(CONFIG_ZFCP) += zfcp.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 9a3c138ec50c..9eb8827e19e2 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -43,9 +43,6 @@ static char *device; /* written against the module interface */ static int __init zfcp_module_init(void); -/* FCP related */ -static void zfcp_ns_gid_pn_handler(unsigned long); - /* miscellaneous */ static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); static void zfcp_sg_list_free(struct zfcp_sg_list *); @@ -1349,518 +1346,3 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) } #undef ZFCP_LOG_AREA - -/****************************************************************/ -/******* Fibre Channel Standard related Functions **************/ -/****************************************************************/ - -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC - -static void zfcp_fsf_incoming_els_rscn(struct zfcp_fsf_req *fsf_req) -{ - struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct fcp_rscn_head *fcp_rscn_head; - struct fcp_rscn_element *fcp_rscn_element; - struct zfcp_port *port; - u16 i; - u16 no_entries; - u32 range_mask; - unsigned long flags; - - fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; - fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; - - /* see FC-FS */ - no_entries = (fcp_rscn_head->payload_len / 4); - - for (i = 1; i < no_entries; i++) { - /* skip head and start with 1st element */ - fcp_rscn_element++; - switch (fcp_rscn_element->addr_format) { - case ZFCP_PORT_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_PORT; - break; - case ZFCP_AREA_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_AREA; - break; - case ZFCP_DOMAIN_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_DOMAIN; - break; - case ZFCP_FABRIC_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_FABRIC; - break; - default: - ZFCP_LOG_INFO("incoming RSCN with unknown " - "address format\n"); - continue; - } - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) { - if (atomic_test_mask - (ZFCP_STATUS_PORT_WKA, &port->status)) - continue; - /* Do we know this port? If not skip it. */ - if (!atomic_test_mask - (ZFCP_STATUS_PORT_DID_DID, &port->status)) { - ZFCP_LOG_INFO("incoming RSCN, trying to open " - "port 0x%016Lx\n", port->wwpn); - zfcp_erp_port_reopen(port, - ZFCP_STATUS_COMMON_ERP_FAILED, - 82, fsf_req); - continue; - } - - /* - * FIXME: race: d_id might being invalidated - * (...DID_DID reset) - */ - if ((port->d_id & range_mask) - == (fcp_rscn_element->nport_did & range_mask)) { - ZFCP_LOG_TRACE("reopen did 0x%08x\n", - fcp_rscn_element->nport_did); - /* - * Unfortunately, an RSCN does not specify the - * type of change a target underwent. We assume - * that it makes sense to reopen the link. - * FIXME: Shall we try to find out more about - * the target and link state before closing it? - * How to accomplish this? (nameserver?) - * Where would such code be put in? - * (inside or outside erp) - */ - ZFCP_LOG_INFO("incoming RSCN, trying to open " - "port 0x%016Lx\n", port->wwpn); - zfcp_test_link(port); - } - } - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - } -} - -static void zfcp_fsf_incoming_els_plogi(struct zfcp_fsf_req *fsf_req) -{ - struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct fsf_plogi *els_plogi; - struct zfcp_port *port; - unsigned long flags; - - els_plogi = (struct fsf_plogi *) status_buffer->payload; - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) { - if (port->wwpn == (*(wwn_t *) &els_plogi->serv_param.wwpn)) - break; - } - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - - if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) { - ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port " - "with d_id 0x%06x on adapter %s\n", - status_buffer->d_id, - zfcp_get_busid_by_adapter(adapter)); - } else { - zfcp_erp_port_forced_reopen(port, 0, 83, fsf_req); - } -} - -static void zfcp_fsf_incoming_els_logo(struct zfcp_fsf_req *fsf_req) -{ - struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; - struct zfcp_port *port; - unsigned long flags; - - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) { - if (port->wwpn == els_logo->nport_wwpn) - break; - } - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - - if (!port || (port->wwpn != els_logo->nport_wwpn)) { - ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port " - "with d_id 0x%06x on adapter %s\n", - status_buffer->d_id, - zfcp_get_busid_by_adapter(adapter)); - } else { - zfcp_erp_port_forced_reopen(port, 0, 84, fsf_req); - } -} - -static void -zfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter, - struct fsf_status_read_buffer *status_buffer) -{ - ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x " - "for adapter %s\n", *(u32 *) (status_buffer->payload), - zfcp_get_busid_by_adapter(adapter)); - -} - -void -zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req) -{ - struct fsf_status_read_buffer *status_buffer; - u32 els_type; - struct zfcp_adapter *adapter; - - status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; - els_type = *(u32 *) (status_buffer->payload); - adapter = fsf_req->adapter; - - zfcp_san_dbf_event_incoming_els(fsf_req); - if (els_type == LS_PLOGI) - zfcp_fsf_incoming_els_plogi(fsf_req); - else if (els_type == LS_LOGO) - zfcp_fsf_incoming_els_logo(fsf_req); - else if ((els_type & 0xffff0000) == LS_RSCN) - /* we are only concerned with the command, not the length */ - zfcp_fsf_incoming_els_rscn(fsf_req); - else - zfcp_fsf_incoming_els_unknown(adapter, status_buffer); -} - - -/** - * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request - * @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data - * @pool: pointer to mempool_t if non-null memory pool is used for allocation - */ -static int -zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool) -{ - struct zfcp_gid_pn_data *data; - - if (pool) - data = mempool_alloc(pool, GFP_ATOMIC); - else - data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC); - - if (NULL == data) - return -ENOMEM; - - memset(data, 0, sizeof(*data)); - data->ct.pool = pool; - sg_init_table(&data->req , 1); - sg_init_table(&data->resp , 1); - data->ct.req = &data->req; - data->ct.resp = &data->resp; - data->ct.req_count = data->ct.resp_count = 1; - zfcp_address_to_sg(&data->ct_iu_req, &data->req, sizeof(struct ct_iu_gid_pn_req)); - zfcp_address_to_sg(&data->ct_iu_resp, &data->resp, sizeof(struct ct_iu_gid_pn_resp)); - - *gid_pn = data; - return 0; -} - -/** - * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request - * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed - */ -static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn) -{ - if (gid_pn->ct.pool) - mempool_free(gid_pn, gid_pn->ct.pool); - else - kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn); -} - -/** - * zfcp_ns_gid_pn_request - initiate GID_PN nameserver request - * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed - */ -int -zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action) -{ - int ret; - struct ct_iu_gid_pn_req *ct_iu_req; - struct zfcp_gid_pn_data *gid_pn; - struct zfcp_adapter *adapter = erp_action->adapter; - - ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn); - if (ret < 0) { - ZFCP_LOG_INFO("error: buffer allocation for gid_pn nameserver " - "request failed for adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - goto out; - } - - /* setup nameserver request */ - ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req); - ct_iu_req->header.revision = ZFCP_CT_REVISION; - ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; - ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER; - ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS; - ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN; - ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE; - ct_iu_req->wwpn = erp_action->port->wwpn; - - /* setup parameters for send generic command */ - gid_pn->ct.port = adapter->nameserver_port; - gid_pn->ct.handler = zfcp_ns_gid_pn_handler; - gid_pn->ct.handler_data = (unsigned long) gid_pn; - gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; - gid_pn->port = erp_action->port; - - ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, - erp_action); - if (ret) { - ZFCP_LOG_INFO("error: initiation of gid_pn nameserver request " - "failed for adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - - zfcp_gid_pn_buffers_free(gid_pn); - } - - out: - return ret; -} - -/** - * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request - * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data - */ -static void zfcp_ns_gid_pn_handler(unsigned long data) -{ - struct zfcp_port *port; - struct zfcp_send_ct *ct; - struct ct_iu_gid_pn_req *ct_iu_req; - struct ct_iu_gid_pn_resp *ct_iu_resp; - struct zfcp_gid_pn_data *gid_pn; - - - gid_pn = (struct zfcp_gid_pn_data *) data; - port = gid_pn->port; - ct = &gid_pn->ct; - ct_iu_req = zfcp_sg_to_address(ct->req); - ct_iu_resp = zfcp_sg_to_address(ct->resp); - - if (ct->status != 0) - goto failed; - - if (zfcp_check_ct_response(&ct_iu_resp->header)) { - /* FIXME: do we need some specific erp entry points */ - atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); - goto failed; - } - /* paranoia */ - if (ct_iu_req->wwpn != port->wwpn) { - ZFCP_LOG_NORMAL("bug: wwpn 0x%016Lx returned by nameserver " - "lookup does not match expected wwpn 0x%016Lx " - "for adapter %s\n", ct_iu_req->wwpn, port->wwpn, - zfcp_get_busid_by_port(port)); - goto mismatch; - } - - /* looks like a valid d_id */ - port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; - atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); - ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%06x\n", - zfcp_get_busid_by_port(port), port->wwpn, port->d_id); - goto out; - - mismatch: - ZFCP_LOG_DEBUG("CT IUs do not match:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req, - sizeof(struct ct_iu_gid_pn_req)); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp, - sizeof(struct ct_iu_gid_pn_resp)); - - failed: - ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn " - "0x%016Lx for adapter %s\n", - port->wwpn, zfcp_get_busid_by_port(port)); - out: - zfcp_gid_pn_buffers_free(gid_pn); - return; -} - -/* reject CT_IU reason codes acc. to FC-GS-4 */ -static const struct zfcp_rc_entry zfcp_ct_rc[] = { - {0x01, "invalid command code"}, - {0x02, "invalid version level"}, - {0x03, "logical error"}, - {0x04, "invalid CT_IU size"}, - {0x05, "logical busy"}, - {0x07, "protocol error"}, - {0x09, "unable to perform command request"}, - {0x0b, "command not supported"}, - {0x0d, "server not available"}, - {0x0e, "session could not be established"}, - {0xff, "vendor specific error"}, - {0, NULL}, -}; - -/* LS_RJT reason codes acc. to FC-FS */ -static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = { - {0x01, "invalid LS_Command code"}, - {0x03, "logical error"}, - {0x05, "logical busy"}, - {0x07, "protocol error"}, - {0x09, "unable to perform command request"}, - {0x0b, "command not supported"}, - {0x0e, "command already in progress"}, - {0xff, "vendor specific error"}, - {0, NULL}, -}; - -/* reject reason codes according to FC-PH/FC-FS */ -static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { - {0x01, "invalid D_ID"}, - {0x02, "invalid S_ID"}, - {0x03, "Nx_Port not available, temporary"}, - {0x04, "Nx_Port not available, permament"}, - {0x05, "class not supported"}, - {0x06, "delimiter usage error"}, - {0x07, "TYPE not supported"}, - {0x08, "invalid Link_Control"}, - {0x09, "invalid R_CTL field"}, - {0x0a, "invalid F_CTL field"}, - {0x0b, "invalid OX_ID"}, - {0x0c, "invalid RX_ID"}, - {0x0d, "invalid SEQ_ID"}, - {0x0e, "invalid DF_CTL"}, - {0x0f, "invalid SEQ_CNT"}, - {0x10, "invalid parameter field"}, - {0x11, "exchange error"}, - {0x12, "protocol error"}, - {0x13, "incorrect length"}, - {0x14, "unsupported ACK"}, - {0x15, "class of service not supported by entity at FFFFFE"}, - {0x16, "login required"}, - {0x17, "excessive sequences attempted"}, - {0x18, "unable to establish exchange"}, - {0x1a, "fabric path not available"}, - {0x1b, "invalid VC_ID (class 4)"}, - {0x1c, "invalid CS_CTL field"}, - {0x1d, "insufficient resources for VC (class 4)"}, - {0x1f, "invalid class of service"}, - {0x20, "preemption request rejected"}, - {0x21, "preemption not enabled"}, - {0x22, "multicast error"}, - {0x23, "multicast error terminate"}, - {0x24, "process login required"}, - {0xff, "vendor specific reject"}, - {0, NULL}, -}; - -/** - * zfcp_rc_description - return description for given reaon code - * @code: reason code - * @rc_table: table of reason codes and descriptions - */ -static const char * -zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) -{ - const char *descr = "unknown reason code"; - - do { - if (code == rc_table->code) { - descr = rc_table->description; - break; - } - rc_table++; - } while (rc_table->code && rc_table->description); - - return descr; -} - -/** - * zfcp_check_ct_response - evaluate reason code for CT_IU - * @rjt: response payload to an CT_IU request - * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code - */ -int -zfcp_check_ct_response(struct ct_hdr *rjt) -{ - if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT) - return 0; - - if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) { - ZFCP_LOG_NORMAL("error: invalid Generic Service command/" - "response code (0x%04hx)\n", - rjt->cmd_rsp_code); - return 1; - } - - ZFCP_LOG_INFO("Generic Service command rejected\n"); - ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n", - zfcp_rc_description(rjt->reason_code, zfcp_ct_rc), - (u32) rjt->reason_code, (u32) rjt->reason_code_expl, - (u32) rjt->vendor_unique); - - return 1; -} - -/** - * zfcp_print_els_rjt - print reject parameter and description for ELS reject - * @rjt_par: reject parameter acc. to FC-PH/FC-FS - * @rc_table: table of reason codes and descriptions - */ -static void -zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, - const struct zfcp_rc_entry *rc_table) -{ - ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n", - zfcp_rc_description(rjt_par->reason_code, rc_table), - (u32) rjt_par->action, (u32) rjt_par->reason_code, - (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique); -} - -/** - * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject - * @sq: status qualifier word - * @rjt_par: reject parameter as described in FC-PH and FC-FS - * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else - */ -int -zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par) -{ - int ret = -EIO; - - if (sq == FSF_IOSTAT_NPORT_RJT) { - ZFCP_LOG_INFO("ELS rejected (P_RJT)\n"); - zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); - /* invalid d_id */ - if (rjt_par->reason_code == 0x01) - ret = -EREMCHG; - } else if (sq == FSF_IOSTAT_FABRIC_RJT) { - ZFCP_LOG_INFO("ELS rejected (F_RJT)\n"); - zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); - /* invalid d_id */ - if (rjt_par->reason_code == 0x01) - ret = -EREMCHG; - } else if (sq == FSF_IOSTAT_LS_RJT) { - ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n"); - zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc); - ret = -EREMOTEIO; - } else - ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq); - - return ret; -} - -/** - * zfcp_plogi_evaluate - evaluate PLOGI playload and copy important fields - * into zfcp_port structure - * @port: zfcp_port structure - * @plogi: plogi payload - */ -void -zfcp_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) -{ - port->maxframe_size = plogi->serv_param.common_serv_param[7] | - ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); - if (plogi->serv_param.class1_serv_param[0] & 0x80) - port->supported_classes |= FC_COS_CLASS1; - if (plogi->serv_param.class2_serv_param[0] & 0x80) - port->supported_classes |= FC_COS_CLASS2; - if (plogi->serv_param.class3_serv_param[0] & 0x80) - port->supported_classes |= FC_COS_CLASS3; - if (plogi->serv_param.class4_serv_param[0] & 0x80) - port->supported_classes |= FC_COS_CLASS4; -} - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 558dae9639f3..01e817abe0a5 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -546,8 +546,8 @@ static const char *zfcp_rec_dbf_ids[] = { [80] = "exclusive read-only unit access unsupported", [81] = "shared read-write unit access unsupported", [82] = "incoming rscn", - [83] = "incoming plogi", - [84] = "incoming logo", + [83] = "incoming wwpn", + [84] = "", [85] = "online", [86] = "offline", [87] = "ccw device gone", diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index fc61a8ed52d3..d23c3b9b283e 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -223,9 +223,9 @@ struct fcp_rsp_iu { #define RSP_CODE_TASKMAN_FAILED 5 /* see fc-fs */ -#define LS_RSCN 0x61040000 -#define LS_LOGO 0x05000000 -#define LS_PLOGI 0x03000000 +#define LS_RSCN 0x61 +#define LS_LOGO 0x05 +#define LS_PLOGI 0x03 struct fcp_rscn_head { u8 command; @@ -622,7 +622,6 @@ typedef void (*zfcp_send_ct_handler_t)(unsigned long); * @resp_count: number of elements in response scatter-gather list * @handler: handler function (called for response to the request) * @handler_data: data passed to handler function - * @pool: pointer to memory pool for ct request structure * @timeout: FSF timeout for this request * @completion: completion for synchronization purposes * @status: used to pass error status to calling function @@ -635,7 +634,6 @@ struct zfcp_send_ct { unsigned int resp_count; zfcp_send_ct_handler_t handler; unsigned long handler_data; - mempool_t *pool; int timeout; struct completion *completion; int status; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d05b37054897..ee19be13e708 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -23,9 +23,6 @@ #include "zfcp_ext.h" -static int zfcp_erp_adisc(struct zfcp_port *); -static void zfcp_erp_adisc_handler(unsigned long); - static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int, u8, void *); static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int, u8, @@ -292,189 +289,6 @@ int zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask, u8 id, return retval; } - -/** - * zfcp_erp_adisc - send ADISC ELS command - * @port: port structure - */ -static int -zfcp_erp_adisc(struct zfcp_port *port) -{ - struct zfcp_adapter *adapter = port->adapter; - struct zfcp_send_els *send_els; - struct zfcp_ls_adisc *adisc; - void *address = NULL; - int retval = 0; - - send_els = kzalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC); - if (send_els == NULL) - goto nomem; - - send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); - if (send_els->req == NULL) - goto nomem; - sg_init_table(send_els->req, 1); - - send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); - if (send_els->resp == NULL) - goto nomem; - sg_init_table(send_els->resp, 1); - - address = (void *) get_zeroed_page(GFP_ATOMIC); - if (address == NULL) - goto nomem; - - zfcp_address_to_sg(address, send_els->req, sizeof(struct zfcp_ls_adisc)); - address += PAGE_SIZE >> 1; - zfcp_address_to_sg(address, send_els->resp, sizeof(struct zfcp_ls_adisc_acc)); - send_els->req_count = send_els->resp_count = 1; - - send_els->adapter = adapter; - send_els->port = port; - send_els->d_id = port->d_id; - send_els->handler = zfcp_erp_adisc_handler; - send_els->handler_data = (unsigned long) send_els; - - adisc = zfcp_sg_to_address(send_els->req); - send_els->ls_code = adisc->code = ZFCP_LS_ADISC; - - /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports - without FC-AL-2 capability, so we don't set it */ - adisc->wwpn = fc_host_port_name(adapter->scsi_host); - adisc->wwnn = fc_host_node_name(adapter->scsi_host); - adisc->nport_id = fc_host_port_id(adapter->scsi_host); - ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x " - "(wwpn=0x%016Lx, wwnn=0x%016Lx, " - "hard_nport_id=0x%06x, nport_id=0x%06x)\n", - adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn, - (wwn_t) adisc->wwnn, adisc->hard_nport_id, - adisc->nport_id); - - retval = zfcp_fsf_send_els(send_els); - if (retval != 0) { - ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port " - "0x%06x on adapter %s\n", send_els->d_id, - zfcp_get_busid_by_adapter(adapter)); - goto freemem; - } - - goto out; - - nomem: - retval = -ENOMEM; - freemem: - if (address != NULL) - __free_pages(sg_page(send_els->req), 0); - if (send_els != NULL) { - kfree(send_els->req); - kfree(send_els->resp); - kfree(send_els); - } - out: - return retval; -} - - -/** - * zfcp_erp_adisc_handler - handler for ADISC ELS command - * @data: pointer to struct zfcp_send_els - * - * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered. - */ -static void -zfcp_erp_adisc_handler(unsigned long data) -{ - struct zfcp_send_els *send_els; - struct zfcp_port *port; - struct zfcp_adapter *adapter; - u32 d_id; - struct zfcp_ls_adisc_acc *adisc; - - send_els = (struct zfcp_send_els *) data; - adapter = send_els->adapter; - port = send_els->port; - d_id = send_els->d_id; - - /* request rejected or timed out */ - if (send_els->status != 0) { - ZFCP_LOG_NORMAL("ELS request rejected/timed out, " - "force physical port reopen " - "(adapter %s, port d_id=0x%06x)\n", - zfcp_get_busid_by_adapter(adapter), d_id); - if (zfcp_erp_port_forced_reopen(port, 0, 63, NULL)) - ZFCP_LOG_NORMAL("failed reopen of port " - "(adapter %s, wwpn=0x%016Lx)\n", - zfcp_get_busid_by_port(port), - port->wwpn); - goto out; - } - - adisc = zfcp_sg_to_address(send_els->resp); - - ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id " - "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, " - "hard_nport_id=0x%06x, nport_id=0x%06x)\n", - d_id, fc_host_port_id(adapter->scsi_host), - (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, - adisc->hard_nport_id, adisc->nport_id); - - /* set wwnn for port */ - if (port->wwnn == 0) - port->wwnn = adisc->wwnn; - - if (port->wwpn != adisc->wwpn) { - ZFCP_LOG_NORMAL("d_id assignment changed, reopening " - "port (adapter %s, wwpn=0x%016Lx, " - "adisc_resp_wwpn=0x%016Lx)\n", - zfcp_get_busid_by_port(port), - port->wwpn, (wwn_t) adisc->wwpn); - if (zfcp_erp_port_reopen(port, 0, 64, NULL)) - ZFCP_LOG_NORMAL("failed reopen of port " - "(adapter %s, wwpn=0x%016Lx)\n", - zfcp_get_busid_by_port(port), - port->wwpn); - } - - out: - zfcp_port_put(port); - __free_pages(sg_page(send_els->req), 0); - kfree(send_els->req); - kfree(send_els->resp); - kfree(send_els); -} - - -/** - * zfcp_test_link - lightweight link test procedure - * @port: port to be tested - * - * Test status of a link to a remote port using the ELS command ADISC. - */ -int -zfcp_test_link(struct zfcp_port *port) -{ - int retval; - - zfcp_port_get(port); - retval = zfcp_erp_adisc(port); - if (retval != 0 && retval != -EBUSY) { - zfcp_port_put(port); - ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx " - "on adapter %s\n ", port->wwpn, - zfcp_get_busid_by_port(port)); - retval = zfcp_erp_port_forced_reopen(port, 0, 65, NULL); - if (retval != 0) { - ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx " - "on adapter %s failed\n", port->wwpn, - zfcp_get_busid_by_port(port)); - retval = -EPERM; - } - } - - return retval; -} - - /* * function: * @@ -2564,7 +2378,7 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action) { int retval; - retval = zfcp_ns_gid_pn_request(erp_action); + retval = zfcp_fc_ns_gid_pn_request(erp_action); if (retval == -ENOMEM) { retval = ZFCP_ERP_NOMEM; goto out; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index e47ab8d05b67..91d58843205c 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -103,7 +103,6 @@ extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, struct zfcp_unit *, struct scsi_cmnd *, int, int); extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); -extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management( struct zfcp_adapter *, struct zfcp_unit *, u8, int); @@ -111,11 +110,12 @@ extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command( unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int); /******************************* FC/FCP **************************************/ +extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); +extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); +extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); +extern void zfcp_test_link(struct zfcp_port *); + extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); -extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *); -extern int zfcp_check_ct_response(struct ct_hdr *); -extern int zfcp_handle_els_rjt(u32, struct zfcp_ls_rjt_par *); -extern void zfcp_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); /******************************* SCSI ****************************************/ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); @@ -158,8 +158,6 @@ extern int zfcp_erp_thread_kill(struct zfcp_adapter *); extern int zfcp_erp_wait(struct zfcp_adapter *); extern void zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long); -extern int zfcp_test_link(struct zfcp_port *); - extern void zfcp_erp_port_boxed(struct zfcp_port *, u8 id, void *ref); extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8 id, void *ref); extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8 id, void *ref); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c new file mode 100644 index 000000000000..bb07c3bf2258 --- /dev/null +++ b/drivers/s390/scsi/zfcp_fc.c @@ -0,0 +1,305 @@ +/* + * zfcp device driver + * + * Fibre Channel related functions for the zfcp device driver. + * + * Copyright IBM Corporation 2008 + */ + +#include "zfcp_ext.h" + +static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, + struct fcp_rscn_element *elem) +{ + unsigned long flags; + struct zfcp_port *port; + + read_lock_irqsave(&zfcp_data.config_lock, flags); + list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { + if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) + continue; + /* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */ + if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) + /* Try to connect to unused ports anyway. */ + zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED, + 82, fsf_req); + else if ((port->d_id & range) == (elem->nport_did & range)) + /* Check connection status for connected ports */ + zfcp_test_link(port); + } + read_unlock_irqrestore(&zfcp_data.config_lock, flags); +} + +static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) +{ + struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data; + struct fcp_rscn_head *fcp_rscn_head; + struct fcp_rscn_element *fcp_rscn_element; + u16 i; + u16 no_entries; + u32 range_mask; + + fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; + fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; + + /* see FC-FS */ + no_entries = fcp_rscn_head->payload_len / + sizeof(struct fcp_rscn_element); + + for (i = 1; i < no_entries; i++) { + /* skip head and start with 1st element */ + fcp_rscn_element++; + switch (fcp_rscn_element->addr_format) { + case ZFCP_PORT_ADDRESS: + range_mask = ZFCP_PORTS_RANGE_PORT; + break; + case ZFCP_AREA_ADDRESS: + range_mask = ZFCP_PORTS_RANGE_AREA; + break; + case ZFCP_DOMAIN_ADDRESS: + range_mask = ZFCP_PORTS_RANGE_DOMAIN; + break; + case ZFCP_FABRIC_ADDRESS: + range_mask = ZFCP_PORTS_RANGE_FABRIC; + break; + default: + continue; + } + _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); + } +} + +static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) +{ + struct zfcp_adapter *adapter = req->adapter; + struct zfcp_port *port; + unsigned long flags; + + read_lock_irqsave(&zfcp_data.config_lock, flags); + list_for_each_entry(port, &adapter->port_list_head, list) + if (port->wwpn == wwpn) + break; + read_unlock_irqrestore(&zfcp_data.config_lock, flags); + + if (port && (port->wwpn == wwpn)) + zfcp_erp_port_forced_reopen(port, 0, 83, req); +} + +static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) +{ + struct fsf_status_read_buffer *status_buffer = + (struct fsf_status_read_buffer *)req->data; + struct fsf_plogi *els_plogi = + (struct fsf_plogi *) status_buffer->payload; + + zfcp_fc_incoming_wwpn(req, els_plogi->serv_param.wwpn); +} + +static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req) +{ + struct fsf_status_read_buffer *status_buffer = + (struct fsf_status_read_buffer *)req->data; + struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; + + zfcp_fc_incoming_wwpn(req, els_logo->nport_wwpn); +} + +/** + * zfcp_fc_incoming_els - handle incoming ELS + * @fsf_req - request which contains incoming ELS + */ +void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) +{ + struct fsf_status_read_buffer *status_buffer = + (struct fsf_status_read_buffer *) fsf_req->data; + unsigned int els_type = status_buffer->payload[0]; + + zfcp_san_dbf_event_incoming_els(fsf_req); + if (els_type == LS_PLOGI) + zfcp_fc_incoming_plogi(fsf_req); + else if (els_type == LS_LOGO) + zfcp_fc_incoming_logo(fsf_req); + else if (els_type == LS_RSCN) + zfcp_fc_incoming_rscn(fsf_req); +} + +static void zfcp_ns_gid_pn_handler(unsigned long data) +{ + struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data; + struct zfcp_send_ct *ct = &gid_pn->ct; + struct ct_iu_gid_pn_req *ct_iu_req = sg_virt(ct->req); + struct ct_iu_gid_pn_resp *ct_iu_resp = sg_virt(ct->resp); + struct zfcp_port *port = gid_pn->port; + + if (ct->status) + goto out; + if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) { + atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); + goto out; + } + /* paranoia */ + if (ct_iu_req->wwpn != port->wwpn) + goto out; + /* looks like a valid d_id */ + port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; + atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); +out: + mempool_free(gid_pn, port->adapter->pool.data_gid_pn); +} + +/** + * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request + * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed + * return: -ENOMEM on error, 0 otherwise + */ +int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action) +{ + int ret; + struct zfcp_gid_pn_data *gid_pn; + struct zfcp_adapter *adapter = erp_action->adapter; + + gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC); + if (!gid_pn) + return -ENOMEM; + + memset(gid_pn, 0, sizeof(*gid_pn)); + + /* setup parameters for send generic command */ + gid_pn->port = erp_action->port; + gid_pn->ct.port = adapter->nameserver_port; + gid_pn->ct.handler = zfcp_ns_gid_pn_handler; + gid_pn->ct.handler_data = (unsigned long) gid_pn; + gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; + gid_pn->ct.req = &gid_pn->req; + gid_pn->ct.resp = &gid_pn->resp; + gid_pn->ct.req_count = 1; + gid_pn->ct.resp_count = 1; + sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, + sizeof(struct ct_iu_gid_pn_req)); + sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, + sizeof(struct ct_iu_gid_pn_resp)); + + /* setup nameserver request */ + gid_pn->ct_iu_req.header.revision = ZFCP_CT_REVISION; + gid_pn->ct_iu_req.header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; + gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; + gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; + gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; + gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; + gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; + + ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, + erp_action); + if (ret) + mempool_free(gid_pn, adapter->pool.data_gid_pn); + return ret; +} + +/** + * zfcp_fc_plogi_evaluate - evaluate PLOGI playload + * @port: zfcp_port structure + * @plogi: plogi payload + * + * Evaluate PLOGI playload and copy important fields into zfcp_port structure + */ +void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) +{ + port->maxframe_size = plogi->serv_param.common_serv_param[7] | + ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); + if (plogi->serv_param.class1_serv_param[0] & 0x80) + port->supported_classes |= FC_COS_CLASS1; + if (plogi->serv_param.class2_serv_param[0] & 0x80) + port->supported_classes |= FC_COS_CLASS2; + if (plogi->serv_param.class3_serv_param[0] & 0x80) + port->supported_classes |= FC_COS_CLASS3; + if (plogi->serv_param.class4_serv_param[0] & 0x80) + port->supported_classes |= FC_COS_CLASS4; +} + +struct zfcp_els_adisc { + struct zfcp_send_els els; + struct scatterlist req; + struct scatterlist resp; + struct zfcp_ls_adisc ls_adisc; + struct zfcp_ls_adisc_acc ls_adisc_acc; +}; + +static void zfcp_fc_adisc_handler(unsigned long data) +{ + struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data; + struct zfcp_port *port = adisc->els.port; + struct zfcp_ls_adisc_acc *ls_adisc = &adisc->ls_adisc_acc; + + if (!adisc->els.status) { + /* request rejected or timed out */ + zfcp_erp_port_forced_reopen(port, 0, 63, NULL); + goto out; + } + + if (!port->wwnn) + port->wwnn = ls_adisc->wwnn; + + if (port->wwpn != ls_adisc->wwpn) + zfcp_erp_port_reopen(port, 0, 64, NULL); + + out: + zfcp_port_put(port); + kfree(adisc); +} + +static int zfcp_fc_adisc(struct zfcp_port *port) +{ + struct zfcp_els_adisc *adisc; + struct zfcp_adapter *adapter = port->adapter; + + adisc = kzalloc(sizeof(struct zfcp_els_adisc), GFP_ATOMIC); + if (!adisc) + return -ENOMEM; + + adisc->els.req = &adisc->req; + adisc->els.resp = &adisc->resp; + sg_init_one(adisc->els.req, &adisc->ls_adisc, + sizeof(struct zfcp_ls_adisc)); + sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, + sizeof(struct zfcp_ls_adisc_acc)); + + adisc->els.req_count = 1; + adisc->els.resp_count = 1; + adisc->els.adapter = adapter; + adisc->els.port = port; + adisc->els.d_id = port->d_id; + adisc->els.handler = zfcp_fc_adisc_handler; + adisc->els.handler_data = (unsigned long) adisc; + adisc->els.ls_code = adisc->ls_adisc.code = ZFCP_LS_ADISC; + + /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports + without FC-AL-2 capability, so we don't set it */ + adisc->ls_adisc.wwpn = fc_host_port_name(adapter->scsi_host); + adisc->ls_adisc.wwnn = fc_host_node_name(adapter->scsi_host); + adisc->ls_adisc.nport_id = fc_host_port_id(adapter->scsi_host); + + return zfcp_fsf_send_els(&adisc->els); +} + +/** + * zfcp_test_link - lightweight link test procedure + * @port: port to be tested + * + * Test status of a link to a remote port using the ELS command ADISC. + * If there is a problem with the remote port, error recovery steps + * will be triggered. + */ +void zfcp_test_link(struct zfcp_port *port) +{ + int retval; + + zfcp_port_get(port); + retval = zfcp_fc_adisc(port); + if (retval == 0 || retval == -EBUSY) + return; + + /* send of ADISC was not possible */ + zfcp_port_put(port); + zfcp_erp_port_forced_reopen(port, 0, 65, NULL); +} diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 01f9b27daa8c..8568b6f3f27c 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -848,7 +848,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_STATUS_READ_INCOMING_ELS: - zfcp_fsf_incoming_els(fsf_req); + zfcp_fc_incoming_els(fsf_req); break; case FSF_STATUS_READ_SENSE_DATA_AVAIL: @@ -1742,10 +1742,6 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = - zfcp_handle_els_rjt(header->fsf_status_qual.word[1], - (struct zfcp_ls_rjt_par *) - &header->fsf_status_qual.word[2]); break; case FSF_SQ_RETRY_IF_POSSIBLE: fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -2534,7 +2530,7 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) &port->status); } else { port->wwnn = plogi->serv_param.wwnn; - zfcp_plogi_evaluate(port, plogi); + zfcp_fc_plogi_evaluate(port, plogi); } } } -- cgit v1.2.3 From 45633fdc9615f9fd2a0ae18e301562298b15abf3 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 10 Jun 2008 18:20:55 +0200 Subject: [SCSI] zfcp: Move CFDC code to new file. zfcp implements a device file to allow Linux guests changing the Access Control Tables stored in the adapter. The code for the device file has nothing to do with the other parts of the driver, so move it to a new file and cleanup the code while doing so. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/Makefile | 2 +- drivers/s390/scsi/zfcp_aux.c | 425 +++--------------------------------------- drivers/s390/scsi/zfcp_cfdc.c | 259 +++++++++++++++++++++++++ drivers/s390/scsi/zfcp_def.h | 43 ----- drivers/s390/scsi/zfcp_ext.h | 8 +- drivers/s390/scsi/zfcp_fsf.c | 246 +++--------------------- drivers/s390/scsi/zfcp_fsf.h | 12 ++ 7 files changed, 331 insertions(+), 664 deletions(-) create mode 100644 drivers/s390/scsi/zfcp_cfdc.c (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index f775f9e6030c..c0fa8ffe5448 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -4,6 +4,6 @@ zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ - zfcp_sysfs_unit.o zfcp_sysfs_driver.o zfcp_fc.o + zfcp_sysfs_unit.o zfcp_sysfs_driver.o zfcp_fc.o zfcp_cfdc.o obj-$(CONFIG_ZFCP) += zfcp.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 9eb8827e19e2..735f7af43d6a 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -33,6 +33,7 @@ * Ralph Wuerthner */ +#include #include "zfcp_ext.h" /* accumulated log level (module parameter) */ @@ -43,33 +44,6 @@ static char *device; /* written against the module interface */ static int __init zfcp_module_init(void); -/* miscellaneous */ -static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); -static void zfcp_sg_list_free(struct zfcp_sg_list *); -static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, - void __user *, size_t); -static int zfcp_sg_list_copy_to_user(void __user *, - struct zfcp_sg_list *, size_t); -static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long); - -#define ZFCP_CFDC_IOC_MAGIC 0xDD -#define ZFCP_CFDC_IOC \ - _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data) - - -static const struct file_operations zfcp_cfdc_fops = { - .unlocked_ioctl = zfcp_cfdc_dev_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = zfcp_cfdc_dev_ioctl -#endif -}; - -static struct miscdevice zfcp_cfdc_misc = { - .minor = ZFCP_CFDC_DEV_MINOR, - .name = ZFCP_CFDC_DEV_NAME, - .fops = &zfcp_cfdc_fops -}; - /*********************** KERNEL/MODULE PARAMETERS ***************************/ /* declare driver module init/cleanup functions */ @@ -294,9 +268,6 @@ zfcp_module_init(void) goto out_misc; } - ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n", - ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor); - /* Initialise proc semaphores */ sema_init(&zfcp_data.config_sema, 1); @@ -329,372 +300,6 @@ zfcp_module_init(void) return retval; } -/* - * function: zfcp_cfdc_dev_ioctl - * - * purpose: Handle control file upload/download transaction via IOCTL - * interface - * - * returns: 0 - Operation completed successfuly - * -ENOTTY - Unknown IOCTL command - * -EINVAL - Invalid sense data record - * -ENXIO - The FCP adapter is not available - * -EOPNOTSUPP - The FCP adapter does not have CFDC support - * -ENOMEM - Insufficient memory - * -EFAULT - User space memory I/O operation fault - * -EPERM - Cannot create or queue FSF request or create SBALs - * -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS) - */ -static long -zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, - unsigned long buffer) -{ - struct zfcp_cfdc_sense_data *sense_data, __user *sense_data_user; - struct zfcp_adapter *adapter = NULL; - struct zfcp_fsf_req *fsf_req = NULL; - struct zfcp_sg_list *sg_list = NULL; - u32 fsf_command, option; - char *bus_id = NULL; - int retval = 0; - - sense_data = kmalloc(sizeof(struct zfcp_cfdc_sense_data), GFP_KERNEL); - if (sense_data == NULL) { - retval = -ENOMEM; - goto out; - } - - sg_list = kzalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL); - if (sg_list == NULL) { - retval = -ENOMEM; - goto out; - } - - if (command != ZFCP_CFDC_IOC) { - ZFCP_LOG_INFO("IOC request code 0x%x invalid\n", command); - retval = -ENOTTY; - goto out; - } - - if ((sense_data_user = (void __user *) buffer) == NULL) { - ZFCP_LOG_INFO("sense data record is required\n"); - retval = -EINVAL; - goto out; - } - - retval = copy_from_user(sense_data, sense_data_user, - sizeof(struct zfcp_cfdc_sense_data)); - if (retval) { - retval = -EFAULT; - goto out; - } - - if (sense_data->signature != ZFCP_CFDC_SIGNATURE) { - ZFCP_LOG_INFO("invalid sense data request signature 0x%08x\n", - ZFCP_CFDC_SIGNATURE); - retval = -EINVAL; - goto out; - } - - switch (sense_data->command) { - - case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: - fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; - option = FSF_CFDC_OPTION_NORMAL_MODE; - break; - - case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: - fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; - option = FSF_CFDC_OPTION_FORCE; - break; - - case ZFCP_CFDC_CMND_FULL_ACCESS: - fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; - option = FSF_CFDC_OPTION_FULL_ACCESS; - break; - - case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: - fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; - option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; - break; - - case ZFCP_CFDC_CMND_UPLOAD: - fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE; - option = 0; - break; - - default: - ZFCP_LOG_INFO("invalid command code 0x%08x\n", - sense_data->command); - retval = -EINVAL; - goto out; - } - - bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL); - if (bus_id == NULL) { - retval = -ENOMEM; - goto out; - } - snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x", - (sense_data->devno >> 24), - (sense_data->devno >> 16) & 0xFF, - (sense_data->devno & 0xFFFF)); - - read_lock_irq(&zfcp_data.config_lock); - adapter = zfcp_get_adapter_by_busid(bus_id); - if (adapter) - zfcp_adapter_get(adapter); - read_unlock_irq(&zfcp_data.config_lock); - - kfree(bus_id); - - if (adapter == NULL) { - ZFCP_LOG_INFO("invalid adapter\n"); - retval = -ENXIO; - goto out; - } - - if (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE) { - retval = zfcp_sg_list_alloc(sg_list, - ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); - if (retval) { - retval = -ENOMEM; - goto out; - } - } - - if ((sense_data->command & ZFCP_CFDC_DOWNLOAD) && - (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE)) { - retval = zfcp_sg_list_copy_from_user( - sg_list, &sense_data_user->control_file, - ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); - if (retval) { - retval = -EFAULT; - goto out; - } - } - - retval = zfcp_fsf_control_file(adapter, &fsf_req, fsf_command, - option, sg_list); - if (retval) - goto out; - - if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) && - (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { - retval = -ENXIO; - goto out; - } - - sense_data->fsf_status = fsf_req->qtcb->header.fsf_status; - memcpy(&sense_data->fsf_status_qual, - &fsf_req->qtcb->header.fsf_status_qual, - sizeof(union fsf_status_qual)); - memcpy(&sense_data->payloads, &fsf_req->qtcb->bottom.support.els, 256); - - retval = copy_to_user(sense_data_user, sense_data, - sizeof(struct zfcp_cfdc_sense_data)); - if (retval) { - retval = -EFAULT; - goto out; - } - - if (sense_data->command & ZFCP_CFDC_UPLOAD) { - retval = zfcp_sg_list_copy_to_user( - &sense_data_user->control_file, sg_list, - ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); - if (retval) { - retval = -EFAULT; - goto out; - } - } - - out: - if (fsf_req != NULL) - zfcp_fsf_req_free(fsf_req); - - if ((adapter != NULL) && (retval != -ENXIO)) - zfcp_adapter_put(adapter); - - if (sg_list != NULL) { - zfcp_sg_list_free(sg_list); - kfree(sg_list); - } - - kfree(sense_data); - - return retval; -} - - -/** - * zfcp_sg_list_alloc - create a scatter-gather list of the specified size - * @sg_list: structure describing a scatter gather list - * @size: size of scatter-gather list - * Return: 0 on success, else -ENOMEM - * - * In sg_list->sg a pointer to the created scatter-gather list is returned, - * or NULL if we run out of memory. sg_list->count specifies the number of - * elements of the scatter-gather list. The maximum size of a single element - * in the scatter-gather list is PAGE_SIZE. - */ -static int -zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) -{ - struct scatterlist *sg; - unsigned int i; - int retval = 0; - void *address; - - BUG_ON(sg_list == NULL); - - sg_list->count = size >> PAGE_SHIFT; - if (size & ~PAGE_MASK) - sg_list->count++; - sg_list->sg = kcalloc(sg_list->count, sizeof(struct scatterlist), - GFP_KERNEL); - if (sg_list->sg == NULL) { - sg_list->count = 0; - retval = -ENOMEM; - goto out; - } - sg_init_table(sg_list->sg, sg_list->count); - - for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) { - address = (void *) get_zeroed_page(GFP_KERNEL); - if (address == NULL) { - sg_list->count = i; - zfcp_sg_list_free(sg_list); - retval = -ENOMEM; - goto out; - } - zfcp_address_to_sg(address, sg, min(size, PAGE_SIZE)); - size -= sg->length; - } - - out: - return retval; -} - - -/** - * zfcp_sg_list_free - free memory of a scatter-gather list - * @sg_list: structure describing a scatter-gather list - * - * Memory for each element in the scatter-gather list is freed. - * Finally sg_list->sg is freed itself and sg_list->count is reset. - */ -static void -zfcp_sg_list_free(struct zfcp_sg_list *sg_list) -{ - struct scatterlist *sg; - unsigned int i; - - BUG_ON(sg_list == NULL); - - for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) - free_page((unsigned long) zfcp_sg_to_address(sg)); - - sg_list->count = 0; - kfree(sg_list->sg); -} - -/** - * zfcp_sg_size - determine size of a scatter-gather list - * @sg: array of (struct scatterlist) - * @sg_count: elements in array - * Return: size of entire scatter-gather list - */ -static size_t zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) -{ - unsigned int i; - struct scatterlist *p; - size_t size; - - size = 0; - for (i = 0, p = sg; i < sg_count; i++, p++) { - BUG_ON(p == NULL); - size += p->length; - } - - return size; -} - - -/** - * zfcp_sg_list_copy_from_user -copy data from user space to scatter-gather list - * @sg_list: structure describing a scatter-gather list - * @user_buffer: pointer to buffer in user space - * @size: number of bytes to be copied - * Return: 0 on success, -EFAULT if copy_from_user fails. - */ -static int -zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, - void __user *user_buffer, - size_t size) -{ - struct scatterlist *sg; - unsigned int length; - void *zfcp_buffer; - int retval = 0; - - BUG_ON(sg_list == NULL); - - if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) - return -EFAULT; - - for (sg = sg_list->sg; size > 0; sg++) { - length = min((unsigned int)size, sg->length); - zfcp_buffer = zfcp_sg_to_address(sg); - if (copy_from_user(zfcp_buffer, user_buffer, length)) { - retval = -EFAULT; - goto out; - } - user_buffer += length; - size -= length; - } - - out: - return retval; -} - - -/** - * zfcp_sg_list_copy_to_user - copy data from scatter-gather list to user space - * @user_buffer: pointer to buffer in user space - * @sg_list: structure describing a scatter-gather list - * @size: number of bytes to be copied - * Return: 0 on success, -EFAULT if copy_to_user fails - */ -static int -zfcp_sg_list_copy_to_user(void __user *user_buffer, - struct zfcp_sg_list *sg_list, - size_t size) -{ - struct scatterlist *sg; - unsigned int length; - void *zfcp_buffer; - int retval = 0; - - BUG_ON(sg_list == NULL); - - if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) - return -EFAULT; - - for (sg = sg_list->sg; size > 0; sg++) { - length = min((unsigned int) size, sg->length); - zfcp_buffer = zfcp_sg_to_address(sg); - if (copy_to_user(user_buffer, zfcp_buffer, length)) { - retval = -EFAULT; - goto out; - } - user_buffer += length; - size -= length; - } - - out: - return retval; -} - - #undef ZFCP_LOG_AREA /****************************************************************/ @@ -1345,4 +950,32 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) return 0; } +void zfcp_sg_free_table(struct scatterlist *sg, int count) +{ + int i; + + for (i = 0; i < count; i++, sg++) + if (sg) + free_page((unsigned long) sg_virt(sg)); + else + break; +} + +int zfcp_sg_setup_table(struct scatterlist *sg, int count) +{ + void *addr; + int i; + + sg_init_table(sg, count); + for (i = 0; i < count; i++, sg++) { + addr = (void *) get_zeroed_page(GFP_KERNEL); + if (!addr) { + zfcp_sg_free_table(sg, i); + return -ENOMEM; + } + sg_set_buf(sg, addr, PAGE_SIZE); + } + return 0; +} + #undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c new file mode 100644 index 000000000000..ec2abceca6dc --- /dev/null +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -0,0 +1,259 @@ +/* + * zfcp device driver + * + * Userspace interface for accessing the + * Access Control Lists / Control File Data Channel + * + * Copyright IBM Corporation 2008 + */ + +#include +#include +#include +#include "zfcp_def.h" +#include "zfcp_ext.h" +#include "zfcp_fsf.h" + +#define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001 +#define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101 +#define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201 +#define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401 +#define ZFCP_CFDC_CMND_UPLOAD 0x00010002 + +#define ZFCP_CFDC_DOWNLOAD 0x00000001 +#define ZFCP_CFDC_UPLOAD 0x00000002 +#define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000 + +#define ZFCP_CFDC_IOC_MAGIC 0xDD +#define ZFCP_CFDC_IOC \ + _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_data) + +/** + * struct zfcp_cfdc_data - data for ioctl cfdc interface + * @signature: request signature + * @devno: FCP adapter device number + * @command: command code + * @fsf_status: returns status of FSF command to userspace + * @fsf_status_qual: returned to userspace + * @payloads: access conflicts list + * @control_file: access control table + */ +struct zfcp_cfdc_data { + u32 signature; + u32 devno; + u32 command; + u32 fsf_status; + u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; + u8 payloads[256]; + u8 control_file[0]; +}; + +static int zfcp_cfdc_copy_from_user(struct scatterlist *sg, + void __user *user_buffer) +{ + unsigned int length; + unsigned int size = ZFCP_CFDC_MAX_SIZE; + + while (size) { + length = min((unsigned int)size, sg->length); + if (copy_from_user(sg_virt(sg++), user_buffer, length)) + return -EFAULT; + user_buffer += length; + size -= length; + } + return 0; +} + +static int zfcp_cfdc_copy_to_user(void __user *user_buffer, + struct scatterlist *sg) +{ + unsigned int length; + unsigned int size = ZFCP_CFDC_MAX_SIZE; + + while (size) { + length = min((unsigned int) size, sg->length); + if (copy_to_user(user_buffer, sg_virt(sg++), length)) + return -EFAULT; + user_buffer += length; + size -= length; + } + return 0; +} + +static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) +{ + struct zfcp_adapter *adapter = NULL, *cur_adapter; + struct ccw_dev_id dev_id; + + read_lock_irq(&zfcp_data.config_lock); + list_for_each_entry(cur_adapter, &zfcp_data.adapter_list_head, list) { + ccw_device_get_id(cur_adapter->ccw_device, &dev_id); + if (dev_id.devno == devno) { + adapter = cur_adapter; + zfcp_adapter_get(adapter); + break; + } + } + read_unlock_irq(&zfcp_data.config_lock); + return adapter; +} + +static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command) +{ + switch (command) { + case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: + fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; + fsf_cfdc->option = FSF_CFDC_OPTION_NORMAL_MODE; + break; + case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: + fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; + fsf_cfdc->option = FSF_CFDC_OPTION_FORCE; + break; + case ZFCP_CFDC_CMND_FULL_ACCESS: + fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; + fsf_cfdc->option = FSF_CFDC_OPTION_FULL_ACCESS; + break; + case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: + fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; + fsf_cfdc->option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; + break; + case ZFCP_CFDC_CMND_UPLOAD: + fsf_cfdc->command = FSF_QTCB_UPLOAD_CONTROL_FILE; + fsf_cfdc->option = 0; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int zfcp_cfdc_sg_setup(int command, struct scatterlist *sg, + u8 __user *control_file) +{ + int retval; + retval = zfcp_sg_setup_table(sg, ZFCP_CFDC_PAGES); + if (retval) + return retval; + + sg[ZFCP_CFDC_PAGES - 1].length = ZFCP_CFDC_MAX_SIZE % PAGE_SIZE; + + if (command & ZFCP_CFDC_WITH_CONTROL_FILE && + command & ZFCP_CFDC_DOWNLOAD) { + retval = zfcp_cfdc_copy_from_user(sg, control_file); + if (retval) { + zfcp_sg_free_table(sg, ZFCP_CFDC_PAGES); + return -EFAULT; + } + } + + return 0; +} + +static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data *data, + struct zfcp_fsf_req *req) +{ + data->fsf_status = req->qtcb->header.fsf_status; + memcpy(&data->fsf_status_qual, &req->qtcb->header.fsf_status_qual, + sizeof(union fsf_status_qual)); + memcpy(&data->payloads, &req->qtcb->bottom.support.els, + sizeof(req->qtcb->bottom.support.els)); +} + +static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, + unsigned long buffer) +{ + struct zfcp_cfdc_data *data; + struct zfcp_cfdc_data __user *data_user; + struct zfcp_adapter *adapter; + struct zfcp_fsf_req *req; + struct zfcp_fsf_cfdc *fsf_cfdc; + int retval; + + if (command != ZFCP_CFDC_IOC) + return -ENOTTY; + + data_user = (void __user *) buffer; + if (!data_user) + return -EINVAL; + + fsf_cfdc = kmalloc(sizeof(struct zfcp_fsf_cfdc), GFP_KERNEL); + if (!fsf_cfdc) + return -ENOMEM; + + data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL); + if (!data) { + retval = -ENOMEM; + goto no_mem_sense; + } + + retval = copy_from_user(data, data_user, sizeof(*data)); + if (retval) { + retval = -EFAULT; + goto free_buffer; + } + + if (data->signature != 0xCFDCACDF) { + retval = -EINVAL; + goto free_buffer; + } + + retval = zfcp_cfdc_set_fsf(fsf_cfdc, data->command); + + adapter = zfcp_cfdc_get_adapter(data->devno); + if (!adapter) { + retval = -ENXIO; + goto free_buffer; + } + + retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, + data_user->control_file); + if (retval) + goto adapter_put; + req = zfcp_fsf_control_file(adapter, fsf_cfdc); + if (IS_ERR(req)) { + retval = PTR_ERR(req); + goto free_sg; + } + + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { + retval = -ENXIO; + goto free_fsf; + } + + zfcp_cfdc_req_to_sense(data, req); + retval = copy_to_user(data_user, data, sizeof(*data_user)); + if (retval) { + retval = -EFAULT; + goto free_fsf; + } + + if (data->command & ZFCP_CFDC_UPLOAD) + retval = zfcp_cfdc_copy_to_user(&data_user->control_file, + fsf_cfdc->sg); + + free_fsf: + zfcp_fsf_req_free(req); + free_sg: + zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); + adapter_put: + zfcp_adapter_put(adapter); + free_buffer: + kfree(data); + no_mem_sense: + kfree(fsf_cfdc); + return retval; +} + +static const struct file_operations zfcp_cfdc_fops = { + .unlocked_ioctl = zfcp_cfdc_dev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = zfcp_cfdc_dev_ioctl +#endif +}; + +struct miscdevice zfcp_cfdc_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "zfcp_cfdc", + .fops = &zfcp_cfdc_fops, +}; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index d23c3b9b283e..72f225817ebd 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -534,38 +533,6 @@ do { \ #define ZFCP_ERP_DISMISSED 0x4 #define ZFCP_ERP_NOMEM 0x5 - -/******************** CFDC SPECIFIC STUFF *****************************/ - -/* Firewall data channel sense data record */ -struct zfcp_cfdc_sense_data { - u32 signature; /* Request signature */ - u32 devno; /* FCP adapter device number */ - u32 command; /* Command code */ - u32 fsf_status; /* FSF request status and status qualifier */ - u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; - u8 payloads[256]; /* Access conflicts list */ - u8 control_file[0]; /* Access control table */ -}; - -#define ZFCP_CFDC_SIGNATURE 0xCFDCACDF - -#define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001 -#define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101 -#define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201 -#define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401 -#define ZFCP_CFDC_CMND_UPLOAD 0x00010002 - -#define ZFCP_CFDC_DOWNLOAD 0x00000001 -#define ZFCP_CFDC_UPLOAD 0x00000002 -#define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000 - -#define ZFCP_CFDC_DEV_NAME "zfcp_cfdc" -#define ZFCP_CFDC_DEV_MAJOR MISC_MAJOR -#define ZFCP_CFDC_DEV_MINOR MISC_DYNAMIC_MINOR - -#define ZFCP_CFDC_MAX_CONTROL_FILE_SIZE 127 * 1024 - /************************* STRUCTURE DEFINITIONS *****************************/ struct zfcp_fsf_req; @@ -897,16 +864,6 @@ struct zfcp_data { struct kmem_cache *gid_pn_cache; }; -/** - * struct zfcp_sg_list - struct describing a scatter-gather list - * @sg: pointer to array of (struct scatterlist) - * @count: number of elements in scatter-gather list - */ -struct zfcp_sg_list { - struct scatterlist *sg; - unsigned int count; -}; - /* number of elements for various memory pools */ #define ZFCP_POOL_FSF_REQ_ERP_NR 1 #define ZFCP_POOL_FSF_REQ_SCSI_NR 1 diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 91d58843205c..867972898cb1 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -86,8 +86,8 @@ extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, struct fsf_qtcb_bottom_port *); -extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, - u32, u32, struct zfcp_sg_list *); +extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, + struct zfcp_fsf_cfdc *fsf_cfdc); extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); @@ -167,6 +167,8 @@ extern void zfcp_erp_port_access_changed(struct zfcp_port *, u8, void *); extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *); /******************************** AUX ****************************************/ +extern void zfcp_sg_free_table(struct scatterlist *sg, int count); +extern int zfcp_sg_setup_table(struct scatterlist *sg, int count); extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter); extern void zfcp_rec_dbf_event_thread_lock(u8 id, struct zfcp_adapter *adapter); extern void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *); @@ -200,4 +202,6 @@ extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, struct scsi_cmnd *); extern int zfcp_reqlist_isempty(struct zfcp_adapter *); +extern struct miscdevice zfcp_cfdc_misc; + #endif /* ZFCP_EXT_H */ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 8568b6f3f27c..de42a01fc4b1 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -36,7 +36,7 @@ static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *); static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *); static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); +static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); static inline int zfcp_fsf_req_sbal_check( unsigned long *, struct zfcp_qdio_queue *, int); static inline int zfcp_use_one_sbal( @@ -4183,53 +4183,35 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) * -ENOMEM - Insufficient memory * -EPERM - Cannot create FSF request or place it in QDIO queue */ -int -zfcp_fsf_control_file(struct zfcp_adapter *adapter, - struct zfcp_fsf_req **fsf_req_ptr, - u32 fsf_command, - u32 option, - struct zfcp_sg_list *sg_list) +struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, + struct zfcp_fsf_cfdc *fsf_cfdc) { struct zfcp_fsf_req *fsf_req; struct fsf_qtcb_bottom_support *bottom; volatile struct qdio_buffer_element *sbale; unsigned long lock_flags; - int req_flags = 0; int direction; - int retval = 0; - - if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) { - ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n", - zfcp_get_busid_by_adapter(adapter)); - retval = -EOPNOTSUPP; - goto out; - } + int retval; + int bytes; - switch (fsf_command) { + if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) + return ERR_PTR(-EOPNOTSUPP); + switch (fsf_cfdc->command) { case FSF_QTCB_DOWNLOAD_CONTROL_FILE: direction = SBAL_FLAGS0_TYPE_WRITE; - if ((option != FSF_CFDC_OPTION_FULL_ACCESS) && - (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS)) - req_flags = ZFCP_WAIT_FOR_SBAL; break; - case FSF_QTCB_UPLOAD_CONTROL_FILE: direction = SBAL_FLAGS0_TYPE_READ; break; - default: - ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command); - retval = -EINVAL; - goto out; + return ERR_PTR(-EINVAL); } - retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags, + retval = zfcp_fsf_req_create(adapter, fsf_cfdc->command, + ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags, &fsf_req); if (retval < 0) { - ZFCP_LOG_INFO("error: Could not create FSF request for the " - "adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); retval = -EPERM; goto unlock_queue_lock; } @@ -4239,220 +4221,40 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter, bottom = &fsf_req->qtcb->bottom.support; bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; - bottom->option = option; - - if (sg_list->count > 0) { - int bytes; - - bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, - sg_list->sg, sg_list->count, - ZFCP_MAX_SBALS_PER_REQ); - if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) { - ZFCP_LOG_INFO( - "error: Could not create sufficient number of " - "SBALS for an FSF request to the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - retval = -ENOMEM; - goto free_fsf_req; - } - } else - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + bottom->option = fsf_cfdc->option; + + bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, + fsf_cfdc->sg, ZFCP_CFDC_PAGES, + ZFCP_MAX_SBALS_PER_REQ); + if (bytes != ZFCP_CFDC_MAX_SIZE) { + retval = -ENOMEM; + goto free_fsf_req; + } zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(fsf_req); if (retval < 0) { - ZFCP_LOG_INFO("initiation of cfdc up/download failed" - "(adapter %s)\n", - zfcp_get_busid_by_adapter(adapter)); retval = -EPERM; goto free_fsf_req; } write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the " - "adapter %s\n", - fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ? - "download" : "upload", - zfcp_get_busid_by_adapter(adapter)); - wait_event(fsf_req->completion_wq, fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - *fsf_req_ptr = fsf_req; - goto out; + return fsf_req; free_fsf_req: zfcp_fsf_req_free(fsf_req); unlock_queue_lock: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - out: - return retval; + return ERR_PTR(retval); } - -/* - * function: zfcp_fsf_control_file_handler - * - * purpose: Handler of the control file upload/download FSF requests - * - * returns: 0 - FSF request successfuly processed - * -EAGAIN - Operation has to be repeated because of a temporary problem - * -EACCES - There is no permission to execute an operation - * -EPERM - The control file is not in a right format - * -EIO - There is a problem with the FCP adapter - * -EINVAL - Invalid operation - * -EFAULT - User space memory I/O operation fault - */ -static int -zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) { - struct zfcp_adapter *adapter = fsf_req->adapter; - struct fsf_qtcb_header *header = &fsf_req->qtcb->header; - struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support; - int retval = 0; - - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - retval = -EINVAL; - goto skip_fsfstatus; - } - - switch (header->fsf_status) { - - case FSF_GOOD: - ZFCP_LOG_NORMAL( - "The FSF request has been successfully completed " - "on the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - break; - - case FSF_OPERATION_PARTIALLY_SUCCESSFUL: - if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) { - switch (header->fsf_status_qual.word[0]) { - - case FSF_SQ_CFDC_HARDENED_ON_SE: - ZFCP_LOG_NORMAL( - "CFDC on the adapter %s has being " - "hardened on primary and secondary SE\n", - zfcp_get_busid_by_adapter(adapter)); - break; - - case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE: - ZFCP_LOG_NORMAL( - "CFDC of the adapter %s could not " - "be saved on the SE\n", - zfcp_get_busid_by_adapter(adapter)); - break; - - case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2: - ZFCP_LOG_NORMAL( - "CFDC of the adapter %s could not " - "be copied to the secondary SE\n", - zfcp_get_busid_by_adapter(adapter)); - break; - - default: - ZFCP_LOG_NORMAL( - "CFDC could not be hardened " - "on the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - } - } - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EAGAIN; - break; - - case FSF_AUTHORIZATION_FAILURE: - ZFCP_LOG_NORMAL( - "Adapter %s does not accept privileged commands\n", - zfcp_get_busid_by_adapter(adapter)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EACCES; - break; - - case FSF_CFDC_ERROR_DETECTED: - ZFCP_LOG_NORMAL( - "Error at position %d in the CFDC, " - "CFDC is discarded by the adapter %s\n", - header->fsf_status_qual.word[0], - zfcp_get_busid_by_adapter(adapter)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EPERM; - break; - - case FSF_CONTROL_FILE_UPDATE_ERROR: - ZFCP_LOG_NORMAL( - "Adapter %s cannot harden the control file, " - "file is discarded\n", - zfcp_get_busid_by_adapter(adapter)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EIO; - break; - - case FSF_CONTROL_FILE_TOO_LARGE: - ZFCP_LOG_NORMAL( - "Control file is too large, file is discarded " - "by the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EIO; - break; - - case FSF_ACCESS_CONFLICT_DETECTED: - if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) - ZFCP_LOG_NORMAL( - "CFDC has been discarded by the adapter %s, " - "because activation would impact " - "%d active connection(s)\n", - zfcp_get_busid_by_adapter(adapter), - header->fsf_status_qual.word[0]); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EIO; - break; - - case FSF_CONFLICTS_OVERRULED: - if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) - ZFCP_LOG_NORMAL( - "CFDC has been activated on the adapter %s, " - "but activation has impacted " - "%d active connection(s)\n", - zfcp_get_busid_by_adapter(adapter), - header->fsf_status_qual.word[0]); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EIO; - break; - - case FSF_UNKNOWN_OP_SUBTYPE: - ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, " - "op_subtype=0x%x)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->operation_subtype); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EINVAL; - break; - - case FSF_INVALID_COMMAND_OPTION: - ZFCP_LOG_NORMAL( - "Invalid option 0x%x has been specified " - "in QTCB bottom sent to the adapter %s\n", - bottom->option, - zfcp_get_busid_by_adapter(adapter)); + if (fsf_req->qtcb->header.fsf_status != FSF_GOOD) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EINVAL; - break; - - default: - ZFCP_LOG_NORMAL( - "bug: An unknown/unexpected FSF status 0x%08x " - "was presented on the adapter %s\n", - header->fsf_status, - zfcp_get_busid_by_adapter(adapter)); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EINVAL; - break; - } - -skip_fsfstatus: - return retval; } static inline int diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 8b1a7d9c840f..598eba9baa31 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -22,6 +22,8 @@ #ifndef FSF_H #define FSF_H +#include + #define FSF_QTCB_CURRENT_VERSION 0x00000001 /* FSF commands */ @@ -258,6 +260,16 @@ #define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000 #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000 +/* FSF interface for CFDC */ +#define ZFCP_CFDC_MAX_SIZE 127 * 1024 +#define ZFCP_CFDC_PAGES PFN_UP(ZFCP_CFDC_MAX_SIZE) + +struct zfcp_fsf_cfdc { + struct scatterlist sg[ZFCP_CFDC_PAGES]; + u32 command; + u32 option; +}; + struct fsf_queue_designator { u8 cssid; u8 chpid; -- cgit v1.2.3 From fa04c2816883a49ec518514f6c19767d54be20b5 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 10 Jun 2008 18:20:56 +0200 Subject: [SCSI] zfcp: Cleanup code in zfcp_ccw Overall cleanup in file zfcp_ccw.c. Fix coding style issues, remove useless macros and messages and convert remaining messages to standard macros. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ccw.c | 150 +++++++++++++++---------------------------- 1 file changed, 50 insertions(+), 100 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 66d3b88844b0..da472e865e58 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -1,64 +1,13 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Registration and callback for the s390 common I/O layer. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #include "zfcp_ext.h" -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG - -static int zfcp_ccw_probe(struct ccw_device *); -static void zfcp_ccw_remove(struct ccw_device *); -static int zfcp_ccw_set_online(struct ccw_device *); -static int zfcp_ccw_set_offline(struct ccw_device *); -static int zfcp_ccw_notify(struct ccw_device *, int); -static void zfcp_ccw_shutdown(struct ccw_device *); - -static struct ccw_device_id zfcp_ccw_device_id[] = { - {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, - ZFCP_CONTROL_UNIT_MODEL, - ZFCP_DEVICE_TYPE, - ZFCP_DEVICE_MODEL)}, - {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, - ZFCP_CONTROL_UNIT_MODEL, - ZFCP_DEVICE_TYPE, - ZFCP_DEVICE_MODEL_PRIV)}, - {}, -}; - -static struct ccw_driver zfcp_ccw_driver = { - .owner = THIS_MODULE, - .name = ZFCP_NAME, - .ids = zfcp_ccw_device_id, - .probe = zfcp_ccw_probe, - .remove = zfcp_ccw_remove, - .set_online = zfcp_ccw_set_online, - .set_offline = zfcp_ccw_set_offline, - .notify = zfcp_ccw_notify, - .shutdown = zfcp_ccw_shutdown, - .driver = { - .groups = zfcp_driver_attr_groups, - }, -}; - -MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); - /** * zfcp_ccw_probe - probe function of zfcp driver * @ccw_device: pointer to belonging ccw device @@ -69,19 +18,18 @@ MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); * In addition the nameserver port will be added to the ports of the adapter * and its sysfs representation will be created too. */ -static int -zfcp_ccw_probe(struct ccw_device *ccw_device) +static int zfcp_ccw_probe(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; int retval = 0; down(&zfcp_data.config_sema); adapter = zfcp_adapter_enqueue(ccw_device); - if (!adapter) + if (!adapter) { + dev_err(&ccw_device->dev, + "Setup of data structures failed.\n"); retval = -EINVAL; - else - ZFCP_LOG_DEBUG("Probed adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + } up(&zfcp_data.config_sema); return retval; } @@ -95,8 +43,7 @@ zfcp_ccw_probe(struct ccw_device *ccw_device) * ports that belong to this adapter. And in addition all resources of this * adapter will be freed too. */ -static void -zfcp_ccw_remove(struct ccw_device *ccw_device) +static void zfcp_ccw_remove(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; struct zfcp_port *port, *p; @@ -106,8 +53,6 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) down(&zfcp_data.config_sema); adapter = dev_get_drvdata(&ccw_device->dev); - ZFCP_LOG_DEBUG("Removing adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); write_lock_irq(&zfcp_data.config_lock); list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { @@ -145,8 +90,7 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) * registered with the SCSI stack, that the QDIO queues will be set up * and that the adapter will be opened (asynchronously). */ -static int -zfcp_ccw_set_online(struct ccw_device *ccw_device) +static int zfcp_ccw_set_online(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; int retval; @@ -155,12 +99,8 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) adapter = dev_get_drvdata(&ccw_device->dev); retval = zfcp_erp_thread_setup(adapter); - if (retval) { - ZFCP_LOG_INFO("error: start of error recovery thread for " - "adapter %s failed\n", - zfcp_get_busid_by_adapter(adapter)); + if (retval) goto out; - } retval = zfcp_adapter_scsi_register(adapter); if (retval) @@ -191,8 +131,7 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) * This function gets called by the common i/o layer and sets an adapter * into state offline. */ -static int -zfcp_ccw_set_offline(struct ccw_device *ccw_device) +static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; @@ -206,15 +145,14 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device) } /** - * zfcp_ccw_notify + * zfcp_ccw_notify - ccw notify function * @ccw_device: pointer to belonging ccw device * @event: indicates if adapter was detached or attached * * This function gets called by the common i/o layer if an adapter has gone * or reappeared. */ -static int -zfcp_ccw_notify(struct ccw_device *ccw_device, int event) +static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) { struct zfcp_adapter *adapter; @@ -222,18 +160,15 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event) adapter = dev_get_drvdata(&ccw_device->dev); switch (event) { case CIO_GONE: - ZFCP_LOG_NORMAL("adapter %s: device gone\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&adapter->ccw_device->dev, "device gone\n"); zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL); break; case CIO_NO_PATH: - ZFCP_LOG_NORMAL("adapter %s: no path\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&adapter->ccw_device->dev, "no path\n"); zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL); break; case CIO_OPER: - ZFCP_LOG_NORMAL("adapter %s: operational again\n", - zfcp_get_busid_by_adapter(adapter)); + dev_info(&adapter->ccw_device->dev, "operational again\n"); zfcp_erp_modify_adapter_status(adapter, 11, NULL, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); @@ -247,24 +182,10 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event) } /** - * zfcp_ccw_register - ccw register function - * - * Registers the driver at the common i/o layer. This function will be called - * at module load time/system start. + * zfcp_ccw_shutdown - handle shutdown from cio + * @cdev: device for adapter to shutdown. */ -int __init -zfcp_ccw_register(void) -{ - return ccw_driver_register(&zfcp_ccw_driver); -} - -/** - * zfcp_ccw_shutdown - gets called on reboot/shutdown - * - * Makes sure that QDIO queues are down when the system gets stopped. - */ -static void -zfcp_ccw_shutdown(struct ccw_device *cdev) +static void zfcp_ccw_shutdown(struct ccw_device *cdev) { struct zfcp_adapter *adapter; @@ -275,4 +196,33 @@ zfcp_ccw_shutdown(struct ccw_device *cdev) up(&zfcp_data.config_sema); } -#undef ZFCP_LOG_AREA +static struct ccw_device_id zfcp_ccw_device_id[] = { + { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, + { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x4) }, /* priv. */ + {}, +}; + +MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); + +static struct ccw_driver zfcp_ccw_driver = { + .owner = THIS_MODULE, + .name = "zfcp", + .ids = zfcp_ccw_device_id, + .probe = zfcp_ccw_probe, + .remove = zfcp_ccw_remove, + .set_online = zfcp_ccw_set_online, + .set_offline = zfcp_ccw_set_offline, + .notify = zfcp_ccw_notify, + .shutdown = zfcp_ccw_shutdown, +}; + +/** + * zfcp_ccw_register - ccw register function + * + * Registers the driver at the common i/o layer. This function will be called + * at module load time/system start. + */ +int __init zfcp_ccw_register(void) +{ + return ccw_driver_register(&zfcp_ccw_driver); +} -- cgit v1.2.3 From 00bab91066a49468bfa4f6d5c8ad5e9ec53b7ea3 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 10 Jun 2008 18:20:57 +0200 Subject: [SCSI] zfcp: Cleanup qdio code Cleanup the interface code from zfcp to qdio. Also move code that belongs to the qdio interface from the erp to the qdio file. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 45 +-- drivers/s390/scsi/zfcp_dbf.c | 3 +- drivers/s390/scsi/zfcp_def.h | 26 +- drivers/s390/scsi/zfcp_erp.c | 114 +----- drivers/s390/scsi/zfcp_ext.h | 18 +- drivers/s390/scsi/zfcp_fsf.c | 178 ++++----- drivers/s390/scsi/zfcp_qdio.c | 815 ++++++++++++++++-------------------------- 7 files changed, 412 insertions(+), 787 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 735f7af43d6a..7084a6ae1096 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -606,7 +606,6 @@ static void _zfcp_status_read_scheduler(struct work_struct *work) struct zfcp_adapter * zfcp_adapter_enqueue(struct ccw_device *ccw_device) { - int retval = 0; struct zfcp_adapter *adapter; /* @@ -627,19 +626,11 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) /* save ccw_device pointer */ adapter->ccw_device = ccw_device; - retval = zfcp_qdio_allocate_queues(adapter); - if (retval) - goto queues_alloc_failed; - - retval = zfcp_qdio_allocate(adapter); - if (retval) + if (zfcp_qdio_allocate(adapter)) goto qdio_allocate_failed; - retval = zfcp_allocate_low_mem_buffers(adapter); - if (retval) { - ZFCP_LOG_INFO("error: pool allocation failed\n"); + if (zfcp_allocate_low_mem_buffers(adapter)) goto failed_low_mem_buffers; - } /* initialise reference count stuff */ atomic_set(&adapter->refcount, 0); @@ -653,11 +644,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) /* initialize list of fsf requests */ spin_lock_init(&adapter->req_list_lock); - retval = zfcp_reqlist_alloc(adapter); - if (retval) { - ZFCP_LOG_INFO("request list initialization failed\n"); + if (zfcp_reqlist_alloc(adapter)) goto failed_low_mem_buffers; - } /* initialize debug locks */ @@ -666,8 +654,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) spin_lock_init(&adapter->scsi_dbf_lock); spin_lock_init(&adapter->rec_dbf_lock); - retval = zfcp_adapter_debug_register(adapter); - if (retval) + if (zfcp_adapter_debug_register(adapter)) goto debug_register_failed; /* initialize error recovery stuff */ @@ -685,7 +672,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) init_waitqueue_head(&adapter->erp_done_wqh); /* initialize lock of associated request queue */ - rwlock_init(&adapter->request_queue.queue_lock); + rwlock_init(&adapter->req_q.lock); INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); /* mark adapter unusable as long as sysfs registration is not complete */ @@ -723,12 +710,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) zfcp_reqlist_free(adapter); failed_low_mem_buffers: zfcp_free_low_mem_buffers(adapter); - if (qdio_free(ccw_device) != 0) - ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", - zfcp_get_busid_by_adapter(adapter)); qdio_allocate_failed: - zfcp_qdio_free_queues(adapter); - queues_alloc_failed: + zfcp_qdio_free(adapter); kfree(adapter); adapter = NULL; out: @@ -757,10 +740,6 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) retval = zfcp_reqlist_isempty(adapter); spin_unlock_irqrestore(&adapter->req_list_lock, flags); if (!retval) { - ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " - "%i requests outstanding\n", - zfcp_get_busid_by_adapter(adapter), adapter, - atomic_read(&adapter->reqs_active)); retval = -EBUSY; goto out; } @@ -775,19 +754,9 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) /* decrease number of adapters in list */ zfcp_data.adapters--; - ZFCP_LOG_TRACE("adapter %s (%p) removed from list, " - "%i adapters still in list\n", - zfcp_get_busid_by_adapter(adapter), - adapter, zfcp_data.adapters); - - retval = qdio_free(adapter->ccw_device); - if (retval) - ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", - zfcp_get_busid_by_adapter(adapter)); + zfcp_qdio_free(adapter); zfcp_free_low_mem_buffers(adapter); - /* free memory of adapter data structure and queues */ - zfcp_qdio_free_queues(adapter); zfcp_reqlist_free(adapter); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 01e817abe0a5..c47c23a01c7f 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -603,13 +603,14 @@ static const char *zfcp_rec_dbf_ids[] = { [137] = "hbaapi port open", [138] = "hbaapi unit open", [139] = "hbaapi unit shutdown", - [140] = "qdio error", + [140] = "qdio error outbound", [141] = "scsi host reset", [142] = "dismissing fsf request for recovery action", [143] = "recovery action timed out", [144] = "recovery action gone", [145] = "recovery action being processed", [146] = "recovery action ready for next step", + [147] = "qdio error inbound", }; static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 72f225817ebd..5fcb555e1484 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -112,21 +112,10 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) /* max. number of (data buffer) SBALEs in largest SBAL chain multiplied with number of sectors per 4k block */ -/* FIXME(tune): free space should be one max. SBAL chain plus what? */ -#define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ - - (ZFCP_MAX_SBALS_PER_REQ + 4)) - #define ZFCP_SBAL_TIMEOUT (5*HZ) #define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */ -/* queue polling (values in microseconds) */ -#define ZFCP_MAX_INPUT_THRESHOLD 5000 /* FIXME: tune */ -#define ZFCP_MAX_OUTPUT_THRESHOLD 1000 /* FIXME: tune */ -#define ZFCP_MIN_INPUT_THRESHOLD 1 /* ignored by QDIO layer */ -#define ZFCP_MIN_OUTPUT_THRESHOLD 1 /* ignored by QDIO layer */ - -#define QDIO_SCSI_QFMT 1 /* 1 for FSF */ #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) /********************* FSF SPECIFIC DEFINES *********************************/ @@ -649,13 +638,13 @@ struct zfcp_send_els { }; struct zfcp_qdio_queue { - struct qdio_buffer *buffer[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */ - u8 free_index; /* index of next free bfr + struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */ + u8 first; /* index of next free bfr in queue (free_count>0) */ - atomic_t free_count; /* number of free buffers + atomic_t count; /* number of free buffers in queue */ - rwlock_t queue_lock; /* lock for operations on queue */ - int distance_from_int; /* SBALs used since PCI indication + rwlock_t lock; /* lock for operations on queue */ + int pci_batch; /* SBALs since PCI indication was last set */ }; @@ -711,15 +700,14 @@ struct zfcp_adapter { struct list_head port_remove_lh; /* head of ports to be removed */ u32 ports; /* number of remote ports */ - atomic_t reqs_active; /* # active FSF reqs */ unsigned long req_no; /* unique FSF req number */ struct list_head *req_list; /* list of pending reqs */ spinlock_t req_list_lock; /* request list lock */ - struct zfcp_qdio_queue request_queue; /* request queue */ + struct zfcp_qdio_queue req_q; /* request queue */ u32 fsf_req_seq_no; /* FSF cmnd seq number */ wait_queue_head_t request_wq; /* can be used to wait for more avaliable SBALs */ - struct zfcp_qdio_queue response_queue; /* response queue */ + struct zfcp_qdio_queue resp_q; /* response queue */ rwlock_t abort_lock; /* Protects against SCSI stack abort/command completion races */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index ee19be13e708..4a6d08363d4b 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -113,41 +113,6 @@ static void zfcp_erp_action_to_running(struct zfcp_erp_action *); static void zfcp_erp_memwait_handler(unsigned long); -/** - * zfcp_close_qdio - close qdio queues for an adapter - */ -static void zfcp_close_qdio(struct zfcp_adapter *adapter) -{ - struct zfcp_qdio_queue *req_queue; - int first, count; - - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) - return; - - /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ - req_queue = &adapter->request_queue; - write_lock_irq(&req_queue->queue_lock); - atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); - write_unlock_irq(&req_queue->queue_lock); - - while (qdio_shutdown(adapter->ccw_device, - QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) - ssleep(1); - - /* cleanup used outbound sbals */ - count = atomic_read(&req_queue->free_count); - if (count < QDIO_MAX_BUFFERS_PER_Q) { - first = (req_queue->free_index+count) % QDIO_MAX_BUFFERS_PER_Q; - count = QDIO_MAX_BUFFERS_PER_Q - count; - zfcp_qdio_zero_sbals(req_queue->buffer, first, count); - } - req_queue->free_index = 0; - atomic_set(&req_queue->free_count, 0); - req_queue->distance_from_int = 0; - adapter->response_queue.free_index = 0; - atomic_set(&adapter->response_queue.free_count, 0); -} - /** * zfcp_close_fsf - stop FSF operations for an adapter * @@ -158,7 +123,7 @@ static void zfcp_close_qdio(struct zfcp_adapter *adapter) static void zfcp_close_fsf(struct zfcp_adapter *adapter) { /* close queues to ensure that buffers are not accessed by adapter */ - zfcp_close_qdio(adapter); + zfcp_qdio_close(adapter); zfcp_fsf_req_dismiss_all(adapter); /* reset FSF request sequence number */ adapter->fsf_req_seq_no = 0; @@ -1735,88 +1700,17 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) { - int retval; - int i; - volatile struct qdio_buffer_element *sbale; struct zfcp_adapter *adapter = erp_action->adapter; - if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { - ZFCP_LOG_NORMAL("bug: second attempt to set up QDIO on " - "adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - goto failed_sanity; - } - - if (qdio_establish(&adapter->qdio_init_data) != 0) { - ZFCP_LOG_INFO("error: establishment of QDIO queues failed " - "on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - goto failed_qdio_establish; - } - - if (qdio_activate(adapter->ccw_device, 0) != 0) { - ZFCP_LOG_INFO("error: activation of QDIO queues failed " - "on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - goto failed_qdio_activate; - } - - /* - * put buffers into response queue, - */ - for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { - sbale = &(adapter->response_queue.buffer[i]->element[0]); - sbale->length = 0; - sbale->flags = SBAL_FLAGS_LAST_ENTRY; - sbale->addr = NULL; - } - - ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, " - "queue_no=%i, index_in_queue=%i, count=%i)\n", - zfcp_get_busid_by_adapter(adapter), - QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q); - - retval = do_QDIO(adapter->ccw_device, - QDIO_FLAG_SYNC_INPUT, - 0, 0, QDIO_MAX_BUFFERS_PER_Q, NULL); - - if (retval) { - ZFCP_LOG_NORMAL("bug: setup of QDIO failed (retval=%d)\n", - retval); - goto failed_do_qdio; - } else { - adapter->response_queue.free_index = 0; - atomic_set(&adapter->response_queue.free_count, 0); - ZFCP_LOG_DEBUG("%i buffers successfully enqueued to " - "response queue\n", QDIO_MAX_BUFFERS_PER_Q); - } - /* set index of first avalable SBALS / number of available SBALS */ - adapter->request_queue.free_index = 0; - atomic_set(&adapter->request_queue.free_count, QDIO_MAX_BUFFERS_PER_Q); - adapter->request_queue.distance_from_int = 0; + if (zfcp_qdio_open(adapter)) + return ZFCP_ERP_FAILED; /* initialize waitqueue used to wait for free SBALs in requests queue */ init_waitqueue_head(&adapter->request_wq); /* ok, we did it - skip all cleanups for different failures */ atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); - retval = ZFCP_ERP_SUCCEEDED; - goto out; - - failed_do_qdio: - /* NOP */ - - failed_qdio_activate: - while (qdio_shutdown(adapter->ccw_device, - QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) - ssleep(1); - - failed_qdio_establish: - failed_sanity: - retval = ZFCP_ERP_FAILED; - - out: - return retval; + return ZFCP_ERP_SUCCEEDED; } diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 867972898cb1..6ffe2068ba8a 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -57,21 +57,17 @@ extern int zfcp_ccw_register(void); extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int); extern int zfcp_qdio_allocate(struct zfcp_adapter *); -extern int zfcp_qdio_allocate_queues(struct zfcp_adapter *); -extern void zfcp_qdio_free_queues(struct zfcp_adapter *); -extern int zfcp_qdio_determine_pci(struct zfcp_qdio_queue *, - struct zfcp_fsf_req *); +extern void zfcp_qdio_free(struct zfcp_adapter *); +extern int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req); extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req - (struct zfcp_fsf_req *, int, int); + (struct zfcp_fsf_req *); extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr (struct zfcp_fsf_req *); extern int zfcp_qdio_sbals_from_sg - (struct zfcp_fsf_req *, unsigned long, struct scatterlist *, int, int); -extern int zfcp_qdio_sbals_from_scsicmnd - (struct zfcp_fsf_req *, unsigned long, struct scsi_cmnd *); - - + (struct zfcp_fsf_req *, unsigned long, struct scatterlist *, int); +extern int zfcp_qdio_open(struct zfcp_adapter *adapter); +extern void zfcp_qdio_close(struct zfcp_adapter *adapter); /******************************** FSF ****************************************/ extern int zfcp_fsf_open_port(struct zfcp_erp_action *); extern int zfcp_fsf_close_port(struct zfcp_erp_action *); @@ -95,7 +91,7 @@ extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, unsigned long *, struct zfcp_fsf_req **) - __acquires(adapter->request_queue.queue_lock); + __acquires(adapter->req_q.lock); extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, struct zfcp_erp_action *); extern int zfcp_fsf_send_els(struct zfcp_send_els *); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index de42a01fc4b1..cc48a6462e6c 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -171,7 +171,6 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) BUG_ON(atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)); spin_lock_irqsave(&adapter->req_list_lock, flags); - atomic_set(&adapter->reqs_active, 0); for (i = 0; i < REQUEST_LIST_SIZE; i++) list_splice_init(&adapter->req_list[i], &remove_queue); spin_unlock_irqrestore(&adapter->req_list_lock, flags); @@ -726,7 +725,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) goto failed_req_create; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; fsf_req->sbale_curr = 2; @@ -763,7 +762,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) failed_req_create: zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); out: - write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } @@ -1075,7 +1074,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, &unit->status))) goto unit_blocked; - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1098,7 +1097,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, fsf_req = NULL; out: - write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return fsf_req; } @@ -1295,7 +1294,7 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, goto failed_req; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); if (zfcp_use_one_sbal(ct->req, ct->req_count, ct->resp, ct->resp_count)){ /* both request buffer and response buffer @@ -1311,7 +1310,7 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, /* try to use chained SBALs */ bytes = zfcp_qdio_sbals_from_sg(fsf_req, SBAL_FLAGS0_TYPE_WRITE_READ, - ct->req, ct->req_count, + ct->req, ZFCP_MAX_SBALS_PER_CT_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of CT request failed " @@ -1328,7 +1327,7 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; bytes = zfcp_qdio_sbals_from_sg(fsf_req, SBAL_FLAGS0_TYPE_WRITE_READ, - ct->resp, ct->resp_count, + ct->resp, ZFCP_MAX_SBALS_PER_CT_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of CT request failed " @@ -1387,8 +1386,7 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, } failed_req: out: - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return ret; } @@ -1593,7 +1591,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) goto port_blocked; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); if (zfcp_use_one_sbal(els->req, els->req_count, els->resp, els->resp_count)){ /* both request buffer and response buffer @@ -1609,7 +1607,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) /* try to use chained SBALs */ bytes = zfcp_qdio_sbals_from_sg(fsf_req, SBAL_FLAGS0_TYPE_WRITE_READ, - els->req, els->req_count, + els->req, ZFCP_MAX_SBALS_PER_ELS_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " @@ -1626,7 +1624,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; bytes = zfcp_qdio_sbals_from_sg(fsf_req, SBAL_FLAGS0_TYPE_WRITE_READ, - els->resp, els->resp_count, + els->resp, ZFCP_MAX_SBALS_PER_ELS_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " @@ -1657,7 +1655,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT; fsf_req->data = (unsigned long) els; - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); zfcp_san_dbf_event_els_request(fsf_req); @@ -1680,8 +1678,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) failed_req: out: - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return ret; } @@ -1863,12 +1860,11 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) ZFCP_LOG_INFO("error: Could not create exchange configuration " "data request for adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1882,8 +1878,7 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); if (retval) { ZFCP_LOG_INFO("error: Could not send exchange configuration " "data command on the adapter %s\n", @@ -1916,12 +1911,11 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, ZFCP_LOG_INFO("error: Could not create exchange configuration " "data request for adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1936,8 +1930,7 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(fsf_req); - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); if (retval) ZFCP_LOG_INFO("error: Could not send exchange configuration " "data command on the adapter %s\n", @@ -2178,12 +2171,11 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) "exchange port data request for " "the adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2192,7 +2184,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); - write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); if (retval) { ZFCP_LOG_INFO("error: Could not send an exchange port data " @@ -2237,21 +2229,20 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, "exchange port data request for " "the adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); - write_unlock_irqrestore(&adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } if (data) fsf_req->data = (unsigned long) data; - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(fsf_req); - write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); if (retval) ZFCP_LOG_INFO("error: Could not send an exchange port data " @@ -2355,7 +2346,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2382,8 +2373,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) zfcp_get_busid_by_adapter(erp_action->adapter), erp_action->port->wwpn); out: - write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; } @@ -2587,7 +2577,7 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2615,8 +2605,7 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) zfcp_get_busid_by_adapter(erp_action->adapter), erp_action->port->wwpn); out: - write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; } @@ -2716,7 +2705,7 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2746,8 +2735,7 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) zfcp_get_busid_by_adapter(erp_action->adapter), erp_action->port->wwpn); out: - write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; } @@ -2911,7 +2899,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2944,8 +2932,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) zfcp_get_busid_by_adapter(erp_action->adapter), erp_action->port->wwpn, erp_action->unit->fcp_lun); out: - write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; } @@ -3226,7 +3213,7 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -3255,8 +3242,7 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) zfcp_get_busid_by_adapter(erp_action->adapter), erp_action->port->wwpn, erp_action->unit->fcp_lun); out: - write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, - lock_flags); + write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; } @@ -3498,7 +3484,9 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t); /* generate SBALEs from data buffer */ - real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd); + real_bytes = zfcp_qdio_sbals_from_sg(fsf_req, sbtype, + scsi_sglist(scsi_cmnd), + ZFCP_MAX_SBALS_PER_REQ); if (unlikely(real_bytes < 0)) { if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) { ZFCP_LOG_DEBUG( @@ -3556,7 +3544,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, scsi_cmnd->host_scribble = NULL; success: failed_req_create: - write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } @@ -3609,7 +3597,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, fsf_req->qtcb->bottom.io.fcp_cmnd_length = sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t); - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -3629,7 +3617,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, fsf_req = NULL; out: - write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return fsf_req; } @@ -4216,7 +4204,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, goto unlock_queue_lock; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= direction; bottom = &fsf_req->qtcb->bottom.support; @@ -4224,7 +4212,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, bottom->option = fsf_cfdc->option; bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, - fsf_cfdc->sg, ZFCP_CFDC_PAGES, + fsf_cfdc->sg, ZFCP_MAX_SBALS_PER_REQ); if (bytes != ZFCP_CFDC_MAX_SIZE) { retval = -ENOMEM; @@ -4237,7 +4225,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, retval = -EPERM; goto free_fsf_req; } - write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); wait_event(fsf_req->completion_wq, fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); @@ -4247,7 +4235,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, free_fsf_req: zfcp_fsf_req_free(fsf_req); unlock_queue_lock: - write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return ERR_PTR(retval); } @@ -4261,10 +4249,10 @@ static inline int zfcp_fsf_req_sbal_check(unsigned long *flags, struct zfcp_qdio_queue *queue, int needed) { - write_lock_irqsave(&queue->queue_lock, *flags); - if (likely(atomic_read(&queue->free_count) >= needed)) + write_lock_irqsave(&queue->lock, *flags); + if (likely(atomic_read(&queue->count) >= needed)) return 1; - write_unlock_irqrestore(&queue->queue_lock, *flags); + write_unlock_irqrestore(&queue->lock, *flags); return 0; } @@ -4293,24 +4281,24 @@ zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) * @req_flags: flags indicating whether to wait for needed SBAL or not * @lock_flags: lock_flags if queue_lock is taken * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS - * Locks: lock adapter->request_queue->queue_lock on success + * Locks: lock adapter->req_q->lock on success */ static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags, unsigned long *lock_flags) { long ret; - struct zfcp_qdio_queue *req_queue = &adapter->request_queue; + struct zfcp_qdio_queue *req_q = &adapter->req_q; if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) { ret = wait_event_interruptible_timeout(adapter->request_wq, - zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1), + zfcp_fsf_req_sbal_check(lock_flags, req_q, 1), ZFCP_SBAL_TIMEOUT); if (ret < 0) return ret; if (!ret) return -EIO; - } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1)) + } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_q, 1)) return -EIO; return 0; @@ -4340,7 +4328,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, volatile struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req = NULL; int ret = 0; - struct zfcp_qdio_queue *req_queue = &adapter->request_queue; + struct zfcp_qdio_queue *req_q = &adapter->req_q; /* allocate new FSF request */ fsf_req = zfcp_fsf_req_alloc(pool, req_flags); @@ -4377,7 +4365,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, */ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { - write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags); + write_unlock_irqrestore(&req_q->lock, *lock_flags); ret = -EIO; goto failed_sbals; } @@ -4387,15 +4375,15 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; } fsf_req->sbal_number = 1; - fsf_req->sbal_first = req_queue->free_index; - fsf_req->sbal_last = req_queue->free_index; + fsf_req->sbal_first = req_q->first; + fsf_req->sbal_last = req_q->first; fsf_req->sbale_curr = 1; if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) { fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; } - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); /* setup common SBALE fields */ sbale[0].addr = (void *) fsf_req->req_id; @@ -4416,7 +4404,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, fsf_req = NULL; failed_fsf_req: - write_lock_irqsave(&req_queue->queue_lock, *lock_flags); + write_lock_irqsave(&req_q->lock, *lock_flags); success: *fsf_req_p = fsf_req; return ret; @@ -4433,18 +4421,17 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter; - struct zfcp_qdio_queue *req_queue; + struct zfcp_qdio_queue *req_q; volatile struct qdio_buffer_element *sbale; int inc_seq_no; - int new_distance_from_int; int retval = 0; adapter = fsf_req->adapter; - req_queue = &adapter->request_queue, + req_q = &adapter->req_q; /* FIXME(debug): remove it later */ - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags); ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr, @@ -4457,52 +4444,24 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) inc_seq_no = (fsf_req->qtcb != NULL); - ZFCP_LOG_TRACE("request queue of adapter %s: " - "next free SBAL is %i, %i free SBALs\n", - zfcp_get_busid_by_adapter(adapter), - req_queue->free_index, - atomic_read(&req_queue->free_count)); - - ZFCP_LOG_DEBUG("calling do_QDIO adapter %s, flags=0x%x, queue_no=%i, " - "index_in_queue=%i, count=%i, buffers=%p\n", - zfcp_get_busid_by_adapter(adapter), - QDIO_FLAG_SYNC_OUTPUT, - 0, fsf_req->sbal_first, fsf_req->sbal_number, - &req_queue->buffer[fsf_req->sbal_first]); - - /* - * adjust the number of free SBALs in request queue as well as - * position of first one - */ - atomic_sub(fsf_req->sbal_number, &req_queue->free_count); - ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count)); - req_queue->free_index += fsf_req->sbal_number; /* increase */ - req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap if needed */ - new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req); - fsf_req->issued = get_clock(); - retval = do_QDIO(adapter->ccw_device, - QDIO_FLAG_SYNC_OUTPUT, - 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL); + retval = zfcp_qdio_send(fsf_req); if (unlikely(retval)) { /* Queues are down..... */ - retval = -EIO; del_timer(&fsf_req->timer); spin_lock(&adapter->req_list_lock); zfcp_reqlist_remove(adapter, fsf_req); spin_unlock(&adapter->req_list_lock); /* undo changes in request queue made for this request */ - zfcp_qdio_zero_sbals(req_queue->buffer, - fsf_req->sbal_first, fsf_req->sbal_number); - atomic_add(fsf_req->sbal_number, &req_queue->free_count); - req_queue->free_index -= fsf_req->sbal_number; - req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q; - req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ + atomic_add(fsf_req->sbal_number, &req_q->count); + req_q->first -= fsf_req->sbal_number; + req_q->first += QDIO_MAX_BUFFERS_PER_Q; + req_q->first %= QDIO_MAX_BUFFERS_PER_Q; zfcp_erp_adapter_reopen(adapter, 0, 116, fsf_req); + retval = -EIO; } else { - req_queue->distance_from_int = new_distance_from_int; /* * increase FSF sequence counter - * this must only be done for request successfully enqueued to @@ -4514,9 +4473,6 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) /* Don't increase for unsolicited status */ if (inc_seq_no) adapter->fsf_req_seq_no++; - - /* count FSF requests pending */ - atomic_inc(&adapter->reqs_active); } return retval; } diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index e71547357f62..bd6561d53589 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -1,241 +1,92 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Setup and helper functions to access QDIO. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #include "zfcp_ext.h" -static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); -static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get - (struct zfcp_qdio_queue *, int, int); -static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp - (struct zfcp_fsf_req *, int, int); -static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain - (struct zfcp_fsf_req *, unsigned long); -static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next - (struct zfcp_fsf_req *, unsigned long); -static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); -static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *); -static void zfcp_qdio_sbale_fill - (struct zfcp_fsf_req *, unsigned long, void *, int); -static int zfcp_qdio_sbals_from_segment - (struct zfcp_fsf_req *, unsigned long, void *, unsigned long); - -static qdio_handler_t zfcp_qdio_request_handler; -static qdio_handler_t zfcp_qdio_response_handler; -static int zfcp_qdio_handler_error_check(struct zfcp_adapter *, - unsigned int, unsigned int, unsigned int, int, int); - -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO +/* FIXME(tune): free space should be one max. SBAL chain plus what? */ +#define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ + - (ZFCP_MAX_SBALS_PER_REQ + 4)) -/* - * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array - * in the adapter struct sbuf is the pointer array. - * - * locks: must only be called with zfcp_data.config_sema taken - */ -static void -zfcp_qdio_buffers_dequeue(struct qdio_buffer **sbuf) -{ - int pos; - - for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) - free_page((unsigned long) sbuf[pos]); -} - -/* - * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t - * array in the adapter struct. - * Cur_buf is the pointer array - * - * returns: zero on success else -ENOMEM - * locks: must only be called with zfcp_data.config_sema taken - */ -static int -zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbuf) +static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) { int pos; for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) { - sbuf[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL); - if (!sbuf[pos]) { - zfcp_qdio_buffers_dequeue(sbuf); + sbal[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL); + if (!sbal[pos]) return -ENOMEM; - } } for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++) if (pos % QBUFF_PER_PAGE) - sbuf[pos] = sbuf[pos - 1] + 1; + sbal[pos] = sbal[pos - 1] + 1; return 0; } -/* locks: must only be called with zfcp_data.config_sema taken */ -int -zfcp_qdio_allocate_queues(struct zfcp_adapter *adapter) +static volatile struct qdio_buffer_element * +zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) { - int ret; - - ret = zfcp_qdio_buffers_enqueue(adapter->request_queue.buffer); - if (ret) - return ret; - return zfcp_qdio_buffers_enqueue(adapter->response_queue.buffer); + return &q->sbal[sbal_idx]->element[sbale_idx]; } -/* locks: must only be called with zfcp_data.config_sema taken */ -void -zfcp_qdio_free_queues(struct zfcp_adapter *adapter) +/** + * zfcp_qdio_free - free memory used by request- and resposne queue + * @adapter: pointer to the zfcp_adapter structure + */ +void zfcp_qdio_free(struct zfcp_adapter *adapter) { - ZFCP_LOG_TRACE("freeing request_queue buffers\n"); - zfcp_qdio_buffers_dequeue(adapter->request_queue.buffer); - - ZFCP_LOG_TRACE("freeing response_queue buffers\n"); - zfcp_qdio_buffers_dequeue(adapter->response_queue.buffer); -} + struct qdio_buffer **sbal_req, **sbal_resp; + int p; -int -zfcp_qdio_allocate(struct zfcp_adapter *adapter) -{ - struct qdio_initialize *init_data; + if (adapter->ccw_device) + qdio_free(adapter->ccw_device); - init_data = &adapter->qdio_init_data; + sbal_req = adapter->req_q.sbal; + sbal_resp = adapter->resp_q.sbal; - init_data->cdev = adapter->ccw_device; - init_data->q_format = QDIO_SCSI_QFMT; - memcpy(init_data->adapter_name, zfcp_get_busid_by_adapter(adapter), 8); - ASCEBC(init_data->adapter_name, 8); - init_data->qib_param_field_format = 0; - init_data->qib_param_field = NULL; - init_data->input_slib_elements = NULL; - init_data->output_slib_elements = NULL; - init_data->min_input_threshold = ZFCP_MIN_INPUT_THRESHOLD; - init_data->max_input_threshold = ZFCP_MAX_INPUT_THRESHOLD; - init_data->min_output_threshold = ZFCP_MIN_OUTPUT_THRESHOLD; - init_data->max_output_threshold = ZFCP_MAX_OUTPUT_THRESHOLD; - init_data->no_input_qs = 1; - init_data->no_output_qs = 1; - init_data->input_handler = zfcp_qdio_response_handler; - init_data->output_handler = zfcp_qdio_request_handler; - init_data->int_parm = (unsigned long) adapter; - init_data->flags = QDIO_INBOUND_0COPY_SBALS | - QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; - init_data->input_sbal_addr_array = - (void **) (adapter->response_queue.buffer); - init_data->output_sbal_addr_array = - (void **) (adapter->request_queue.buffer); - - return qdio_allocate(init_data); + for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) { + free_page((unsigned long) sbal_req[p]); + free_page((unsigned long) sbal_resp[p]); + } } -/* - * function: zfcp_qdio_handler_error_check - * - * purpose: called by the response handler to determine error condition - * - * returns: error flag - * - */ -static int -zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, - unsigned int qdio_error, unsigned int siga_error, - int first_element, int elements_processed) +static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, u8 id) { - int retval = 0; + dev_warn(&adapter->ccw_device->dev, "QDIO problem occurred.\n"); - if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { - retval = -EIO; - - ZFCP_LOG_INFO("QDIO problem occurred (status=0x%x, " - "qdio_error=0x%x, siga_error=0x%x)\n", - status, qdio_error, siga_error); - - zfcp_hba_dbf_event_qdio(adapter, status, qdio_error, siga_error, - first_element, elements_processed); - /* - * Restarting IO on the failed adapter from scratch. - * Since we have been using this adapter, it is save to assume - * that it is not failed but recoverable. The card seems to - * report link-up events by self-initiated queue shutdown. - * That is why we need to clear the link-down flag - * which is set again in case we have missed by a mile. - */ - zfcp_erp_adapter_reopen(adapter, - ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | - ZFCP_STATUS_COMMON_ERP_FAILED, 140, - NULL); - } - return retval; + zfcp_erp_adapter_reopen(adapter, + ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | + ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); } -/* - * function: zfcp_qdio_request_handler - * - * purpose: is called by QDIO layer for completed SBALs in request queue - * - * returns: (void) - */ -static void -zfcp_qdio_request_handler(struct ccw_device *ccw_device, - unsigned int status, - unsigned int qdio_error, - unsigned int siga_error, - unsigned int queue_number, - int first_element, - int elements_processed, - unsigned long int_parm) +static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int status, + unsigned int qdio_err, unsigned int siga_err, + unsigned int queue_no, int first, int count, + unsigned long parm) { - struct zfcp_adapter *adapter; - struct zfcp_qdio_queue *queue; - - adapter = (struct zfcp_adapter *) int_parm; - queue = &adapter->request_queue; + struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; + struct zfcp_qdio_queue *queue = &adapter->req_q; - ZFCP_LOG_DEBUG("adapter %s, first=%d, elements_processed=%d\n", - zfcp_get_busid_by_adapter(adapter), - first_element, elements_processed); - - if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, - siga_error, first_element, - elements_processed))) - goto out; - /* - * we stored address of struct zfcp_adapter data structure - * associated with irq in int_parm - */ + if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { + zfcp_hba_dbf_event_qdio(adapter, status, qdio_err, siga_err, + first, count); + zfcp_qdio_handler_error(adapter, 140); + return; + } /* cleanup all SBALs being program-owned now */ - zfcp_qdio_zero_sbals(queue->buffer, first_element, elements_processed); + zfcp_qdio_zero_sbals(queue->sbal, first, count); - /* increase free space in outbound queue */ - atomic_add(elements_processed, &queue->free_count); - ZFCP_LOG_DEBUG("free_count=%d\n", atomic_read(&queue->free_count)); + atomic_add(count, &queue->count); wake_up(&adapter->request_wq); - ZFCP_LOG_DEBUG("elements_processed=%d, free count=%d\n", - elements_processed, atomic_read(&queue->free_count)); - out: - return; } -/** - * zfcp_qdio_reqid_check - checks for valid reqids. - */ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, - unsigned long req_id, int sbal) + unsigned long req_id, int sbal_idx) { struct zfcp_fsf_req *fsf_req; unsigned long flags; @@ -248,204 +99,117 @@ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, * Unknown request means that we have potentially memory * corruption and must stop the machine immediatly. */ - panic("error: unknown request id (%ld) on adapter %s.\n", + panic("error: unknown request id (%lx) on adapter %s.\n", req_id, zfcp_get_busid_by_adapter(adapter)); zfcp_reqlist_remove(adapter, fsf_req); - atomic_dec(&adapter->reqs_active); spin_unlock_irqrestore(&adapter->req_list_lock, flags); - fsf_req->sbal_response = sbal; - /* finish the FSF request */ + fsf_req->sbal_response = sbal_idx; zfcp_fsf_req_complete(fsf_req); } -/* - * function: zfcp_qdio_response_handler - * - * purpose: is called by QDIO layer for completed SBALs in response queue - * - * returns: (void) - */ -static void -zfcp_qdio_response_handler(struct ccw_device *ccw_device, - unsigned int status, - unsigned int qdio_error, - unsigned int siga_error, - unsigned int queue_number, - int first_element, - int elements_processed, - unsigned long int_parm) +static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed) { - struct zfcp_adapter *adapter; - struct zfcp_qdio_queue *queue; - int buffer_index; - int i; - struct qdio_buffer *buffer; - int retval = 0; - u8 count; - u8 start; - volatile struct qdio_buffer_element *buffere = NULL; - int buffere_index; - - adapter = (struct zfcp_adapter *) int_parm; - queue = &adapter->response_queue; - - if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, - siga_error, first_element, - elements_processed))) - goto out; + struct zfcp_qdio_queue *queue = &adapter->resp_q; + struct ccw_device *cdev = adapter->ccw_device; + u8 count, start = queue->first; + unsigned int retval; - /* - * we stored address of struct zfcp_adapter data structure - * associated with irq in int_parm - */ + count = atomic_read(&queue->count) + processed; + + retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, + 0, start, count, NULL); + + if (unlikely(retval)) { + atomic_set(&queue->count, count); + /* FIXME: Recover this with an adapter reopen? */ + } else { + queue->first += count; + queue->first %= QDIO_MAX_BUFFERS_PER_Q; + atomic_set(&queue->count, 0); + } +} + +static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int status, + unsigned int qdio_err, unsigned int siga_err, + unsigned int queue_no, int first, int count, + unsigned long parm) +{ + struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; + struct zfcp_qdio_queue *queue = &adapter->resp_q; + volatile struct qdio_buffer_element *sbale; + int sbal_idx, sbale_idx, sbal_no; + + if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { + zfcp_hba_dbf_event_qdio(adapter, status, qdio_err, siga_err, + first, count); + zfcp_qdio_handler_error(adapter, 147); + return; + } - buffere = &(queue->buffer[first_element]->element[0]); - ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x\n", buffere->flags); /* * go through all SBALs from input queue currently * returned by QDIO layer */ - - for (i = 0; i < elements_processed; i++) { - - buffer_index = first_element + i; - buffer_index %= QDIO_MAX_BUFFERS_PER_Q; - buffer = queue->buffer[buffer_index]; + for (sbal_no = 0; sbal_no < count; sbal_no++) { + sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; /* go through all SBALEs of SBAL */ - for (buffere_index = 0; - buffere_index < QDIO_MAX_ELEMENTS_PER_BUFFER; - buffere_index++) { - - /* look for QDIO request identifiers in SB */ - buffere = &buffer->element[buffere_index]; + for (sbale_idx = 0; sbale_idx < QDIO_MAX_ELEMENTS_PER_BUFFER; + sbale_idx++) { + sbale = zfcp_qdio_sbale(queue, sbal_idx, sbale_idx); zfcp_qdio_reqid_check(adapter, - (unsigned long) buffere->addr, i); - - /* - * A single used SBALE per inbound SBALE has been - * implemented by QDIO so far. Hope they will - * do some optimisation. Will need to change to - * unlikely() then. - */ - if (likely(buffere->flags & SBAL_FLAGS_LAST_ENTRY)) + (unsigned long) sbale->addr, + sbal_idx); + if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) break; }; - if (unlikely(!(buffere->flags & SBAL_FLAGS_LAST_ENTRY))) { - ZFCP_LOG_NORMAL("bug: End of inbound data " - "not marked!\n"); - } + if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY))) + dev_warn(&adapter->ccw_device->dev, + "Protocol violation by adapter. " + "Continuing operations.\n"); } /* * put range of SBALs back to response queue * (including SBALs which have already been free before) */ - count = atomic_read(&queue->free_count) + elements_processed; - start = queue->free_index; - - ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, " - "queue_no=%i, index_in_queue=%i, count=%i, " - "buffers=0x%lx\n", - zfcp_get_busid_by_adapter(adapter), - QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, - 0, start, count, (unsigned long) &queue->buffer[start]); - - retval = do_QDIO(ccw_device, - QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, - 0, start, count, NULL); - - if (unlikely(retval)) { - atomic_set(&queue->free_count, count); - ZFCP_LOG_DEBUG("clearing of inbound data regions failed, " - "queues may be down " - "(count=%d, start=%d, retval=%d)\n", - count, start, retval); - } else { - queue->free_index += count; - queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; - atomic_set(&queue->free_count, 0); - ZFCP_LOG_TRACE("%i buffers enqueued to response " - "queue at position %i\n", count, start); - } - out: - return; + zfcp_qdio_resp_put_back(adapter, count); } /** - * zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue - * @queue: queue from which SBALE should be returned - * @sbal: specifies number of SBAL in queue - * @sbale: specifes number of SBALE in SBAL - */ -static inline volatile struct qdio_buffer_element * -zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale) -{ - return &queue->buffer[sbal]->element[sbale]; -} - -/** - * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for - * a struct zfcp_fsf_req + * zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req + * @fsf_req: pointer to struct fsf_req + * Returns: pointer to qdio_buffer_element (SBALE) structure */ volatile struct qdio_buffer_element * -zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) -{ - return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue, - sbal, sbale); -} - -/** - * zfcp_qdio_sbale_resp - return pointer to SBALE of response_queue for - * a struct zfcp_fsf_req - */ -static inline volatile struct qdio_buffer_element * -zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) +zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) { - return zfcp_qdio_sbale_get(&fsf_req->adapter->response_queue, - sbal, sbale); + return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0); } /** - * zfcp_qdio_sbale_curr - return current SBALE on request_queue for - * a struct zfcp_fsf_req + * zfcp_qdio_sbale_curr - return curr SBALE on req_q for a struct zfcp_fsf_req + * @fsf_req: pointer to struct fsf_req + * Returns: pointer to qdio_buffer_element (SBALE) structure */ volatile struct qdio_buffer_element * -zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) +zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req) { - return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, - fsf_req->sbale_curr); + return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, + req->sbale_curr); } -/** - * zfcp_qdio_sbal_limit - determine maximum number of SBALs that can be used - * on the request_queue for a struct zfcp_fsf_req - * @fsf_req: the number of the last SBAL that can be used is stored herein - * @max_sbals: used to pass an upper limit for the number of SBALs - * - * Note: We can assume at least one free SBAL in the request_queue when called. - */ -static void -zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) +static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) { - int count = atomic_read(&fsf_req->adapter->request_queue.free_count); + int count = atomic_read(&fsf_req->adapter->req_q.count); count = min(count, max_sbals); - fsf_req->sbal_limit = fsf_req->sbal_first; - fsf_req->sbal_limit += (count - 1); - fsf_req->sbal_limit %= QDIO_MAX_BUFFERS_PER_Q; + fsf_req->sbal_limit = (fsf_req->sbal_first + count - 1) + % QDIO_MAX_BUFFERS_PER_Q; } -/** - * zfcp_qdio_sbal_chain - chain SBALs if more than one SBAL is needed for a - * request - * @fsf_req: zfcp_fsf_req to be processed - * @sbtype: SBAL flags which have to be set in first SBALE of new SBAL - * - * This function changes sbal_last, sbale_curr, sbal_number of fsf_req. - */ static volatile struct qdio_buffer_element * zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) { @@ -460,7 +224,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) return NULL; /* set chaining flag in first SBALE of current SBAL */ - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + sbale = zfcp_qdio_sbale_req(fsf_req); sbale->flags |= SBAL_FLAGS0_MORE_SBALS; /* calculate index of next SBAL */ @@ -480,214 +244,271 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) return sbale; } -/** - * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed - */ static volatile struct qdio_buffer_element * zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) { if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) return zfcp_qdio_sbal_chain(fsf_req, sbtype); - fsf_req->sbale_curr++; - return zfcp_qdio_sbale_curr(fsf_req); } -/** - * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue - * with zero from - */ -static int -zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last) +static void zfcp_qdio_undo_sbals(struct zfcp_fsf_req *fsf_req) { - struct qdio_buffer **buf = queue->buffer; - int curr = first; - int count = 0; - - for(;;) { - curr %= QDIO_MAX_BUFFERS_PER_Q; - count++; - memset(buf[curr], 0, sizeof(struct qdio_buffer)); - if (curr == last) - break; - curr++; - } - return count; + struct qdio_buffer **sbal = fsf_req->adapter->req_q.sbal; + int first = fsf_req->sbal_first; + int last = fsf_req->sbal_last; + int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) % + QDIO_MAX_BUFFERS_PER_Q + 1; + zfcp_qdio_zero_sbals(sbal, first, count); } - -/** - * zfcp_qdio_sbals_wipe - reset all changes in SBALs for an fsf_req - */ -static inline int -zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req) -{ - return zfcp_qdio_sbals_zero(&fsf_req->adapter->request_queue, - fsf_req->sbal_first, fsf_req->sbal_last); -} - - -/** - * zfcp_qdio_sbale_fill - set address and length in current SBALE - * on request_queue - */ -static void -zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, - void *addr, int length) +static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, + unsigned int sbtype, void *start_addr, + unsigned int total_length) { volatile struct qdio_buffer_element *sbale; - - sbale = zfcp_qdio_sbale_curr(fsf_req); - sbale->addr = addr; - sbale->length = length; -} - -/** - * zfcp_qdio_sbals_from_segment - map memory segment to SBALE(s) - * @fsf_req: request to be processed - * @sbtype: SBALE flags - * @start_addr: address of memory segment - * @total_length: length of memory segment - * - * Alignment and length of the segment determine how many SBALEs are needed - * for the memory segment. - */ -static int -zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, - void *start_addr, unsigned long total_length) -{ unsigned long remaining, length; void *addr; - /* split segment up heeding page boundaries */ + /* split segment up */ for (addr = start_addr, remaining = total_length; remaining > 0; addr += length, remaining -= length) { - /* get next free SBALE for new piece */ - if (NULL == zfcp_qdio_sbale_next(fsf_req, sbtype)) { - /* no SBALE left, clean up and leave */ - zfcp_qdio_sbals_wipe(fsf_req); + sbale = zfcp_qdio_sbale_next(fsf_req, sbtype); + if (!sbale) { + zfcp_qdio_undo_sbals(fsf_req); return -EINVAL; } - /* calculate length of new piece */ + + /* new piece must not exceed next page boundary */ length = min(remaining, - (PAGE_SIZE - ((unsigned long) addr & + (PAGE_SIZE - ((unsigned long)addr & (PAGE_SIZE - 1)))); - /* fill current SBALE with calculated piece */ - zfcp_qdio_sbale_fill(fsf_req, sbtype, addr, length); + sbale->addr = addr; + sbale->length = length; } - return total_length; + return 0; } - /** * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list * @fsf_req: request to be processed * @sbtype: SBALE flags * @sg: scatter-gather list - * @sg_count: number of elements in scatter-gather list * @max_sbals: upper bound for number of SBALs to be used + * Returns: number of bytes, or error (negativ) */ -int -zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, - struct scatterlist *sgl, int sg_count, int max_sbals) +int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, + struct scatterlist *sg, int max_sbals) { - int sg_index; - struct scatterlist *sg_segment; - int retval; volatile struct qdio_buffer_element *sbale; - int bytes = 0; + int retval, bytes = 0; /* figure out last allowed SBAL */ zfcp_qdio_sbal_limit(fsf_req, max_sbals); - /* set storage-block type for current SBAL */ - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_last, 0); + /* set storage-block type for this request */ + sbale = zfcp_qdio_sbale_req(fsf_req); sbale->flags |= sbtype; - /* process all segements of scatter-gather list */ - for_each_sg(sgl, sg_segment, sg_count, sg_index) { - retval = zfcp_qdio_sbals_from_segment( - fsf_req, - sbtype, - zfcp_sg_to_address(sg_segment), - sg_segment->length); - if (retval < 0) { - bytes = retval; - goto out; - } else - bytes += retval; + for (; sg; sg = sg_next(sg)) { + retval = zfcp_qdio_fill_sbals(fsf_req, sbtype, sg_virt(sg), + sg->length); + if (retval < 0) + return retval; + bytes += sg->length; } + /* assume that no other SBALEs are to follow in the same SBAL */ sbale = zfcp_qdio_sbale_curr(fsf_req); sbale->flags |= SBAL_FLAGS_LAST_ENTRY; -out: + return bytes; } - /** - * zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command - * @fsf_req: request to be processed - * @sbtype: SBALE flags - * @scsi_cmnd: either scatter-gather list or buffer contained herein is used - * to fill SBALs + * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO + * @fsf_req: pointer to struct zfcp_fsf_req + * Returns: 0 on success, error otherwise */ -int -zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, - unsigned long sbtype, struct scsi_cmnd *scsi_cmnd) +int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req) { - return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, scsi_sglist(scsi_cmnd), - scsi_sg_count(scsi_cmnd), - ZFCP_MAX_SBALS_PER_REQ); + struct zfcp_adapter *adapter = fsf_req->adapter; + struct zfcp_qdio_queue *req_q = &adapter->req_q; + int first = fsf_req->sbal_first; + int count = fsf_req->sbal_number; + int retval, pci, pci_batch; + volatile struct qdio_buffer_element *sbale; + + /* acknowledgements for transferred buffers */ + pci_batch = req_q->pci_batch + count; + if (unlikely(pci_batch >= ZFCP_QDIO_PCI_INTERVAL)) { + pci_batch %= ZFCP_QDIO_PCI_INTERVAL; + pci = first + count - (pci_batch + 1); + pci %= QDIO_MAX_BUFFERS_PER_Q; + sbale = zfcp_qdio_sbale(req_q, pci, 0); + sbale->flags |= SBAL_FLAGS0_PCI; + } + + retval = do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, first, + count, NULL); + if (unlikely(retval)) { + zfcp_qdio_zero_sbals(req_q->sbal, first, count); + return retval; + } + + /* account for transferred buffers */ + atomic_sub(count, &req_q->count); + req_q->first += count; + req_q->first %= QDIO_MAX_BUFFERS_PER_Q; + req_q->pci_batch = pci_batch; + return 0; } /** - * zfcp_qdio_determine_pci - set PCI flag in first SBALE on qdio queue if needed + * zfcp_qdio_zero_sbals - zero all sbals of the specified area and queue + * @buf: pointer to array of SBALS + * @first: integer specifying the SBAL number to start + * @count: integer specifying the number of SBALS to process */ -int -zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue, - struct zfcp_fsf_req *fsf_req) +void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int count) { - int new_distance_from_int; - int pci_pos; - volatile struct qdio_buffer_element *sbale; + int i, sbal_idx; - new_distance_from_int = req_queue->distance_from_int + - fsf_req->sbal_number; - - if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) { - new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL; - pci_pos = fsf_req->sbal_first; - pci_pos += fsf_req->sbal_number; - pci_pos -= new_distance_from_int; - pci_pos -= 1; - pci_pos %= QDIO_MAX_BUFFERS_PER_Q; - sbale = zfcp_qdio_sbale_req(fsf_req, pci_pos, 0); - sbale->flags |= SBAL_FLAGS0_PCI; + for (i = first; i < first + count; i++) { + sbal_idx = i % QDIO_MAX_BUFFERS_PER_Q; + memset(sbal[sbal_idx], 0, sizeof(struct qdio_buffer)); } - return new_distance_from_int; } -/* - * function: zfcp_zero_sbals - * - * purpose: zeros specified range of SBALs - * - * returns: +/** + * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data + * @adapter: pointer to struct zfcp_adapter + * Returns: -ENOMEM on memory allocation error or return value from + * qdio_allocate + */ +int zfcp_qdio_allocate(struct zfcp_adapter *adapter) +{ + struct qdio_initialize *init_data; + + if (zfcp_qdio_buffers_enqueue(adapter->req_q.sbal) || + zfcp_qdio_buffers_enqueue(adapter->resp_q.sbal)) + return -ENOMEM; + + init_data = &adapter->qdio_init_data; + + init_data->cdev = adapter->ccw_device; + init_data->q_format = QDIO_ZFCP_QFMT; + memcpy(init_data->adapter_name, zfcp_get_busid_by_adapter(adapter), 8); + ASCEBC(init_data->adapter_name, 8); + init_data->qib_param_field_format = 0; + init_data->qib_param_field = NULL; + init_data->input_slib_elements = NULL; + init_data->output_slib_elements = NULL; + init_data->min_input_threshold = 1; + init_data->max_input_threshold = 5000; + init_data->min_output_threshold = 1; + init_data->max_output_threshold = 1000; + init_data->no_input_qs = 1; + init_data->no_output_qs = 1; + init_data->input_handler = zfcp_qdio_int_resp; + init_data->output_handler = zfcp_qdio_int_req; + init_data->int_parm = (unsigned long) adapter; + init_data->flags = QDIO_INBOUND_0COPY_SBALS | + QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; + init_data->input_sbal_addr_array = + (void **) (adapter->resp_q.sbal); + init_data->output_sbal_addr_array = + (void **) (adapter->req_q.sbal); + + return qdio_allocate(init_data); +} + +/** + * zfcp_close_qdio - close qdio queues for an adapter */ -void -zfcp_qdio_zero_sbals(struct qdio_buffer *buf[], int first, int clean_count) +void zfcp_qdio_close(struct zfcp_adapter *adapter) { - int cur_pos; - int index; - - for (cur_pos = first; cur_pos < (first + clean_count); cur_pos++) { - index = cur_pos % QDIO_MAX_BUFFERS_PER_Q; - memset(buf[index], 0, sizeof (struct qdio_buffer)); - ZFCP_LOG_TRACE("zeroing BUFFER %d at address %p\n", - index, buf[index]); + struct zfcp_qdio_queue *req_q; + int first, count; + + if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) + return; + + /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ + req_q = &adapter->req_q; + write_lock_irq(&req_q->lock); + atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); + write_unlock_irq(&req_q->lock); + + while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) + == -EINPROGRESS) + ssleep(1); + + /* cleanup used outbound sbals */ + count = atomic_read(&req_q->count); + if (count < QDIO_MAX_BUFFERS_PER_Q) { + first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q; + count = QDIO_MAX_BUFFERS_PER_Q - count; + zfcp_qdio_zero_sbals(req_q->sbal, first, count); } + req_q->first = 0; + atomic_set(&req_q->count, 0); + req_q->pci_batch = 0; + adapter->resp_q.first = 0; + atomic_set(&adapter->resp_q.count, 0); } -#undef ZFCP_LOG_AREA +/** + * zfcp_qdio_open - prepare and initialize response queue + * @adapter: pointer to struct zfcp_adapter + * Returns: 0 on success, otherwise -EIO + */ +int zfcp_qdio_open(struct zfcp_adapter *adapter) +{ + volatile struct qdio_buffer_element *sbale; + int cc; + + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) + return -EIO; + + if (qdio_establish(&adapter->qdio_init_data)) { + dev_err(&adapter->ccw_device->dev, + "Establish of QDIO queues failed.\n"); + return -EIO; + } + + if (qdio_activate(adapter->ccw_device, 0)) { + dev_err(&adapter->ccw_device->dev, + "Activate of QDIO queues failed.\n"); + goto failed_qdio; + } + + for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) { + sbale = &(adapter->resp_q.sbal[cc]->element[0]); + sbale->length = 0; + sbale->flags = SBAL_FLAGS_LAST_ENTRY; + sbale->addr = NULL; + } + + if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0, + QDIO_MAX_BUFFERS_PER_Q, NULL)) { + dev_err(&adapter->ccw_device->dev, + "Init of QDIO response queue failed.\n"); + goto failed_qdio; + } + + /* set index of first avalable SBALS / number of available SBALS */ + adapter->req_q.first = 0; + atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q); + adapter->req_q.pci_batch = 0; + + return 0; + +failed_qdio: + while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) + == -EINPROGRESS) + ssleep(1); + + return -EIO; +} -- cgit v1.2.3 From 553448f6c4838a1e4bed2bc9301c748278d7d9ce Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 10 Jun 2008 18:20:58 +0200 Subject: [SCSI] zfcp: Message cleanup Cleanup the messages used in the zfcp driver: Remove unnecessary debug and trace message and convert the remaining messages to standard kernel macros. Remove the zfcp message macros and while updating the whole flie also update the copyright headers. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/Makefile | 2 +- drivers/s390/scsi/zfcp_aux.c | 75 +- drivers/s390/scsi/zfcp_dbf.c | 41 +- drivers/s390/scsi/zfcp_def.h | 124 +-- drivers/s390/scsi/zfcp_erp.c | 293 ++---- drivers/s390/scsi/zfcp_ext.h | 20 +- drivers/s390/scsi/zfcp_fsf.c | 1557 ++++++-------------------------- drivers/s390/scsi/zfcp_fsf.h | 20 +- drivers/s390/scsi/zfcp_scsi.c | 64 +- drivers/s390/scsi/zfcp_sysfs_adapter.c | 23 +- drivers/s390/scsi/zfcp_sysfs_driver.c | 106 --- drivers/s390/scsi/zfcp_sysfs_port.c | 23 +- drivers/s390/scsi/zfcp_sysfs_unit.c | 23 +- 13 files changed, 396 insertions(+), 1975 deletions(-) delete mode 100644 drivers/s390/scsi/zfcp_sysfs_driver.c (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index c0fa8ffe5448..1aa46500f650 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -4,6 +4,6 @@ zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ - zfcp_sysfs_unit.o zfcp_sysfs_driver.o zfcp_fc.o zfcp_cfdc.o + zfcp_sysfs_unit.o zfcp_fc.o zfcp_cfdc.o obj-$(CONFIG_ZFCP) += zfcp.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 7084a6ae1096..47739f4f6709 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -1,22 +1,9 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Module interface and handling of zfcp data structures. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ /* @@ -31,13 +18,16 @@ * Maxim Shchetynin * Volker Sameske * Ralph Wuerthner + * Michael Loehr + * Swen Schillig + * Christof Schmitt + * Martin Petermann + * Sven Schuetz */ #include #include "zfcp_ext.h" -/* accumulated log level (module parameter) */ -static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS; static char *device; /*********************** FUNCTION PROTOTYPES *********************************/ @@ -57,12 +47,6 @@ MODULE_LICENSE("GPL"); module_param(device, charp, 0400); MODULE_PARM_DESC(device, "specify initial device"); -module_param(loglevel, uint, 0400); -MODULE_PARM_DESC(loglevel, - "log levels, 8 nibbles: " - "FC ERP QDIO CIO Config FSF SCSI Other, " - "levels: 0=none 1=normal 2=devel 3=trace"); - /****************************************************************/ /************** Functions without logging ***********************/ /****************************************************************/ @@ -87,8 +71,6 @@ _zfcp_hex_dump(char *addr, int count) /****** Functions to handle the request ID hash table ********/ /****************************************************************/ -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF - static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) { int idx; @@ -118,14 +100,10 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) return 1; } -#undef ZFCP_LOG_AREA - /****************************************************************/ /************** Uncategorised Functions *************************/ /****************************************************************/ -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER - /** * zfcp_device_setup - setup function * @str: pointer to parameter string @@ -143,8 +121,11 @@ zfcp_device_setup(char *devstr) len = strlen(devstr) + 1; str = kmalloc(len, GFP_KERNEL); - if (!str) - goto err_out; + if (!str) { + pr_err("zfcp: Could not allocate memory for " + "device parameter string, device not attached.\n"); + return 0; + } memcpy(str, devstr, len); tmp = strchr(str, ','); @@ -167,7 +148,8 @@ zfcp_device_setup(char *devstr) return 1; err_out: - ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", str); + pr_err("zfcp: Parse error for device parameter string %s, " + "device not attached.\n", str); kfree(str); return 0; } @@ -248,8 +230,6 @@ zfcp_module_init(void) if (!zfcp_data.gid_pn_cache) goto out_gid_cache; - atomic_set(&zfcp_data.loglevel, loglevel); - /* initialize adapter list */ INIT_LIST_HEAD(&zfcp_data.adapter_list_head); @@ -263,8 +243,7 @@ zfcp_module_init(void) retval = misc_register(&zfcp_cfdc_misc); if (retval != 0) { - ZFCP_LOG_INFO("registration of misc device " - "zfcp_cfdc failed\n"); + pr_err("zfcp: registration of misc device zfcp_cfdc failed\n"); goto out_misc; } @@ -277,7 +256,7 @@ zfcp_module_init(void) /* setup dynamic I/O */ retval = zfcp_ccw_register(); if (retval) { - ZFCP_LOG_NORMAL("registration with common I/O layer failed\n"); + pr_err("zfcp: Registration with common I/O layer failed.\n"); goto out_ccw_register; } @@ -300,14 +279,10 @@ zfcp_module_init(void) return retval; } -#undef ZFCP_LOG_AREA - /****************************************************************/ /****** Functions for configuration/set-up of structures ********/ /****************************************************************/ -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG - /** * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN * @port: pointer to port to search for unit @@ -598,6 +573,8 @@ static void _zfcp_status_read_scheduler(struct work_struct *work) * All adapter internal structures are set up. * Proc-fs entries are also created. * + * FIXME: Use -ENOMEM as return code for allocation failures + * * returns: 0 if a new adapter was successfully enqueued * ZFCP_KNOWN if an adapter with this devno was already present * -ENOMEM if alloc failed @@ -615,11 +592,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) /* try to allocate new adapter data structure (zeroed) */ adapter = kzalloc(sizeof (struct zfcp_adapter), GFP_KERNEL); - if (!adapter) { - ZFCP_LOG_INFO("error: allocation of base adapter " - "structure failed\n"); + if (!adapter) goto out; - } ccw_device->handler = NULL; @@ -760,7 +734,6 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) zfcp_reqlist_free(adapter); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); - ZFCP_LOG_TRACE("freeing adapter structure\n"); kfree(adapter); out: return; @@ -908,12 +881,8 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, ZFCP_DID_DIRECTORY_SERVICE); - if (!port) { - ZFCP_LOG_INFO("error: enqueue of nameserver port for " - "adapter %s failed\n", - zfcp_get_busid_by_adapter(adapter)); + if (!port) return -ENXIO; - } zfcp_port_put(port); return 0; @@ -946,5 +915,3 @@ int zfcp_sg_setup_table(struct scatterlist *sg, int count) } return 0; } - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index c47c23a01c7f..7c72f502eb0f 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -1,22 +1,9 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Debug traces for zfcp. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #include @@ -29,8 +16,6 @@ module_param(dbfsize, uint, 0400); MODULE_PARM_DESC(dbfsize, "number of pages for each debug feature area (default 4)"); -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER - static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, int level, char *from, int from_len) { @@ -515,13 +500,13 @@ static const char *zfcp_rec_dbf_ids[] = { [52] = "port boxed close unit", [53] = "port boxed fcp", [54] = "unit boxed fcp", - [55] = "port access denied ct", - [56] = "port access denied els", - [57] = "port access denied open port", - [58] = "port access denied close physical", - [59] = "unit access denied open unit", + [55] = "port access denied", + [56] = "", + [57] = "", + [58] = "", + [59] = "unit access denied", [60] = "shared unit access denied open unit", - [61] = "unit access denied fcp", + [61] = "", [62] = "request timeout", [63] = "adisc link test reject or timeout", [64] = "adisc link test d_id changed", @@ -586,8 +571,8 @@ static const char *zfcp_rec_dbf_ids[] = { [120] = "unknown fsf command", [121] = "no recommendation for status qualifier", [122] = "status read physical port closed in error", - [123] = "fc service class not supported ct", - [124] = "fc service class not supported els", + [123] = "fc service class not supported", + [124] = "", [125] = "need newer zfcp", [126] = "need newer microcode", [127] = "arbitrated loop not supported", @@ -595,7 +580,7 @@ static const char *zfcp_rec_dbf_ids[] = { [129] = "qtcb size mismatch", [130] = "unknown fsf status ecd", [131] = "fcp request too big", - [132] = "fc service class not supported fcp", + [132] = "", [133] = "data direction not valid fcp", [134] = "command length not valid fcp", [135] = "status read act update", @@ -1291,5 +1276,3 @@ void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) adapter->hba_dbf = NULL; adapter->rec_dbf = NULL; } - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 5fcb555e1484..73425dbb2be8 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -1,22 +1,9 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Global definitions for the zfcp device driver. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #ifndef ZFCP_DEF_H @@ -52,9 +39,6 @@ /********************* GENERAL DEFINES *********************************/ -/* zfcp version number, it consists of major, minor, and patch-level number */ -#define ZFCP_VERSION "4.8.0" - /** * zfcp_sg_to_address - determine kernel address from struct scatterlist * @list: struct scatterlist @@ -308,107 +292,6 @@ struct zfcp_rc_entry { */ #define ZFCP_CT_TIMEOUT (3 * R_A_TOV) -/******************** LOGGING MACROS AND DEFINES *****************************/ - -/* - * Logging may be applied on certain kinds of driver operations - * independently. Additionally, different log-levels are supported for - * each of these areas. - */ - -#define ZFCP_NAME "zfcp" - -/* independent log areas */ -#define ZFCP_LOG_AREA_OTHER 0 -#define ZFCP_LOG_AREA_SCSI 1 -#define ZFCP_LOG_AREA_FSF 2 -#define ZFCP_LOG_AREA_CONFIG 3 -#define ZFCP_LOG_AREA_CIO 4 -#define ZFCP_LOG_AREA_QDIO 5 -#define ZFCP_LOG_AREA_ERP 6 -#define ZFCP_LOG_AREA_FC 7 - -/* log level values*/ -#define ZFCP_LOG_LEVEL_NORMAL 0 -#define ZFCP_LOG_LEVEL_INFO 1 -#define ZFCP_LOG_LEVEL_DEBUG 2 -#define ZFCP_LOG_LEVEL_TRACE 3 - -/* - * this allows removal of logging code by the preprocessor - * (the most detailed log level still to be compiled in is specified, - * higher log levels are removed) - */ -#define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE - -/* get "loglevel" nibble assignment */ -#define ZFCP_GET_LOG_VALUE(zfcp_lognibble) \ - ((atomic_read(&zfcp_data.loglevel) >> (zfcp_lognibble<<2)) & 0xF) - -/* set "loglevel" nibble */ -#define ZFCP_SET_LOG_NIBBLE(value, zfcp_lognibble) \ - (value << (zfcp_lognibble << 2)) - -/* all log-level defaults are combined to generate initial log-level */ -#define ZFCP_LOG_LEVEL_DEFAULTS \ - (ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_OTHER) | \ - ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_SCSI) | \ - ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_FSF) | \ - ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_CONFIG) | \ - ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_CIO) | \ - ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_QDIO) | \ - ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_ERP) | \ - ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_FC)) - -/* check whether we have the right level for logging */ -#define ZFCP_LOG_CHECK(level) \ - ((ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA)) >= level) - -/* logging routine for zfcp */ -#define _ZFCP_LOG(fmt, args...) \ - printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __func__, \ - __LINE__ , ##args) - -#define ZFCP_LOG(level, fmt, args...) \ -do { \ - if (ZFCP_LOG_CHECK(level)) \ - _ZFCP_LOG(fmt, ##args); \ -} while (0) - -#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL -# define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0) -#else -# define ZFCP_LOG_NORMAL(fmt, args...) \ -do { \ - if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \ - printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ -} while (0) -#endif - -#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO -# define ZFCP_LOG_INFO(fmt, args...) do { } while (0) -#else -# define ZFCP_LOG_INFO(fmt, args...) \ -do { \ - if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \ - printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ -} while (0) -#endif - -#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG -# define ZFCP_LOG_DEBUG(fmt, args...) do { } while (0) -#else -# define ZFCP_LOG_DEBUG(fmt, args...) \ - ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args) -#endif - -#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE -# define ZFCP_LOG_TRACE(fmt, args...) do { } while (0) -#else -# define ZFCP_LOG_TRACE(fmt, args...) \ - ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args) -#endif - /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ /* @@ -846,7 +729,6 @@ struct zfcp_data { char init_busid[BUS_ID_SIZE]; wwn_t init_wwpn; fcp_lun_t init_fcp_lun; - char *driver_version; struct kmem_cache *fsf_req_qtcb_cache; struct kmem_cache *sr_buffer_cache; struct kmem_cache *gid_pn_cache; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 4a6d08363d4b..c06156b288ea 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1,26 +1,11 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Error Recovery Procedures (ERP). * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP - #include "zfcp_ext.h" static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int, u8, @@ -171,14 +156,9 @@ static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, { int retval; - ZFCP_LOG_DEBUG("reopen adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - zfcp_erp_adapter_block(adapter, clear_mask); if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { - ZFCP_LOG_DEBUG("skipped reopen of failed adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); /* ensure propagation of failed status to new devices */ zfcp_erp_adapter_failed(adapter, 13, NULL); retval = -EIO; @@ -270,15 +250,9 @@ static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, { int retval; - ZFCP_LOG_DEBUG("forced reopen of port 0x%016Lx on adapter %s\n", - port->wwpn, zfcp_get_busid_by_port(port)); - zfcp_erp_port_block(port, clear_mask); if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { - ZFCP_LOG_DEBUG("skipped forced reopen of failed port 0x%016Lx " - "on adapter %s\n", port->wwpn, - zfcp_get_busid_by_port(port)); retval = -EIO; goto out; } @@ -332,15 +306,9 @@ static int zfcp_erp_port_reopen_internal(struct zfcp_port *port, int clear_mask, { int retval; - ZFCP_LOG_DEBUG("reopen of port 0x%016Lx on adapter %s\n", - port->wwpn, zfcp_get_busid_by_port(port)); - zfcp_erp_port_block(port, clear_mask); if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { - ZFCP_LOG_DEBUG("skipped reopen of failed port 0x%016Lx " - "on adapter %s\n", port->wwpn, - zfcp_get_busid_by_port(port)); /* ensure propagation of failed status to new devices */ zfcp_erp_port_failed(port, 14, NULL); retval = -EIO; @@ -396,17 +364,9 @@ static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask, int retval; struct zfcp_adapter *adapter = unit->port->adapter; - ZFCP_LOG_DEBUG("reopen of unit 0x%016Lx on port 0x%016Lx " - "on adapter %s\n", unit->fcp_lun, - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); - zfcp_erp_unit_block(unit, clear_mask); if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { - ZFCP_LOG_DEBUG("skipped reopen of failed unit 0x%016Lx " - "on port 0x%016Lx on adapter %s\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); retval = -EIO; goto out; } @@ -631,13 +591,8 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) ZFCP_STATUS_FSFREQ_DISMISSED; zfcp_rec_dbf_event_action(142, erp_action); } - if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { + if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) zfcp_rec_dbf_event_action(143, erp_action); - ZFCP_LOG_NORMAL("error: erp step timed out " - "(action=%d, fsf_req=%p)\n ", - erp_action->action, - erp_action->fsf_req); - } /* * If fsf_req is neither dismissed nor completed * then keep it running asynchronously and don't mess @@ -740,11 +695,10 @@ zfcp_erp_thread_setup(struct zfcp_adapter *adapter) atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); - if (retval < 0) { - ZFCP_LOG_NORMAL("error: creation of erp thread failed for " - "adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - } else { + if (retval < 0) + dev_err(&adapter->ccw_device->dev, + "Creation of ERP thread failed.\n"); + else { wait_event(adapter->erp_thread_wqh, atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status)); @@ -919,15 +873,10 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action) This might happen if an erp_action that used a memory pool element was timed out. */ - if (adapter->erp_total_count == adapter->erp_low_mem_count) { - ZFCP_LOG_NORMAL("error: no mempool elements available, " - "restarting I/O on adapter %s " - "to free mempool\n", - zfcp_get_busid_by_adapter(adapter)); + if (adapter->erp_total_count == adapter->erp_low_mem_count) zfcp_erp_adapter_reopen_internal(adapter, 0, 66, NULL); - } else { - retval = zfcp_erp_strategy_memwait(erp_action); - } + else + retval = zfcp_erp_strategy_memwait(erp_action); goto unlock; case ZFCP_ERP_CONTINUES: /* leave since this action runs asynchronously */ @@ -1039,12 +988,6 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) case ZFCP_ERP_ACTION_REOPEN_UNIT: retval = zfcp_erp_unit_strategy(erp_action); break; - - default: - ZFCP_LOG_NORMAL("bug: unknown erp action requested on " - "adapter %s (action=%d)\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->action); } return retval; @@ -1083,8 +1026,7 @@ zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref) { zfcp_erp_modify_adapter_status(adapter, id, ref, ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); - ZFCP_LOG_NORMAL("adapter erp failed on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n"); } /* @@ -1100,12 +1042,13 @@ zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref) ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) - ZFCP_LOG_NORMAL("port erp failed (adapter %s, " - "port d_id=0x%06x)\n", - zfcp_get_busid_by_port(port), port->d_id); + dev_err(&port->adapter->ccw_device->dev, + "Port ERP failed for WKA port d_id=0x%06x.\n", + port->d_id); else - ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n", - zfcp_get_busid_by_port(port), port->wwpn); + dev_err(&port->adapter->ccw_device->dev, + "Port ERP failed for port wwpn=0x%016Lx.\n", + port->wwpn); } /* @@ -1120,9 +1063,9 @@ zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref) zfcp_erp_modify_unit_status(unit, id, ref, ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); - ZFCP_LOG_NORMAL("unit erp failed on unit 0x%016Lx on port 0x%016Lx " - " on adapter %s\n", unit->fcp_lun, - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); + dev_err(&unit->port->adapter->ccw_device->dev, + "Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n", + unit->fcp_lun, unit->port->wwpn); } /* @@ -1336,13 +1279,10 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit) p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) { - ZFCP_LOG_NORMAL("error: Out of resources. Could not register " - "the FCP-LUN 0x%Lx connected to " - "the port with WWPN 0x%Lx connected to " - "the adapter %s with the SCSI stack.\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); + dev_err(&unit->port->adapter->ccw_device->dev, + "Out of resources. Could not register unit 0x%016Lx " + "on port 0x%016Lx with SCSI stack.\n", + unit->fcp_lun, unit->port->wwpn); return; } @@ -1585,7 +1525,6 @@ static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) { int retval; - struct zfcp_adapter *adapter = erp_action->adapter; retval = zfcp_erp_adapter_strategy_close(erp_action); if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) @@ -1593,12 +1532,8 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) else retval = zfcp_erp_adapter_strategy_open(erp_action); - if (retval == ZFCP_ERP_FAILED) { - ZFCP_LOG_INFO("Waiting to allow the adapter %s " - "to recover itself\n", - zfcp_get_busid_by_adapter(adapter)); + if (retval == ZFCP_ERP_FAILED) ssleep(ZFCP_TYPE2_RECOVERY_TIME); - } return retval; } @@ -1743,19 +1678,13 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) for (retries = ZFCP_EXCHANGE_CONFIG_DATA_RETRIES; retries; retries--) { atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); - ZFCP_LOG_DEBUG("Doing exchange config data\n"); write_lock_irq(&adapter->erp_lock); zfcp_erp_action_to_running(erp_action); write_unlock_irq(&adapter->erp_lock); if (zfcp_fsf_exchange_config_data(erp_action)) { retval = ZFCP_ERP_FAILED; - ZFCP_LOG_INFO("error: initiation of exchange of " - "configuration data failed for " - "adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); break; } - ZFCP_LOG_DEBUG("Xchange underway\n"); /* * Why this works: @@ -1773,19 +1702,13 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) zfcp_rec_dbf_event_thread_lock(6, adapter); down(&adapter->erp_ready_sem); zfcp_rec_dbf_event_thread_lock(7, adapter); - if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { - ZFCP_LOG_INFO("error: exchange of configuration data " - "for adapter %s timed out\n", - zfcp_get_busid_by_adapter(adapter)); + if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) break; - } if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status)) break; - ZFCP_LOG_DEBUG("host connection still initialising... " - "waiting and retrying...\n"); /* sleep a little bit before retry */ ssleep(sleep); sleep *= 2; @@ -1795,12 +1718,8 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) &adapter->status); if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, - &adapter->status)) { - ZFCP_LOG_INFO("error: exchange of configuration data for " - "adapter %s failed\n", - zfcp_get_busid_by_adapter(adapter)); + &adapter->status)) retval = ZFCP_ERP_FAILED; - } return retval; } @@ -1829,16 +1748,8 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) zfcp_rec_dbf_event_thread_lock(8, adapter); down(&adapter->erp_ready_sem); zfcp_rec_dbf_event_thread_lock(9, adapter); - if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { - ZFCP_LOG_INFO("error: exchange port data timed out (adapter " - "%s)\n", zfcp_get_busid_by_adapter(adapter)); + if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) ret = ZFCP_ERP_FAILED; - } - - /* don't treat as error for the sake of compatibility */ - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status)) - ZFCP_LOG_INFO("warning: exchange port data failed (adapter " - "%s\n", zfcp_get_busid_by_adapter(adapter)); return ret; } @@ -1884,8 +1795,6 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN | ZFCP_STATUS_COMMON_OPEN), &port->status)) { - ZFCP_LOG_DEBUG("port 0x%016Lx is open -> trying " - "close physical\n", port->wwpn); retval = zfcp_erp_port_forced_strategy_close(erp_action); } else @@ -1895,8 +1804,6 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: if (atomic_test_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status)) { - ZFCP_LOG_DEBUG("close physical failed for port " - "0x%016Lx\n", port->wwpn); retval = ZFCP_ERP_FAILED; } else retval = ZFCP_ERP_SUCCEEDED; @@ -1930,8 +1837,6 @@ zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) case ZFCP_ERP_STEP_UNINITIALIZED: zfcp_erp_port_strategy_clearstati(port); if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { - ZFCP_LOG_DEBUG("port 0x%016Lx is open -> trying " - "close\n", port->wwpn); retval = zfcp_erp_port_strategy_close(erp_action); goto out; } /* else it's already closed, open it */ @@ -1939,8 +1844,6 @@ zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) case ZFCP_ERP_STEP_PORT_CLOSING: if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { - ZFCP_LOG_DEBUG("close failed for port 0x%016Lx\n", - port->wwpn); retval = ZFCP_ERP_FAILED; goto out; } /* else it's closed now, open it */ @@ -1983,12 +1886,10 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) case ZFCP_ERP_STEP_PORT_CLOSING: if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) { if (port->wwpn != adapter->peer_wwpn) { - ZFCP_LOG_NORMAL("Failed to open port 0x%016Lx " - "on adapter %s.\nPeer WWPN " - "0x%016Lx does not match\n", - port->wwpn, - zfcp_get_busid_by_adapter(adapter), - adapter->peer_wwpn); + dev_err(&adapter->ccw_device->dev, + "Failed to open port 0x%016Lx, " + "Peer WWPN 0x%016Lx does not match.\n", + port->wwpn, adapter->peer_wwpn); zfcp_erp_port_failed(port, 25, NULL); retval = ZFCP_ERP_FAILED; break; @@ -2001,17 +1902,14 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) if (!(adapter->nameserver_port)) { retval = zfcp_nameserver_enqueue(adapter); if (retval != 0) { - ZFCP_LOG_NORMAL("error: nameserver port " - "unavailable for adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, + "Nameserver port unavailable.\n"); retval = ZFCP_ERP_FAILED; break; } } if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->nameserver_port->status)) { - ZFCP_LOG_DEBUG("nameserver port is not open -> open " - "nameserver port\n"); /* nameserver port may live again */ atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &adapter->nameserver_port->status); @@ -2027,57 +1925,37 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) /* else nameserver port is already open, fall through */ case ZFCP_ERP_STEP_NAMESERVER_OPEN: if (!atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, - &adapter->nameserver_port->status)) { - ZFCP_LOG_DEBUG("open failed for nameserver port\n"); + &adapter->nameserver_port->status)) retval = ZFCP_ERP_FAILED; - } else { - ZFCP_LOG_DEBUG("nameserver port is open -> " - "nameserver look-up for port 0x%016Lx\n", - port->wwpn); + else retval = zfcp_erp_port_strategy_open_common_lookup (erp_action); - } break; case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) { if (atomic_test_mask (ZFCP_STATUS_PORT_INVALID_WWPN, &port->status)) { - ZFCP_LOG_DEBUG("nameserver look-up failed " - "for port 0x%016Lx " - "(misconfigured WWPN?)\n", - port->wwpn); zfcp_erp_port_failed(port, 26, NULL); retval = ZFCP_ERP_EXIT; - } else { - ZFCP_LOG_DEBUG("nameserver look-up failed for " - "port 0x%016Lx\n", port->wwpn); + } else retval = ZFCP_ERP_FAILED; - } - } else { - ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> " - "trying open\n", port->wwpn, port->d_id); + } else retval = zfcp_erp_port_strategy_open_port(erp_action); - } break; case ZFCP_ERP_STEP_PORT_OPENING: /* D_ID might have changed during open */ if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN | ZFCP_STATUS_PORT_DID_DID), - &port->status)) { - ZFCP_LOG_DEBUG("port 0x%016Lx is open\n", port->wwpn); + &port->status)) retval = ZFCP_ERP_SUCCEEDED; - } else { - ZFCP_LOG_DEBUG("open failed for port 0x%016Lx\n", - port->wwpn); + else retval = ZFCP_ERP_FAILED; - } break; default: - ZFCP_LOG_NORMAL("bug: unknown erp step 0x%08x\n", - erp_action->step); + /* unknown erp step */ retval = ZFCP_ERP_FAILED; } @@ -2095,27 +1973,20 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action) case ZFCP_ERP_STEP_UNINITIALIZED: case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: case ZFCP_ERP_STEP_PORT_CLOSING: - ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> trying open\n", - port->wwpn, port->d_id); retval = zfcp_erp_port_strategy_open_port(erp_action); break; case ZFCP_ERP_STEP_PORT_OPENING: - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { - ZFCP_LOG_DEBUG("WKA port is open\n"); + if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) retval = ZFCP_ERP_SUCCEEDED; - } else { - ZFCP_LOG_DEBUG("open failed for WKA port\n"); + else retval = ZFCP_ERP_FAILED; - } /* this is needed anyway (dont care for retval of wakeup) */ - ZFCP_LOG_DEBUG("continue other open port operations\n"); zfcp_erp_port_strategy_open_nameserver_wakeup(erp_action); break; default: - ZFCP_LOG_NORMAL("bug: unknown erp step 0x%08x\n", - erp_action->step); + /* unknown erp step */ retval = ZFCP_ERP_FAILED; } @@ -2313,39 +2184,26 @@ zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) case ZFCP_ERP_STEP_UNINITIALIZED: zfcp_erp_unit_strategy_clearstati(unit); if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { - ZFCP_LOG_DEBUG("unit 0x%016Lx is open -> " - "trying close\n", unit->fcp_lun); retval = zfcp_erp_unit_strategy_close(erp_action); break; } /* else it's already closed, fall through */ case ZFCP_ERP_STEP_UNIT_CLOSING: - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { - ZFCP_LOG_DEBUG("close failed for unit 0x%016Lx\n", - unit->fcp_lun); + if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) retval = ZFCP_ERP_FAILED; - } else { + else if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) retval = ZFCP_ERP_EXIT; - else { - ZFCP_LOG_DEBUG("unit 0x%016Lx is not open -> " - "trying open\n", unit->fcp_lun); + else retval = zfcp_erp_unit_strategy_open(erp_action); - } - } break; case ZFCP_ERP_STEP_UNIT_OPENING: - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { - ZFCP_LOG_DEBUG("unit 0x%016Lx is open\n", - unit->fcp_lun); + if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) retval = ZFCP_ERP_SUCCEEDED; - } else { - ZFCP_LOG_DEBUG("open failed for unit 0x%016Lx\n", - unit->fcp_lun); + else retval = ZFCP_ERP_FAILED; - } break; } @@ -2493,16 +2351,8 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, - &port->status)) { - if (port->erp_action.action != - ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) { - ZFCP_LOG_INFO("dropped erp action %i (port " - "0x%016Lx, action in use: %i)\n", - want, port->wwpn, - port->erp_action.action); - } + &port->status)) goto out; - } if (!atomic_test_mask (ZFCP_STATUS_COMMON_RUNNING, &adapter->status) || atomic_test_mask @@ -2522,19 +2372,10 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, break; default: - ZFCP_LOG_NORMAL("bug: unknown erp action requested " - "on adapter %s (action=%d)\n", - zfcp_get_busid_by_adapter(adapter), want); + /* unknown erp action */ goto out; } - /* check whether we need something stronger first */ - if (need) { - ZFCP_LOG_DEBUG("stronger erp action %d needed before " - "erp action %d on adapter %s\n", - need, want, zfcp_get_busid_by_adapter(adapter)); - } - /* mark adapter to have some error recovery pending */ atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); @@ -2672,10 +2513,9 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, port->rport = fc_remote_port_add(adapter->scsi_host, 0, &ids); if (!port->rport) - ZFCP_LOG_NORMAL("failed registration of rport" - "(adapter %s, wwpn=0x%016Lx)\n", - zfcp_get_busid_by_port(port), - port->wwpn); + dev_err(&adapter->ccw_device->dev, + "Failed registration of rport " + "0x%016Lx.\n", port->wwpn); else { scsi_target_unblock(&port->rport->dev); port->rport->maxframe_size = port->maxframe_size; @@ -2803,7 +2643,6 @@ void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id, void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, void *ref) { - struct zfcp_adapter *adapter = port->adapter; struct zfcp_unit *unit; if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, @@ -2816,34 +2655,16 @@ void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, void *ref) return; } - ZFCP_LOG_NORMAL("reopen of port 0x%016Lx on adapter %s " - "(due to ACT update)\n", - port->wwpn, zfcp_get_busid_by_adapter(adapter)); - if (zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref)) - ZFCP_LOG_NORMAL("failed reopen of port" - "(adapter %s, wwpn=0x%016Lx)\n", - zfcp_get_busid_by_adapter(adapter), port->wwpn); + zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); } void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id, void *ref) { - struct zfcp_adapter *adapter = unit->port->adapter; - if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &unit->status) && !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, &unit->status)) return; - ZFCP_LOG_NORMAL("reopen of unit 0x%016Lx on port 0x%016Lx " - " on adapter %s (due to ACT update)\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_adapter(adapter)); - if (zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref)) - ZFCP_LOG_NORMAL("failed reopen of unit (adapter %s, " - "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", - zfcp_get_busid_by_adapter(adapter), - unit->port->wwpn, unit->fcp_lun); + zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); } - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 6ffe2068ba8a..9aa412bd6637 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -1,22 +1,9 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * External function declarations. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #ifndef ZFCP_EXT_H @@ -27,7 +14,6 @@ extern struct zfcp_data zfcp_data; /******************************** SYSFS *************************************/ -extern struct attribute_group *zfcp_driver_attr_groups[]; extern int zfcp_sysfs_adapter_create_files(struct device *); extern void zfcp_sysfs_adapter_remove_files(struct device *); extern int zfcp_sysfs_port_create_files(struct device *, u32); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index cc48a6462e6c..01ed5fb46c44 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1,22 +1,9 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Implementation of FSF commands. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #include "zfcp_ext.h" @@ -71,12 +58,58 @@ static const char zfcp_act_subtable_type[5][8] = { "unknown", "OS", "WWPN", "DID", "LUN" }; +static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) +{ + u16 subtable = (table & 0xffff0000) >> 16; + u16 rule = table & 0xffff; + + if (subtable > 0 && + subtable < ARRAY_SIZE(zfcp_act_subtable_type)) { + dev_warn(&adapter->ccw_device->dev, + "Access denied in subtable %s, rule %d.\n", + zfcp_act_subtable_type[subtable], rule); + } +} + +static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req, + struct zfcp_port *port) +{ + struct fsf_qtcb_header *header = &req->qtcb->header; + dev_warn(&req->adapter->ccw_device->dev, + "Access denied, cannot send command to port 0x%016Lx.\n", + port->wwpn); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); + zfcp_erp_port_access_denied(port, 55, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; +} + +static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req, + struct zfcp_unit *unit) +{ + struct fsf_qtcb_header *header = &req->qtcb->header; + dev_warn(&req->adapter->ccw_device->dev, + "Access denied for unit 0x%016Lx on port 0x%016Lx.\n", + unit->fcp_lun, unit->port->wwpn); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); + zfcp_erp_unit_access_denied(unit, 59, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; +} + +static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) +{ + dev_err(&req->adapter->ccw_device->dev, + "Required FC class not supported by adapter, " + "shutting down adapter.\n"); + zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; +} + /****************************************************************/ /*************** FSF related Functions *************************/ /****************************************************************/ -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF - /* * function: zfcp_fsf_req_alloc * @@ -200,7 +233,6 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) int cleanup; if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { - ZFCP_LOG_DEBUG("Status read response received\n"); /* * Note: all cleanup handling is done in the callchain of * the function call-chain below. @@ -225,7 +257,6 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) /* cleanup request if requested by initiator */ if (likely(cleanup)) { - ZFCP_LOG_TRACE("removing FSF request %p\n", fsf_req); /* * lock must not be held here since it will be * grabed by the called routine, too @@ -233,7 +264,6 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) zfcp_fsf_req_free(fsf_req); } else { /* notify initiator waiting for the requests completion */ - ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req); /* * FIXME: Race! We must not access fsf_req here as it might have been * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED @@ -276,8 +306,6 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) zfcp_hba_dbf_event_fsf_response(fsf_req); if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { - ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n", - (unsigned long) fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ goto skip_protstatus; @@ -291,34 +319,26 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) break; case FSF_PROT_QTCB_VERSION_ERROR: - ZFCP_LOG_NORMAL("error: The adapter %s contains " - "microcode of version 0x%x, the device driver " - "only supports 0x%x. Aborting.\n", - zfcp_get_busid_by_adapter(adapter), - prot_status_qual->version_error.fsf_version, - ZFCP_QTCB_VERSION); + dev_err(&adapter->ccw_device->dev, + "The QTCB version requested by zfcp (0x%x) is not " + "supported by the FCP adapter (lowest supported 0x%x, " + "highest supported 0x%x).\n", + ZFCP_QTCB_VERSION, prot_status_qual->word[0], + prot_status_qual->word[1]); zfcp_erp_adapter_shutdown(adapter, 0, 117, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PROT_SEQ_NUMB_ERROR: - ZFCP_LOG_NORMAL("bug: Sequence number mismatch between " - "driver (0x%x) and adapter %s (0x%x). " - "Restarting all operations on this adapter.\n", - qtcb->prefix.req_seq_no, - zfcp_get_busid_by_adapter(adapter), - prot_status_qual->sequence_error.exp_req_seq_no); zfcp_erp_adapter_reopen(adapter, 0, 98, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PROT_UNSUPP_QTCB_TYPE: - ZFCP_LOG_NORMAL("error: Packet header type used by the " - "device driver is incompatible with " - "that used on adapter %s. " - "Stopping all operations on this adapter.\n", - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, + "Packet header type used by the device driver is " + "incompatible with that used on the adapter.\n"); zfcp_erp_adapter_shutdown(adapter, 0, 118, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -330,12 +350,9 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) break; case FSF_PROT_DUPLICATE_REQUEST_ID: - ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx " - "to the adapter %s is ambiguous. " - "Stopping all operations on this adapter.\n", - *(unsigned long long*) - (&qtcb->bottom.support.req_handle), - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, + "The request identifier 0x%Lx is ambiguous.\n", + (unsigned long long)qtcb->bottom.support.req_handle); zfcp_erp_adapter_shutdown(adapter, 0, 78, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -349,10 +366,6 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) break; case FSF_PROT_REEST_QUEUE: - ZFCP_LOG_NORMAL("The local link to adapter with " - "%s was re-plugged. " - "Re-starting operations on this adapter.\n", - zfcp_get_busid_by_adapter(adapter)); /* All ports should be marked as ready to run again */ zfcp_erp_modify_adapter_status(adapter, 28, NULL, ZFCP_STATUS_COMMON_RUNNING, @@ -365,24 +378,17 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) break; case FSF_PROT_ERROR_STATE: - ZFCP_LOG_NORMAL("error: The adapter %s " - "has entered the error state. " - "Restarting all operations on this " - "adapter.\n", - zfcp_get_busid_by_adapter(adapter)); zfcp_erp_adapter_reopen(adapter, 0, 100, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: - ZFCP_LOG_NORMAL("bug: Transfer protocol status information " - "provided by the adapter %s " - "is not compatible with the device driver. " - "Stopping all operations on this adapter. " - "(debug info 0x%x).\n", - zfcp_get_busid_by_adapter(adapter), - qtcb->prefix.prot_status); + dev_err(&adapter->ccw_device->dev, + "Transfer protocol status information" + "provided by the adapter (0x%x) " + "is not compatible with the device driver.\n", + qtcb->prefix.prot_status); zfcp_erp_adapter_shutdown(adapter, 0, 119, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; } @@ -416,21 +422,14 @@ zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req) /* evaluate FSF Status */ switch (fsf_req->qtcb->header.fsf_status) { case FSF_UNKNOWN_COMMAND: - ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " - "not known by the adapter %s " - "Stopping all operations on this adapter. " - "(debug info 0x%x).\n", - zfcp_get_busid_by_adapter(fsf_req->adapter), - fsf_req->qtcb->header.fsf_command); + dev_err(&fsf_req->adapter->ccw_device->dev, + "Command issued by the device driver (0x%x) is " + "not known by the adapter.\n", + fsf_req->qtcb->header.fsf_command); zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 120, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_FCP_RSP_AVAILABLE: - ZFCP_LOG_DEBUG("FCP Sense data will be presented to the " - "SCSI stack.\n"); - break; - case FSF_ADAPTER_STATUS_AVAILABLE: zfcp_fsf_fsfstatus_qual_eval(fsf_req); break; @@ -472,17 +471,13 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_NO_RECOM: - ZFCP_LOG_NORMAL("bug: No recommendation could be given for a " - "problem on the adapter %s " - "Stopping all operations on this adapter. ", - zfcp_get_busid_by_adapter(fsf_req->adapter)); + dev_err(&fsf_req->adapter->ccw_device->dev, + "No recommendation could be given for a " + "problem on the adapter.\n"); zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 121, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_ULP_PROGRAMMING_ERROR: - ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer " - "(adapter %s)\n", - zfcp_get_busid_by_adapter(fsf_req->adapter)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: @@ -491,11 +486,6 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) /* dealt with in the respective functions */ break; default: - ZFCP_LOG_NORMAL("bug: Additional status info could " - "not be interpreted properly.\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, - (char *) &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } @@ -523,84 +513,67 @@ zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *fsf_req, u8 id, switch (link_down->error_code) { case FSF_PSQ_LINK_NO_LIGHT: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(no light detected)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "no light detected.\n"); break; case FSF_PSQ_LINK_WRAP_PLUG: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(wrap plug detected)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "wrap plug detected.\n"); break; case FSF_PSQ_LINK_NO_FCP: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(adjacent node on link does not support FCP)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "adjacent node on link does not support FCP.\n"); break; case FSF_PSQ_LINK_FIRMWARE_UPDATE: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(firmware update in progress)\n", - zfcp_get_busid_by_adapter(adapter)); - break; + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "firmware update in progress.\n"); + break; case FSF_PSQ_LINK_INVALID_WWPN: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(duplicate or invalid WWPN detected)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "duplicate or invalid WWPN detected.\n"); break; case FSF_PSQ_LINK_NO_NPIV_SUPPORT: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(no support for NPIV by Fabric)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "no support for NPIV by Fabric.\n"); break; case FSF_PSQ_LINK_NO_FCP_RESOURCES: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(out of resource in FCP daughtercard)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "out of resource in FCP daughtercard.\n"); break; case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(out of resource in Fabric)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "out of resource in Fabric.\n"); break; case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(unable to Fabric login)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link is down: " + "unable to login to Fabric.\n"); break; case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: - ZFCP_LOG_NORMAL("WWPN assignment file corrupted on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "WWPN assignment file corrupted on adapter.\n"); break; case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: - ZFCP_LOG_NORMAL("Mode table corrupted on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "Mode table corrupted on adapter.\n"); break; case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: - ZFCP_LOG_NORMAL("No WWPN for assignment table on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "No WWPN for assignment table on adapter.\n"); break; default: - ZFCP_LOG_NORMAL("The local link to adapter %s is down " - "(warning: unknown reason code %d)\n", - zfcp_get_busid_by_adapter(adapter), - link_down->error_code); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The local link to adapter is down.\n"); } - if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) - ZFCP_LOG_DEBUG("Debug information to link down: " - "primary_status=0x%02x " - "ioerr_code=0x%02x " - "action_code=0x%02x " - "reason_code=0x%02x " - "explanation_code=0x%02x " - "vendor_specific_code=0x%02x\n", - link_down->primary_status, - link_down->ioerr_code, - link_down->action_code, - link_down->reason_code, - link_down->explanation_code, - link_down->vendor_specific_code); - out: zfcp_erp_adapter_failed(adapter, id, fsf_req); } @@ -616,7 +589,6 @@ static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) { struct zfcp_erp_action *erp_action = fsf_req->erp_action; - struct zfcp_adapter *adapter = fsf_req->adapter; int retval = 0; @@ -673,20 +645,6 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) case FSF_QTCB_UPLOAD_CONTROL_FILE: zfcp_fsf_control_file_handler(fsf_req); break; - - default: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " - "not supported by the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - if (fsf_req->fsf_command != fsf_req->qtcb->header.fsf_command) - ZFCP_LOG_NORMAL - ("bug: Command issued by the device driver differs " - "from the command returned by the adapter %s " - "(debug info 0x%x, 0x%x).\n", - zfcp_get_busid_by_adapter(adapter), - fsf_req->fsf_command, - fsf_req->qtcb->header.fsf_command); } if (!erp_action) @@ -718,12 +676,8 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) req_flags | ZFCP_REQ_NO_QTCB, adapter->pool.fsf_req_status_read, &lock_flags, &fsf_req); - if (retval < 0) { - ZFCP_LOG_INFO("error: Could not create unsolicited status " - "buffer for adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); + if (retval < 0) goto failed_req_create; - } sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; @@ -744,14 +698,9 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) sbale->length = sizeof(struct fsf_status_read_buffer); retval = zfcp_fsf_req_send(fsf_req); - if (retval) { - ZFCP_LOG_DEBUG("error: Could not set-up unsolicited status " - "environment.\n"); + if (retval) goto failed_req_send; - } - ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n", - zfcp_get_busid_by_adapter(adapter)); goto out; failed_req_send: @@ -783,14 +732,8 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) break; read_unlock_irqrestore(&zfcp_data.config_lock, flags); - if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) { - ZFCP_LOG_NORMAL("bug: Reopen port indication received for " - "nonexisting port with d_id 0x%06x on " - "adapter %s. Ignored.\n", - status_buffer->d_id & ZFCP_DID_MASK, - zfcp_get_busid_by_adapter(adapter)); + if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) goto out; - } switch (status_buffer->status_subtype) { @@ -801,20 +744,48 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) case FSF_STATUS_READ_SUB_ERROR_PORT: zfcp_erp_port_shutdown(port, 0, 122, fsf_req); break; - - default: - ZFCP_LOG_NORMAL("bug: Undefined status subtype received " - "for a reopen indication on port with " - "d_id 0x%06x on the adapter %s. " - "Ignored. (debug info 0x%x)\n", - status_buffer->d_id, - zfcp_get_busid_by_adapter(adapter), - status_buffer->status_subtype); } out: return 0; } +static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req) +{ + struct zfcp_adapter *adapter = req->adapter; + struct fsf_status_read_buffer *buf = + (struct fsf_status_read_buffer *) req->data; + struct fsf_bit_error_payload *err = + (struct fsf_bit_error_payload *) buf->payload; + dev_warn(&adapter->ccw_device->dev, + "Warning: bit error threshold data " + "received for the adapter: " + "link failures = %i, loss of sync errors = %i, " + "loss of signal errors = %i, " + "primitive sequence errors = %i, " + "invalid transmission word errors = %i, " + "CRC errors = %i).\n", + err->link_failure_error_count, + err->loss_of_sync_error_count, + err->loss_of_signal_error_count, + err->primitive_sequence_error_count, + err->invalid_transmission_word_error_count, + err->crc_error_count); + dev_warn(&adapter->ccw_device->dev, + "Additional bit error threshold data of the adapter: " + "primitive sequence event time-outs = %i, " + "elastic buffer overrun errors = %i, " + "advertised receive buffer-to-buffer credit = %i, " + "current receice buffer-to-buffer credit = %i, " + "advertised transmit buffer-to-buffer credit = %i, " + "current transmit buffer-to-buffer credit = %i).\n", + err->primitive_sequence_event_timeout_count, + err->elastic_buffer_overrun_error_count, + err->advertised_receive_b2b_credit, + err->current_receive_b2b_credit, + err->advertised_transmit_b2b_credit, + err->current_transmit_b2b_credit); +} + /* * function: zfcp_fsf_status_read_handler * @@ -829,7 +800,6 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_status_read_buffer *status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; - struct fsf_bit_error_payload *fsf_bit_error; if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer); @@ -851,79 +821,45 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_STATUS_READ_SENSE_DATA_AVAIL: - ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n", - zfcp_get_busid_by_adapter(adapter)); break; case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: - fsf_bit_error = (struct fsf_bit_error_payload *) - status_buffer->payload; - ZFCP_LOG_NORMAL("Warning: bit error threshold data " - "received (adapter %s, " - "link failures = %i, loss of sync errors = %i, " - "loss of signal errors = %i, " - "primitive sequence errors = %i, " - "invalid transmission word errors = %i, " - "CRC errors = %i)\n", - zfcp_get_busid_by_adapter(adapter), - fsf_bit_error->link_failure_error_count, - fsf_bit_error->loss_of_sync_error_count, - fsf_bit_error->loss_of_signal_error_count, - fsf_bit_error->primitive_sequence_error_count, - fsf_bit_error->invalid_transmission_word_error_count, - fsf_bit_error->crc_error_count); - ZFCP_LOG_INFO("Additional bit error threshold data " - "(adapter %s, " - "primitive sequence event time-outs = %i, " - "elastic buffer overrun errors = %i, " - "advertised receive buffer-to-buffer credit = %i, " - "current receice buffer-to-buffer credit = %i, " - "advertised transmit buffer-to-buffer credit = %i, " - "current transmit buffer-to-buffer credit = %i)\n", - zfcp_get_busid_by_adapter(adapter), - fsf_bit_error->primitive_sequence_event_timeout_count, - fsf_bit_error->elastic_buffer_overrun_error_count, - fsf_bit_error->advertised_receive_b2b_credit, - fsf_bit_error->current_receive_b2b_credit, - fsf_bit_error->advertised_transmit_b2b_credit, - fsf_bit_error->current_transmit_b2b_credit); + zfcp_fsf_bit_error_threshold(fsf_req); break; case FSF_STATUS_READ_LINK_DOWN: switch (status_buffer->status_subtype) { case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: - ZFCP_LOG_INFO("Physical link to adapter %s is down\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&adapter->ccw_device->dev, + "Physical link is down.\n"); zfcp_fsf_link_down_info_eval(fsf_req, 38, (struct fsf_link_down_info *) &status_buffer->payload); break; case FSF_STATUS_READ_SUB_FDISC_FAILED: - ZFCP_LOG_INFO("Local link to adapter %s is down " - "due to failed FDISC login\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&adapter->ccw_device->dev, + "Local link is down " + "due to failed FDISC login.\n"); zfcp_fsf_link_down_info_eval(fsf_req, 39, (struct fsf_link_down_info *) &status_buffer->payload); break; case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: - ZFCP_LOG_INFO("Local link to adapter %s is down " - "due to firmware update on adapter\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&adapter->ccw_device->dev, + "Local link is down " + "due to firmware update on adapter.\n"); zfcp_fsf_link_down_info_eval(fsf_req, 40, NULL); break; default: - ZFCP_LOG_INFO("Local link to adapter %s is down " - "due to unknown reason\n", - zfcp_get_busid_by_adapter(adapter)); + dev_warn(&adapter->ccw_device->dev, + "Local link is down.\n"); zfcp_fsf_link_down_info_eval(fsf_req, 41, NULL); }; break; case FSF_STATUS_READ_LINK_UP: - ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. " - "Restarting operations on this adapter\n", - zfcp_get_busid_by_adapter(adapter)); + dev_info(&adapter->ccw_device->dev, + "Local link was replugged.\n"); /* All ports should be marked as ready to run again */ zfcp_erp_modify_adapter_status(adapter, 30, NULL, ZFCP_STATUS_COMMON_RUNNING, @@ -935,81 +871,18 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_STATUS_READ_NOTIFICATION_LOST: - ZFCP_LOG_NORMAL("Unsolicited status notification(s) lost: " - "adapter %s%s%s%s%s%s%s%s%s\n", - zfcp_get_busid_by_adapter(adapter), - (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_INCOMING_ELS) ? - ", incoming ELS" : "", - (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_SENSE_DATA) ? - ", sense data" : "", - (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_LINK_STATUS) ? - ", link status change" : "", - (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_PORT_CLOSED) ? - ", port close" : "", - (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD) ? - ", bit error exception" : "", - (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_ACT_UPDATED) ? - ", ACT update" : "", - (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_ACT_HARDENED) ? - ", ACT hardening" : "", - (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT) ? - ", adapter feature change" : ""); - if (status_buffer->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) zfcp_erp_adapter_access_changed(adapter, 135, fsf_req); break; case FSF_STATUS_READ_CFDC_UPDATED: - ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); zfcp_erp_adapter_access_changed(adapter, 136, fsf_req); break; - case FSF_STATUS_READ_CFDC_HARDENED: - switch (status_buffer->status_subtype) { - case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE: - ZFCP_LOG_NORMAL("CFDC of adapter %s saved on SE\n", - zfcp_get_busid_by_adapter(adapter)); - break; - case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2: - ZFCP_LOG_NORMAL("CFDC of adapter %s has been copied " - "to the secondary SE\n", - zfcp_get_busid_by_adapter(adapter)); - break; - default: - ZFCP_LOG_NORMAL("CFDC of adapter %s has been hardened\n", - zfcp_get_busid_by_adapter(adapter)); - } - break; - case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: - ZFCP_LOG_INFO("List of supported features on adapter %s has " - "been changed from 0x%08X to 0x%08X\n", - zfcp_get_busid_by_adapter(adapter), - *(u32*) (status_buffer->payload + 4), - *(u32*) (status_buffer->payload)); adapter->adapter_features = *(u32*) status_buffer->payload; break; - - default: - ZFCP_LOG_NORMAL("warning: An unsolicited status packet of unknown " - "type was received (debug info 0x%x)\n", - status_buffer->status_type); - ZFCP_LOG_DEBUG("Dump of status_read_buffer %p:\n", - status_buffer); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) status_buffer, - sizeof (struct fsf_status_read_buffer)); - break; } mempool_free(status_buffer, adapter->pool.data_status_read); zfcp_fsf_req_free(fsf_req); @@ -1060,15 +933,8 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, req_flags, adapter->pool.fsf_req_abort, &lock_flags, &fsf_req); - if (retval < 0) { - ZFCP_LOG_INFO("error: Failed to create an abort command " - "request for lun 0x%016Lx on port 0x%016Lx " - "on adapter %s.\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_adapter(adapter)); + if (retval < 0) goto out; - } if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) @@ -1134,17 +1000,6 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) * fine. */ } else { - ZFCP_LOG_INFO("Temporary port identifier 0x%x for " - "port 0x%016Lx on adapter %s invalid. " - "This may happen occasionally.\n", - unit->port->handle, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - ZFCP_LOG_INFO("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, - (char *) &new_fsf_req->qtcb->header. - fsf_status_qual, - sizeof (union fsf_status_qual)); /* Let's hope this sorts out the mess */ zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104, new_fsf_req); @@ -1160,20 +1015,6 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) * This is fine. */ } else { - ZFCP_LOG_INFO - ("Warning: Temporary LUN identifier 0x%x of LUN " - "0x%016Lx on port 0x%016Lx on adapter %s is " - "invalid. This may happen in rare cases. " - "Trying to re-establish link.\n", - unit->handle, - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - ZFCP_LOG_DEBUG("Status qualifier data:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &new_fsf_req->qtcb->header. - fsf_status_qual, - sizeof (union fsf_status_qual)); /* Let's hope this sorts out the mess */ zfcp_erp_port_reopen(unit->port, 0, 105, new_fsf_req); new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1186,20 +1027,12 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) break; case FSF_PORT_BOXED: - ZFCP_LOG_INFO("Remote port 0x%016Lx on adapter %s needs to " - "be reopened\n", unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); zfcp_erp_port_boxed(unit->port, 47, new_fsf_req); new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; break; case FSF_LUN_BOXED: - ZFCP_LOG_INFO( - "unit 0x%016Lx on port 0x%016Lx on adapter %s needs " - "to be reopened\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); zfcp_erp_unit_boxed(unit, 48, new_fsf_req); new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; @@ -1215,11 +1048,6 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) /* SCSI stack will escalate */ new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - default: - ZFCP_LOG_NORMAL - ("bug: Wrong status qualifier 0x%x arrived.\n", - new_fsf_req->qtcb->header.fsf_status_qual.word[0]); - break; } break; @@ -1227,12 +1055,6 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) retval = 0; new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; break; - - default: - ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " - "(debug info 0x%x)\n", - new_fsf_req->qtcb->header.fsf_status); - break; } skip_fsfstatus: return retval; @@ -1287,12 +1109,8 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, pool, &lock_flags, &fsf_req); - if (ret < 0) { - ZFCP_LOG_INFO("error: Could not create CT request (FC-GS) for " - "adapter: %s\n", - zfcp_get_busid_by_adapter(adapter)); + if (ret < 0) goto failed_req; - } sbale = zfcp_qdio_sbale_req(fsf_req); if (zfcp_use_one_sbal(ct->req, ct->req_count, @@ -1313,9 +1131,6 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, ct->req, ZFCP_MAX_SBALS_PER_CT_REQ); if (bytes <= 0) { - ZFCP_LOG_INFO("error: creation of CT request failed " - "on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); if (bytes == 0) ret = -ENOMEM; else @@ -1330,9 +1145,6 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, ct->resp, ZFCP_MAX_SBALS_PER_CT_REQ); if (bytes <= 0) { - ZFCP_LOG_INFO("error: creation of CT request failed " - "on adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); if (bytes == 0) ret = -ENOMEM; else @@ -1343,10 +1155,6 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, fsf_req->qtcb->bottom.support.resp_buf_length = bytes; } else { /* reject send generic request */ - ZFCP_LOG_INFO( - "error: microcode does not support chained SBALs," - "CT request too big (adapter %s)\n", - zfcp_get_busid_by_adapter(adapter)); ret = -EOPNOTSUPP; goto failed_send; } @@ -1368,15 +1176,9 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); ret = zfcp_fsf_req_send(fsf_req); - if (ret) { - ZFCP_LOG_DEBUG("error: initiation of CT request failed " - "(adapter %s, port 0x%016Lx)\n", - zfcp_get_busid_by_adapter(adapter), port->wwpn); + if (ret) goto failed_send; - } - ZFCP_LOG_DEBUG("CT request initiated (adapter %s, port 0x%016Lx)\n", - zfcp_get_busid_by_adapter(adapter), port->wwpn); goto out; failed_send: @@ -1408,7 +1210,6 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) struct fsf_qtcb_header *header; struct fsf_qtcb_bottom_support *bottom; int retval = -EINVAL; - u16 subtable, rule, counter; adapter = fsf_req->adapter; send_ct = (struct zfcp_send_ct *) fsf_req->data; @@ -1428,13 +1229,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: - ZFCP_LOG_INFO("error: adapter %s does not support fc " - "class %d.\n", - zfcp_get_busid_by_port(port), - ZFCP_FC_SERVICE_CLASS_DEFAULT); - /* stop operation for this adapter */ - zfcp_erp_adapter_shutdown(adapter, 0, 123, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_class_not_supp(fsf_req); break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1448,63 +1243,23 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) /* ERP strategy will escalate */ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - default: - ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x " - "arrived.\n", - header->fsf_status_qual.word[0]); - break; } break; case FSF_ACCESS_DENIED: - ZFCP_LOG_NORMAL("access denied, cannot send generic service " - "command (adapter %s, port d_id=0x%06x)\n", - zfcp_get_busid_by_port(port), port->d_id); - for (counter = 0; counter < 2; counter++) { - subtable = header->fsf_status_qual.halfword[counter * 2]; - rule = header->fsf_status_qual.halfword[counter * 2 + 1]; - switch (subtable) { - case FSF_SQ_CFDC_SUBTABLE_OS: - case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: - case FSF_SQ_CFDC_SUBTABLE_PORT_DID: - case FSF_SQ_CFDC_SUBTABLE_LUN: - ZFCP_LOG_INFO("Access denied (%s rule %d)\n", - zfcp_act_subtable_type[subtable], rule); - break; - } - } - zfcp_erp_port_access_denied(port, 55, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_access_denied_port(fsf_req, port); break; case FSF_GENERIC_COMMAND_REJECTED: - ZFCP_LOG_INFO("generic service command rejected " - "(adapter %s, port d_id=0x%06x)\n", - zfcp_get_busid_by_port(port), port->d_id); - ZFCP_LOG_INFO("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_HANDLE_NOT_VALID: - ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port " - "0x%016Lx on adapter %s invalid. This may " - "happen occasionally.\n", port->handle, - port->wwpn, zfcp_get_busid_by_port(port)); - ZFCP_LOG_INFO("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_adapter_reopen(adapter, 0, 106, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - ZFCP_LOG_INFO("port needs to be reopened " - "(adapter %s, port d_id=0x%06x)\n", - zfcp_get_busid_by_port(port), port->d_id); zfcp_erp_port_boxed(port, 49, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; @@ -1513,37 +1268,13 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) /* following states should never occure, all cases avoided in zfcp_fsf_send_ct - but who knows ... */ case FSF_PAYLOAD_SIZE_MISMATCH: - ZFCP_LOG_INFO("payload size mismatch (adapter: %s, " - "req_buf_length=%d, resp_buf_length=%d)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->req_buf_length, bottom->resp_buf_length); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_REQUEST_SIZE_TOO_LARGE: - ZFCP_LOG_INFO("request size too large (adapter: %s, " - "req_buf_length=%d)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->req_buf_length); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_RESPONSE_SIZE_TOO_LARGE: - ZFCP_LOG_INFO("response size too large (adapter: %s, " - "resp_buf_length=%d)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->resp_buf_length); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_SBAL_MISMATCH: - ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " - "resp_buf_length=%d)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->req_buf_length, bottom->resp_buf_length); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: - ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " - "(debug info 0x%x)\n", header->fsf_status); break; } @@ -1578,12 +1309,8 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, ZFCP_REQ_AUTO_CLEANUP, NULL, &lock_flags, &fsf_req); - if (ret < 0) { - ZFCP_LOG_INFO("error: creation of ELS request failed " - "(adapter %s, port d_id: 0x%06x)\n", - zfcp_get_busid_by_adapter(adapter), d_id); + if (ret < 0) goto failed_req; - } if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &els->port->status))) { @@ -1610,9 +1337,6 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) els->req, ZFCP_MAX_SBALS_PER_ELS_REQ); if (bytes <= 0) { - ZFCP_LOG_INFO("error: creation of ELS request failed " - "(adapter %s, port d_id: 0x%06x)\n", - zfcp_get_busid_by_adapter(adapter), d_id); if (bytes == 0) { ret = -ENOMEM; } else { @@ -1627,9 +1351,6 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) els->resp, ZFCP_MAX_SBALS_PER_ELS_REQ); if (bytes <= 0) { - ZFCP_LOG_INFO("error: creation of ELS request failed " - "(adapter %s, port d_id: 0x%06x)\n", - zfcp_get_busid_by_adapter(adapter), d_id); if (bytes == 0) { ret = -ENOMEM; } else { @@ -1640,10 +1361,6 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) fsf_req->qtcb->bottom.support.resp_buf_length = bytes; } else { /* reject request */ - ZFCP_LOG_INFO("error: microcode does not support chained SBALs" - ", ELS request too big (adapter %s, " - "port d_id: 0x%06x)\n", - zfcp_get_busid_by_adapter(adapter), d_id); ret = -EOPNOTSUPP; goto failed_send; } @@ -1661,15 +1378,9 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); ret = zfcp_fsf_req_send(fsf_req); - if (ret) { - ZFCP_LOG_DEBUG("error: initiation of ELS request failed " - "(adapter %s, port d_id: 0x%06x)\n", - zfcp_get_busid_by_adapter(adapter), d_id); + if (ret) goto failed_send; - } - ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: " - "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto out; port_blocked: @@ -1701,7 +1412,6 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) struct fsf_qtcb_bottom_support *bottom; struct zfcp_send_els *send_els; int retval = -EINVAL; - u16 subtable, rule, counter; send_els = (struct zfcp_send_els *) fsf_req->data; adapter = send_els->adapter; @@ -1721,13 +1431,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: - ZFCP_LOG_INFO("error: adapter %s does not support fc " - "class %d.\n", - zfcp_get_busid_by_adapter(adapter), - ZFCP_FC_SERVICE_CLASS_DEFAULT); - /* stop operation for this adapter */ - zfcp_erp_adapter_shutdown(adapter, 0, 124, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_class_not_supp(fsf_req); break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1743,91 +1447,25 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) case FSF_SQ_RETRY_IF_POSSIBLE: fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - default: - ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n", - header->fsf_status_qual.word[0]); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, - (char*)header->fsf_status_qual.word, 16); } break; case FSF_ELS_COMMAND_REJECTED: - ZFCP_LOG_INFO("ELS has been rejected because command filter " - "prohibited sending " - "(adapter: %s, port d_id: 0x%06x)\n", - zfcp_get_busid_by_adapter(adapter), d_id); - - break; - case FSF_PAYLOAD_SIZE_MISMATCH: - ZFCP_LOG_INFO( - "ELS request size and ELS response size must be either " - "both 0, or both greater than 0 " - "(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->req_buf_length, - bottom->resp_buf_length); - break; - case FSF_REQUEST_SIZE_TOO_LARGE: - ZFCP_LOG_INFO( - "Length of the ELS request buffer, " - "specified in QTCB bottom, " - "exceeds the size of the buffers " - "that have been allocated for ELS request data " - "(adapter: %s, req_buf_length=%d)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->req_buf_length); - break; - case FSF_RESPONSE_SIZE_TOO_LARGE: - ZFCP_LOG_INFO( - "Length of the ELS response buffer, " - "specified in QTCB bottom, " - "exceeds the size of the buffers " - "that have been allocated for ELS response data " - "(adapter: %s, resp_buf_length=%d)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->resp_buf_length); break; case FSF_SBAL_MISMATCH: /* should never occure, avoided in zfcp_fsf_send_els */ - ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " - "resp_buf_length=%d)\n", - zfcp_get_busid_by_adapter(adapter), - bottom->req_buf_length, bottom->resp_buf_length); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ACCESS_DENIED: - ZFCP_LOG_NORMAL("access denied, cannot send ELS command " - "(adapter %s, port d_id=0x%06x)\n", - zfcp_get_busid_by_adapter(adapter), d_id); - for (counter = 0; counter < 2; counter++) { - subtable = header->fsf_status_qual.halfword[counter * 2]; - rule = header->fsf_status_qual.halfword[counter * 2 + 1]; - switch (subtable) { - case FSF_SQ_CFDC_SUBTABLE_OS: - case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: - case FSF_SQ_CFDC_SUBTABLE_PORT_DID: - case FSF_SQ_CFDC_SUBTABLE_LUN: - ZFCP_LOG_INFO("Access denied (%s rule %d)\n", - zfcp_act_subtable_type[subtable], rule); - break; - } - } - if (port != NULL) - zfcp_erp_port_access_denied(port, 56, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_access_denied_port(fsf_req, port); break; default: - ZFCP_LOG_NORMAL( - "bug: An unknown FSF Status was presented " - "(adapter: %s, fsf_status=0x%08x)\n", - zfcp_get_busid_by_adapter(adapter), - header->fsf_status); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } @@ -1857,9 +1495,6 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Could not create exchange configuration " - "data request for adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } @@ -1880,16 +1515,9 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) retval = zfcp_fsf_req_send(fsf_req); write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); if (retval) { - ZFCP_LOG_INFO("error: Could not send exchange configuration " - "data command on the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; } - else - ZFCP_LOG_DEBUG("exchange configuration data request initiated " - "(adapter %s)\n", - zfcp_get_busid_by_adapter(adapter)); return retval; } @@ -1908,9 +1536,6 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags, &fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Could not create exchange configuration " - "data request for adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } @@ -1931,11 +1556,7 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(fsf_req); write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - if (retval) - ZFCP_LOG_INFO("error: Could not send exchange configuration " - "data command on the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - else + if (!retval) wait_event(fsf_req->completion_wq, fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); @@ -1959,8 +1580,6 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) struct Scsi_Host *shost = adapter->scsi_host; bottom = &fsf_req->qtcb->bottom.config; - ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n", - bottom->low_qtcb_version, bottom->high_qtcb_version); adapter->fsf_lic_version = bottom->lic_version; adapter->adapter_features = bottom->adapter_features; adapter->connection_features = bottom->connection_features; @@ -2013,36 +1632,17 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) min(FC_SERIAL_NUMBER_SIZE, 17)); } - if (fsf_req->erp_action) - ZFCP_LOG_NORMAL("The adapter %s reported the following " - "characteristics:\n" - "WWNN 0x%016Lx, WWPN 0x%016Lx, " - "S_ID 0x%06x,\n" - "adapter version 0x%x, " - "LIC version 0x%x, " - "FC link speed %d Gb/s\n", - zfcp_get_busid_by_adapter(adapter), - (wwn_t) fc_host_node_name(shost), - (wwn_t) fc_host_port_name(shost), - fc_host_port_id(shost), - adapter->hydra_version, - adapter->fsf_lic_version, - fc_host_speed(shost)); if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { - ZFCP_LOG_NORMAL("error: the adapter %s " - "only supports newer control block " - "versions in comparison to this device " - "driver (try updated device driver)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, + "The adapter only supports newer control block " + "versions, try updated device driver.\n"); zfcp_erp_adapter_shutdown(adapter, 0, 125, fsf_req); return -EIO; } if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) { - ZFCP_LOG_NORMAL("error: the adapter %s " - "only supports older control block " - "versions than this device driver uses" - "(consider a microcode upgrade)\n", - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, + "The adapter only supports older control block " + "versions, consider a microcode upgrade.\n"); zfcp_erp_adapter_shutdown(adapter, 0, 126, fsf_req); return -EIO; } @@ -2074,50 +1674,38 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) switch (fc_host_port_type(adapter->scsi_host)) { case FC_PORTTYPE_PTP: - ZFCP_LOG_NORMAL("Point-to-Point fibrechannel " - "configuration detected at adapter %s\n" - "Peer WWNN 0x%016llx, " - "peer WWPN 0x%016llx, " - "peer d_id 0x%06x\n", - zfcp_get_busid_by_adapter(adapter), - adapter->peer_wwnn, - adapter->peer_wwpn, - adapter->peer_d_id); + if (fsf_req->erp_action) + dev_info(&adapter->ccw_device->dev, + "Point-to-Point fibrechannel " + "configuration detected.\n"); break; case FC_PORTTYPE_NLPORT: - ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel " - "topology detected at adapter %s " - "unsupported, shutting down adapter\n", - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, + "Unsupported arbitrated loop fibrechannel " + "topology detected, shutting down adapter\n"); zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req); return -EIO; case FC_PORTTYPE_NPORT: if (fsf_req->erp_action) - ZFCP_LOG_NORMAL("Switched fabric fibrechannel " - "network detected at adapter " - "%s.\n", - zfcp_get_busid_by_adapter(adapter)); + dev_info(&adapter->ccw_device->dev, + "Switched fabric fibrechannel " + "network detected.\n"); break; default: - ZFCP_LOG_NORMAL("bug: The fibrechannel topology " - "reported by the exchange " - "configuration command for " - "the adapter %s is not " - "of a type known to the zfcp " - "driver, shutting down adapter\n", - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, + "The fibrechannel topology reported by the " + "adapter is not known by the zfcp driver, " + "shutting down adapter.\n"); zfcp_erp_adapter_shutdown(adapter, 0, 128, fsf_req); return -EIO; } bottom = &qtcb->bottom.config; if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { - ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) " - "allowed by the adapter %s " - "is lower than the minimum " - "required by the driver (%ld bytes).\n", - bottom->max_qtcb_size, - zfcp_get_busid_by_adapter(adapter), - sizeof(struct fsf_qtcb)); + dev_err(&adapter->ccw_device->dev, + "Maximum QTCB size (%d bytes) allowed by " + "the adapter is lower than the minimum " + "required by the driver (%ld bytes).\n", + bottom->max_qtcb_size, sizeof(struct fsf_qtcb)); zfcp_erp_adapter_shutdown(adapter, 0, 129, fsf_req); return -EIO; } @@ -2154,12 +1742,8 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) unsigned long lock_flags; int retval; - if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { - ZFCP_LOG_INFO("error: exchange port data " - "command not supported by adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - } /* setup new FSF request */ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, @@ -2167,10 +1751,6 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Out of resources. Could not create an " - "exchange port data request for " - "the adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } @@ -2187,16 +1767,9 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); if (retval) { - ZFCP_LOG_INFO("error: Could not send an exchange port data " - "command on the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; } - else - ZFCP_LOG_DEBUG("exchange port data request initiated " - "(adapter %s)\n", - zfcp_get_busid_by_adapter(adapter)); return retval; } @@ -2214,21 +1787,13 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, unsigned long lock_flags; int retval; - if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { - ZFCP_LOG_INFO("error: exchange port data " - "command not supported by adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - } /* setup new FSF request */ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0, NULL, &lock_flags, &fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Out of resources. Could not create an " - "exchange port data request for " - "the adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); return retval; } @@ -2244,11 +1809,7 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, retval = zfcp_fsf_req_send(fsf_req); write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - if (retval) - ZFCP_LOG_INFO("error: Could not send an exchange port data " - "command on the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); - else + if (!retval) wait_event(fsf_req->completion_wq, fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); @@ -2338,13 +1899,8 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, erp_action->adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); - if (retval < 0) { - ZFCP_LOG_INFO("error: Could not create open port request " - "for port 0x%016Lx on adapter %s.\n", - erp_action->port->wwpn, - zfcp_get_busid_by_adapter(erp_action->adapter)); + if (retval < 0) goto out; - } sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; @@ -2359,19 +1915,11 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Could not send open port request for " - "port 0x%016Lx on adapter %s.\n", - erp_action->port->wwpn, - zfcp_get_busid_by_adapter(erp_action->adapter)); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; goto out; } - ZFCP_LOG_DEBUG("open port request initiated " - "(adapter %s, port 0x%016Lx)\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->port->wwpn); out: write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; @@ -2391,7 +1939,6 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) struct zfcp_port *port; struct fsf_plogi *plogi; struct fsf_qtcb_header *header; - u16 subtable, rule, counter; port = (struct zfcp_port *) fsf_req->data; header = &fsf_req->qtcb->header; @@ -2405,9 +1952,6 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) switch (header->fsf_status) { case FSF_PORT_ALREADY_OPEN: - ZFCP_LOG_NORMAL("bug: remote port 0x%016Lx on adapter %s " - "is already open.\n", - port->wwpn, zfcp_get_busid_by_port(port)); /* * This is a bug, however operation should continue normally * if it is simply ignored @@ -2415,31 +1959,14 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_ACCESS_DENIED: - ZFCP_LOG_NORMAL("Access denied, cannot open port 0x%016Lx " - "on adapter %s\n", - port->wwpn, zfcp_get_busid_by_port(port)); - for (counter = 0; counter < 2; counter++) { - subtable = header->fsf_status_qual.halfword[counter * 2]; - rule = header->fsf_status_qual.halfword[counter * 2 + 1]; - switch (subtable) { - case FSF_SQ_CFDC_SUBTABLE_OS: - case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: - case FSF_SQ_CFDC_SUBTABLE_PORT_DID: - case FSF_SQ_CFDC_SUBTABLE_LUN: - ZFCP_LOG_INFO("Access denied (%s rule %d)\n", - zfcp_act_subtable_type[subtable], rule); - break; - } - } - zfcp_erp_port_access_denied(port, 57, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_access_denied_port(fsf_req, port); break; case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: - ZFCP_LOG_INFO("error: The FSF adapter is out of resources. " - "The remote port 0x%016Lx on adapter %s " - "could not be opened. Disabling it.\n", - port->wwpn, zfcp_get_busid_by_port(port)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The adapter is out of resources. The remote port " + "0x%016Lx could not be opened, disabling it.\n", + port->wwpn); zfcp_erp_port_failed(port, 31, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -2455,18 +1982,13 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_NO_RETRY_POSSIBLE: - ZFCP_LOG_NORMAL("The remote port 0x%016Lx on " - "adapter %s could not be opened. " - "Disabling it.\n", - port->wwpn, - zfcp_get_busid_by_port(port)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The remote port 0x%016Lx could not be " + "opened. Disabling it.\n", port->wwpn); zfcp_erp_port_failed(port, 32, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: - ZFCP_LOG_NORMAL - ("bug: Wrong status qualifier 0x%x arrived.\n", - header->fsf_status_qual.word[0]); break; } break; @@ -2474,10 +1996,6 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) case FSF_GOOD: /* save port handle assigned by FSF */ port->handle = header->port_handle; - ZFCP_LOG_INFO("The remote port 0x%016Lx via adapter %s " - "was opened, it's port handle is 0x%x\n", - port->wwpn, zfcp_get_busid_by_port(port), - port->handle); /* mark port as open */ atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); @@ -2505,16 +2023,9 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) { if (fsf_req->qtcb->bottom.support.els1_length < sizeof (struct fsf_plogi)) { - ZFCP_LOG_INFO( - "warning: insufficient length of " - "PLOGI payload (%i)\n", - fsf_req->qtcb->bottom.support.els1_length); /* skip sanity check and assume wwpn is ok */ } else { if (plogi->serv_param.wwpn != port->wwpn) { - ZFCP_LOG_INFO("warning: d_id of port " - "0x%016Lx changed during " - "open\n", port->wwpn); atomic_clear_mask( ZFCP_STATUS_PORT_DID_DID, &port->status); @@ -2528,17 +2039,10 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) case FSF_UNKNOWN_OP_SUBTYPE: /* should never occure, subtype not set in zfcp_fsf_open_port */ - ZFCP_LOG_INFO("unknown operation subtype (adapter: %s, " - "op_subtype=0x%x)\n", - zfcp_get_busid_by_port(port), - fsf_req->qtcb->bottom.support.operation_subtype); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: - ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " - "(debug info 0x%x)\n", - header->fsf_status); break; } @@ -2569,13 +2073,8 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, erp_action->adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); - if (retval < 0) { - ZFCP_LOG_INFO("error: Could not create a close port request " - "for port 0x%016Lx on adapter %s.\n", - erp_action->port->wwpn, - zfcp_get_busid_by_adapter(erp_action->adapter)); + if (retval < 0) goto out; - } sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; @@ -2591,19 +2090,11 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Could not send a close port request for " - "port 0x%016Lx on adapter %s.\n", - erp_action->port->wwpn, - zfcp_get_busid_by_adapter(erp_action->adapter)); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; goto out; } - ZFCP_LOG_TRACE("close port request initiated " - "(adapter %s, port 0x%016Lx)\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->port->wwpn); out: write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; @@ -2633,14 +2124,6 @@ zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req) switch (fsf_req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " - "0x%016Lx on adapter %s invalid. This may happen " - "occasionally.\n", port->handle, - port->wwpn, zfcp_get_busid_by_port(port)); - ZFCP_LOG_DEBUG("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_adapter_reopen(port->adapter, 0, 107, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -2653,20 +2136,11 @@ zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_GOOD: - ZFCP_LOG_TRACE("remote port 0x016%Lx on adapter %s closed, " - "port handle 0x%x\n", port->wwpn, - zfcp_get_busid_by_port(port), port->handle); zfcp_erp_modify_port_status(port, 33, fsf_req, ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); retval = 0; break; - - default: - ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " - "(debug info 0x%x)\n", - fsf_req->qtcb->header.fsf_status); - break; } skip_fsfstatus: @@ -2696,14 +2170,8 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, erp_action->adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); - if (retval < 0) { - ZFCP_LOG_INFO("error: Could not create close physical port " - "request (adapter %s, port 0x%016Lx)\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->port->wwpn); - + if (retval < 0) goto out; - } sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; @@ -2721,19 +2189,11 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Could not send close physical port " - "request (adapter %s, port 0x%016Lx)\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->port->wwpn); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; goto out; } - ZFCP_LOG_TRACE("close physical port request initiated " - "(adapter %s, port 0x%016Lx)\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->port->wwpn); out: write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; @@ -2753,7 +2213,6 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) struct zfcp_port *port; struct zfcp_unit *unit; struct fsf_qtcb_header *header; - u16 subtable, rule, counter; port = (struct zfcp_port *) fsf_req->data; header = &fsf_req->qtcb->header; @@ -2767,47 +2226,15 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - ZFCP_LOG_INFO("Temporary port identifier 0x%x invalid" - "(adapter %s, port 0x%016Lx). " - "This may happen occasionally.\n", - port->handle, - zfcp_get_busid_by_port(port), - port->wwpn); - ZFCP_LOG_DEBUG("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_adapter_reopen(port->adapter, 0, 108, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ACCESS_DENIED: - ZFCP_LOG_NORMAL("Access denied, cannot close " - "physical port 0x%016Lx on adapter %s\n", - port->wwpn, zfcp_get_busid_by_port(port)); - for (counter = 0; counter < 2; counter++) { - subtable = header->fsf_status_qual.halfword[counter * 2]; - rule = header->fsf_status_qual.halfword[counter * 2 + 1]; - switch (subtable) { - case FSF_SQ_CFDC_SUBTABLE_OS: - case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: - case FSF_SQ_CFDC_SUBTABLE_PORT_DID: - case FSF_SQ_CFDC_SUBTABLE_LUN: - ZFCP_LOG_INFO("Access denied (%s rule %d)\n", - zfcp_act_subtable_type[subtable], rule); - break; - } - } - zfcp_erp_port_access_denied(port, 58, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_access_denied_port(fsf_req, port); break; case FSF_PORT_BOXED: - ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter " - "%s needs to be reopened but it was attempted " - "to close it physically.\n", - port->wwpn, - zfcp_get_busid_by_port(port)); zfcp_erp_port_boxed(port, 50, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; @@ -2830,19 +2257,10 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) /* ERP strategy will escalate */ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - default: - ZFCP_LOG_NORMAL - ("bug: Wrong status qualifier 0x%x arrived.\n", - header->fsf_status_qual.word[0]); - break; } break; case FSF_GOOD: - ZFCP_LOG_DEBUG("Remote port 0x%016Lx via adapter %s " - "physically closed, port handle 0x%x\n", - port->wwpn, - zfcp_get_busid_by_port(port), port->handle); /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ @@ -2851,12 +2269,6 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); retval = 0; break; - - default: - ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " - "(debug info 0x%x)\n", - header->fsf_status); - break; } skip_fsfstatus: @@ -2890,14 +2302,8 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, erp_action->adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); - if (retval < 0) { - ZFCP_LOG_INFO("error: Could not create open unit request for " - "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n", - erp_action->unit->fcp_lun, - erp_action->unit->port->wwpn, - zfcp_get_busid_by_adapter(erp_action->adapter)); + if (retval < 0) goto out; - } sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; @@ -2916,21 +2322,10 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(erp_action->fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Could not send an open unit request " - "on the adapter %s, port 0x%016Lx for " - "unit 0x%016Lx\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->port->wwpn, - erp_action->unit->fcp_lun); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; goto out; } - - ZFCP_LOG_TRACE("Open LUN request initiated (adapter %s, " - "port 0x%016Lx, unit 0x%016Lx)\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->port->wwpn, erp_action->unit->fcp_lun); out: write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; @@ -2952,7 +2347,6 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) struct fsf_qtcb_header *header; struct fsf_qtcb_bottom_support *bottom; struct fsf_queue_designator *queue_designator; - u16 subtable, rule, counter; int exclusive, readwrite; unit = (struct zfcp_unit *) fsf_req->data; @@ -2977,55 +2371,21 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - ZFCP_LOG_INFO("Temporary port identifier 0x%x " - "for port 0x%016Lx on adapter %s invalid " - "This may happen occasionally\n", - unit->port->handle, - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); - ZFCP_LOG_DEBUG("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_ALREADY_OPEN: - ZFCP_LOG_NORMAL("bug: Attempted to open unit 0x%016Lx on " - "remote port 0x%016Lx on adapter %s twice.\n", - unit->fcp_lun, - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ACCESS_DENIED: - ZFCP_LOG_NORMAL("Access denied, cannot open unit 0x%016Lx on " - "remote port 0x%016Lx on adapter %s\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - for (counter = 0; counter < 2; counter++) { - subtable = header->fsf_status_qual.halfword[counter * 2]; - rule = header->fsf_status_qual.halfword[counter * 2 + 1]; - switch (subtable) { - case FSF_SQ_CFDC_SUBTABLE_OS: - case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: - case FSF_SQ_CFDC_SUBTABLE_PORT_DID: - case FSF_SQ_CFDC_SUBTABLE_LUN: - ZFCP_LOG_INFO("Access denied (%s rule %d)\n", - zfcp_act_subtable_type[subtable], rule); - break; - } - } - zfcp_erp_unit_access_denied(unit, 59, fsf_req); + zfcp_fsf_access_denied_unit(fsf_req, unit); atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); - atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); break; case FSF_PORT_BOXED: - ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " - "needs to be reopened\n", - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); zfcp_erp_port_boxed(unit->port, 51, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; @@ -3033,39 +2393,18 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) case FSF_LUN_SHARING_VIOLATION: if (header->fsf_status_qual.word[0] != 0) { - ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port " - "with WWPN 0x%Lx " - "connected to the adapter %s " - "is already in use in LPAR%d, CSS%d\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - queue_designator->hla, - queue_designator->cssid); - } else { - subtable = header->fsf_status_qual.halfword[4]; - rule = header->fsf_status_qual.halfword[5]; - switch (subtable) { - case FSF_SQ_CFDC_SUBTABLE_OS: - case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: - case FSF_SQ_CFDC_SUBTABLE_PORT_DID: - case FSF_SQ_CFDC_SUBTABLE_LUN: - ZFCP_LOG_NORMAL("Access to FCP-LUN 0x%Lx at the " - "remote port with WWPN 0x%Lx " - "connected to the adapter %s " - "is denied (%s rule %d)\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - zfcp_act_subtable_type[subtable], - rule); - break; - } - } - ZFCP_LOG_DEBUG("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); + dev_warn(&adapter->ccw_device->dev, + "FCP-LUN 0x%Lx at the remote port " + "with WWPN 0x%Lx " + "connected to the adapter " + "is already in use in LPAR%d, CSS%d.\n", + unit->fcp_lun, + unit->port->wwpn, + queue_designator->hla, + queue_designator->cssid); + } else + zfcp_act_eval_err(adapter, + header->fsf_status_qual.word[2]); zfcp_erp_unit_access_denied(unit, 60, fsf_req); atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); @@ -3073,13 +2412,10 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: - ZFCP_LOG_INFO("error: The adapter ran out of resources. " - "There is no handle (temporary port identifier) " - "available for unit 0x%016Lx on port 0x%016Lx " - "on adapter %s\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); + dev_warn(&fsf_req->adapter->ccw_device->dev, + "The adapter ran out of resources. There is no " + "handle available for unit 0x%016Lx on port 0x%016Lx.", + unit->fcp_lun, unit->port->wwpn); zfcp_erp_unit_failed(unit, 34, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3095,19 +2431,10 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) /* ERP strategy will escalate */ fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - default: - ZFCP_LOG_NORMAL - ("bug: Wrong status qualifier 0x%x arrived.\n", - header->fsf_status_qual.word[0]); } break; case FSF_INVALID_COMMAND_OPTION: - ZFCP_LOG_NORMAL( - "Invalid option 0x%x has been specified " - "in QTCB bottom sent to the adapter %s\n", - bottom->option, - zfcp_get_busid_by_adapter(adapter)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; retval = -EINVAL; break; @@ -3115,12 +2442,6 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) case FSF_GOOD: /* save LUN handle assigned by FSF */ unit->handle = header->lun_handle; - ZFCP_LOG_TRACE("unit 0x%016Lx on remote port 0x%016Lx on " - "adapter %s opened, port handle 0x%x\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - unit->handle); /* mark unit as open */ atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); @@ -3139,23 +2460,27 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) if (!readwrite) { atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); - ZFCP_LOG_NORMAL("read-only access for unit " - "(adapter %s, wwpn=0x%016Lx, " - "fcp_lun=0x%016Lx)\n", - zfcp_get_busid_by_unit(unit), - unit->port->wwpn, - unit->fcp_lun); + dev_info(&fsf_req->adapter->ccw_device->dev, + "Read-only access for unit 0x%016Lx " + "on port 0x%016Lx.\n", + unit->fcp_lun, unit->port->wwpn); } if (exclusive && !readwrite) { - ZFCP_LOG_NORMAL("exclusive access of read-only " - "unit not supported\n"); + dev_err(&fsf_req->adapter->ccw_device->dev, + "Exclusive access of read-only unit " + "0x%016Lx on port 0x%016Lx not " + "supported, disabling unit.\n", + unit->fcp_lun, unit->port->wwpn); zfcp_erp_unit_failed(unit, 35, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; zfcp_erp_unit_shutdown(unit, 0, 80, fsf_req); } else if (!exclusive && readwrite) { - ZFCP_LOG_NORMAL("shared access of read-write " - "unit not supported\n"); + dev_err(&fsf_req->adapter->ccw_device->dev, + "Shared access of read-write unit " + "0x%016Lx on port 0x%016Lx not " + "supported, disabling unit.\n", + unit->fcp_lun, unit->port->wwpn); zfcp_erp_unit_failed(unit, 36, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; zfcp_erp_unit_shutdown(unit, 0, 81, fsf_req); @@ -3164,12 +2489,6 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) retval = 0; break; - - default: - ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " - "(debug info 0x%x)\n", - header->fsf_status); - break; } skip_fsfstatus: @@ -3204,14 +2523,8 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, erp_action->adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); - if (retval < 0) { - ZFCP_LOG_INFO("error: Could not create close unit request for " - "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n", - erp_action->unit->fcp_lun, - erp_action->port->wwpn, - zfcp_get_busid_by_adapter(erp_action->adapter)); + if (retval < 0) goto out; - } sbale = zfcp_qdio_sbale_req(fsf_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; @@ -3227,20 +2540,11 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(erp_action->fsf_req); if (retval) { - ZFCP_LOG_INFO("error: Could not send a close unit request for " - "unit 0x%016Lx on port 0x%016Lx onadapter %s.\n", - erp_action->unit->fcp_lun, - erp_action->port->wwpn, - zfcp_get_busid_by_adapter(erp_action->adapter)); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; goto out; } - ZFCP_LOG_TRACE("Close LUN request initiated (adapter %s, " - "port 0x%016Lx, unit 0x%016Lx)\n", - zfcp_get_busid_by_adapter(erp_action->adapter), - erp_action->port->wwpn, erp_action->unit->fcp_lun); out: write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; @@ -3270,41 +2574,16 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) switch (fsf_req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " - "0x%016Lx on adapter %s invalid. This may " - "happen in rare circumstances\n", - unit->port->handle, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - ZFCP_LOG_DEBUG("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_HANDLE_NOT_VALID: - ZFCP_LOG_INFO("Temporary LUN identifier 0x%x of unit " - "0x%016Lx on port 0x%016Lx on adapter %s is " - "invalid. This may happen occasionally.\n", - unit->handle, - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - ZFCP_LOG_DEBUG("Status qualifier data:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_port_reopen(unit->port, 0, 111, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " - "needs to be reopened\n", - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); zfcp_erp_port_boxed(unit->port, 52, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; @@ -3322,30 +2601,15 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: - ZFCP_LOG_NORMAL - ("bug: Wrong status qualifier 0x%x arrived.\n", - fsf_req->qtcb->header.fsf_status_qual.word[0]); break; } break; case FSF_GOOD: - ZFCP_LOG_TRACE("unit 0x%016Lx on port 0x%016Lx on adapter %s " - "closed, port handle 0x%x\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - unit->handle); /* mark unit as closed */ atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); retval = 0; break; - - default: - ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " - "(debug info 0x%x)\n", - fsf_req->qtcb->header.fsf_status); - break; } skip_fsfstatus: @@ -3379,15 +2643,8 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, adapter->pool.fsf_req_scsi, &lock_flags, &fsf_req); - if (unlikely(retval < 0)) { - ZFCP_LOG_DEBUG("error: Could not create FCP command request " - "for unit 0x%016Lx on port 0x%016Lx on " - "adapter %s\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_adapter(adapter)); + if (unlikely(retval < 0)) goto failed_req_create; - } if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) { @@ -3463,15 +2720,9 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, fcp_cmnd_iu->task_attribute = UNTAGGED; /* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */ - if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) { + if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) fcp_cmnd_iu->add_fcp_cdb_length = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; - ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, " - "additional FCP_CDB length is 0x%x " - "(shifted right 2 bits)\n", - scsi_cmnd->cmd_len, - fcp_cmnd_iu->add_fcp_cdb_length); - } /* * copy SCSI CDB (including additional length, if any) to * FCP_CDB in FCP_CMND IU in QTCB @@ -3488,19 +2739,14 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, scsi_sglist(scsi_cmnd), ZFCP_MAX_SBALS_PER_REQ); if (unlikely(real_bytes < 0)) { - if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) { - ZFCP_LOG_DEBUG( - "Data did not fit into available buffer(s), " - "waiting for more...\n"); + if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) retval = -EIO; - } else { - ZFCP_LOG_NORMAL("error: No truncation implemented but " - "required. Shutting down unit " - "(adapter %s, port 0x%016Lx, " - "unit 0x%016Lx)\n", - zfcp_get_busid_by_unit(unit), - unit->port->wwpn, - unit->fcp_lun); + else { + dev_err(&adapter->ccw_device->dev, + "SCSI request too large. " + "Shutting down unit 0x%016Lx on port " + "0x%016Lx.\n", unit->fcp_lun, + unit->port->wwpn); zfcp_erp_unit_shutdown(unit, 0, 131, fsf_req); retval = -EINVAL; } @@ -3510,28 +2756,13 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, /* set length of FCP data length in FCP_CMND IU in QTCB */ zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); - ZFCP_LOG_DEBUG("Sending SCSI command:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len); - if (use_timer) zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(fsf_req); - if (unlikely(retval < 0)) { - ZFCP_LOG_INFO("error: Could not send FCP command request " - "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n", - zfcp_get_busid_by_adapter(adapter), - unit->port->wwpn, - unit->fcp_lun); + if (unlikely(retval < 0)) goto send_failed; - } - ZFCP_LOG_TRACE("Send FCP Command initiated (adapter %s, " - "port 0x%016Lx, unit 0x%016Lx)\n", - zfcp_get_busid_by_adapter(adapter), - unit->port->wwpn, - unit->fcp_lun); goto success; send_failed: @@ -3563,14 +2794,8 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, adapter->pool.fsf_req_scsi, &lock_flags, &fsf_req); - if (retval < 0) { - ZFCP_LOG_INFO("error: Could not create FCP command (task " - "management) request for adapter %s, port " - " 0x%016Lx, unit 0x%016Lx.\n", - zfcp_get_busid_by_adapter(adapter), - unit->port->wwpn, unit->fcp_lun); + if (retval < 0) goto out; - } if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) @@ -3674,7 +2899,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) int retval = -EINVAL; struct zfcp_unit *unit; struct fsf_qtcb_header *header; - u16 subtable, rule, counter; header = &fsf_req->qtcb->header; @@ -3692,137 +2916,61 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " - "0x%016Lx on adapter %s invalid\n", - unit->port->handle, - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_HANDLE_NOT_VALID: - ZFCP_LOG_INFO("Temporary LUN identifier 0x%x for unit " - "0x%016Lx on port 0x%016Lx on adapter %s is " - "invalid. This may happen occasionally.\n", - unit->handle, - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - ZFCP_LOG_NORMAL("Status qualifier data:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_port_reopen(unit->port, 0, 113, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_HANDLE_MISMATCH: - ZFCP_LOG_NORMAL("bug: The port handle 0x%x has changed " - "unexpectedly. (adapter %s, port 0x%016Lx, " - "unit 0x%016Lx)\n", - unit->port->handle, - zfcp_get_busid_by_unit(unit), - unit->port->wwpn, - unit->fcp_lun); - ZFCP_LOG_NORMAL("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_adapter_reopen(unit->port->adapter, 0, 114, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: - ZFCP_LOG_INFO("error: adapter %s does not support fc " - "class %d.\n", - zfcp_get_busid_by_unit(unit), - ZFCP_FC_SERVICE_CLASS_DEFAULT); - /* stop operation for this adapter */ - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 132, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_class_not_supp(fsf_req); break; case FSF_FCPLUN_NOT_VALID: - ZFCP_LOG_NORMAL("bug: unit 0x%016Lx on port 0x%016Lx on " - "adapter %s does not have correct unit " - "handle 0x%x\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - unit->handle); - ZFCP_LOG_DEBUG("status qualifier:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &header->fsf_status_qual, - sizeof (union fsf_status_qual)); zfcp_erp_port_reopen(unit->port, 0, 115, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ACCESS_DENIED: - ZFCP_LOG_NORMAL("Access denied, cannot send FCP command to " - "unit 0x%016Lx on port 0x%016Lx on " - "adapter %s\n", unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - for (counter = 0; counter < 2; counter++) { - subtable = header->fsf_status_qual.halfword[counter * 2]; - rule = header->fsf_status_qual.halfword[counter * 2 + 1]; - switch (subtable) { - case FSF_SQ_CFDC_SUBTABLE_OS: - case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: - case FSF_SQ_CFDC_SUBTABLE_PORT_DID: - case FSF_SQ_CFDC_SUBTABLE_LUN: - ZFCP_LOG_INFO("Access denied (%s rule %d)\n", - zfcp_act_subtable_type[subtable], rule); - break; - } - } - zfcp_erp_unit_access_denied(unit, 61, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_access_denied_unit(fsf_req, unit); break; case FSF_DIRECTION_INDICATOR_NOT_VALID: - ZFCP_LOG_INFO("bug: Invalid data direction given for unit " - "0x%016Lx on port 0x%016Lx on adapter %s " - "(debug info %d)\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - fsf_req->qtcb->bottom.io.data_direction); - /* stop operation for this adapter */ + dev_err(&fsf_req->adapter->ccw_device->dev, + "Invalid data direction (%d) given for unit 0x%016Lx " + "on port 0x%016Lx, shutting down adapter.\n", + fsf_req->qtcb->bottom.io.data_direction, + unit->fcp_lun, unit->port->wwpn); zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_CMND_LENGTH_NOT_VALID: - ZFCP_LOG_NORMAL - ("bug: An invalid control-data-block length field " - "was found in a command for unit 0x%016Lx on port " - "0x%016Lx on adapter %s " "(debug info %d)\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - fsf_req->qtcb->bottom.io.fcp_cmnd_length); - /* stop operation for this adapter */ + dev_err(&fsf_req->adapter->ccw_device->dev, + "An invalid control-data-block length field (%d) " + "was found in a command for unit 0x%016Lx on port " + "0x%016Lx. Shutting down adapter.\n", + fsf_req->qtcb->bottom.io.fcp_cmnd_length, + unit->fcp_lun, unit->port->wwpn); zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " - "needs to be reopened\n", - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); zfcp_erp_port_boxed(unit->port, 53, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; break; case FSF_LUN_BOXED: - ZFCP_LOG_NORMAL("unit needs to be reopened (adapter %s, " - "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", - zfcp_get_busid_by_unit(unit), - unit->port->wwpn, unit->fcp_lun); zfcp_erp_unit_boxed(unit, 54, fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; @@ -3838,11 +2986,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) /* FIXME(hw) need proper specs for proper action */ /* let scsi stack deal with retries and escalation */ break; - default: - ZFCP_LOG_NORMAL - ("Unknown status qualifier 0x%x arrived.\n", - header->fsf_status_qual.word[0]); - break; } fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3880,34 +3023,26 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) struct scsi_cmnd *scpnt; struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) &(fsf_req->qtcb->bottom.io.fcp_rsp); - struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *) - &(fsf_req->qtcb->bottom.io.fcp_cmnd); u32 sns_len; char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); unsigned long flags; - struct zfcp_unit *unit = fsf_req->unit; read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); scpnt = (struct scsi_cmnd *) fsf_req->data; - if (unlikely(!scpnt)) { - ZFCP_LOG_DEBUG - ("Command with fsf_req %p is not associated to " - "a scsi command anymore. Aborted?\n", fsf_req); + if (unlikely(!scpnt)) goto out; - } + if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { /* FIXME: (design) mid-layer should handle DID_ABORT like * DID_SOFT_ERROR by retrying the request for devices * that allow retries. */ - ZFCP_LOG_DEBUG("Setting DID_SOFT_ERROR and SUGGEST_RETRY\n"); set_host_byte(&scpnt->result, DID_SOFT_ERROR); set_driver_byte(&scpnt->result, SUGGEST_RETRY); goto skip_fsfstatus; } if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { - ZFCP_LOG_DEBUG("Setting DID_ERROR\n"); set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; } @@ -3920,97 +3055,31 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) * of result in SCSI command */ scpnt->result |= fcp_rsp_iu->scsi_status; - if (unlikely(fcp_rsp_iu->scsi_status)) { - /* DEBUG */ - ZFCP_LOG_DEBUG("status for SCSI Command:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - scpnt->cmnd, scpnt->cmd_len); - ZFCP_LOG_DEBUG("SCSI status code 0x%x\n", - fcp_rsp_iu->scsi_status); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (void *) fcp_rsp_iu, sizeof (struct fcp_rsp_iu)); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), - fcp_rsp_iu->fcp_sns_len); - } if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) zfcp_fsf_req_latency(fsf_req); /* check FCP_RSP_INFO */ if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { - ZFCP_LOG_DEBUG("rsp_len is valid\n"); switch (fcp_rsp_info[3]) { case RSP_CODE_GOOD: /* ok, continue */ - ZFCP_LOG_TRACE("no failure or Task Management " - "Function complete\n"); set_host_byte(&scpnt->result, DID_OK); break; case RSP_CODE_LENGTH_MISMATCH: /* hardware bug */ - ZFCP_LOG_NORMAL("bug: FCP response code indictates " - "that the fibrechannel protocol data " - "length differs from the burst length. " - "The problem occured on unit 0x%016Lx " - "on port 0x%016Lx on adapter %s", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - /* dump SCSI CDB as prepared by zfcp */ - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &fsf_req->qtcb-> - bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; case RSP_CODE_FIELD_INVALID: /* driver or hardware bug */ - ZFCP_LOG_NORMAL("bug: FCP response code indictates " - "that the fibrechannel protocol data " - "fields were incorrectly set up. " - "The problem occured on the unit " - "0x%016Lx on port 0x%016Lx on " - "adapter %s", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - /* dump SCSI CDB as prepared by zfcp */ - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &fsf_req->qtcb-> - bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; case RSP_CODE_RO_MISMATCH: /* hardware bug */ - ZFCP_LOG_NORMAL("bug: The FCP response code indicates " - "that conflicting values for the " - "fibrechannel payload offset from the " - "header were found. " - "The problem occured on unit 0x%016Lx " - "on port 0x%016Lx on adapter %s.\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); - /* dump SCSI CDB as prepared by zfcp */ - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &fsf_req->qtcb-> - bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; default: - ZFCP_LOG_NORMAL("bug: An invalid FCP response " - "code was detected for a command. " - "The problem occured on the unit " - "0x%016Lx on port 0x%016Lx on " - "adapter %s (debug info 0x%x)\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - fcp_rsp_info[3]); - /* dump SCSI CDB as prepared by zfcp */ - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) &fsf_req->qtcb-> - bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); + /* invalid FCP response code */ set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; } @@ -4020,50 +3089,15 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { sns_len = FSF_FCP_RSP_SIZE - sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len; - ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n", - sns_len); sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); - ZFCP_LOG_TRACE("room for %i bytes sense data in SCSI command\n", - SCSI_SENSE_BUFFERSIZE); sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); - ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n", - scpnt->result); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, - scpnt->cmnd, scpnt->cmd_len); - ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n", - fcp_rsp_iu->fcp_sns_len); memcpy(scpnt->sense_buffer, zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, - (void *)scpnt->sense_buffer, sns_len); - } - - /* check for overrun */ - if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) { - ZFCP_LOG_INFO("A data overrun was detected for a command. " - "unit 0x%016Lx, port 0x%016Lx, adapter %s. " - "The response data length is " - "%d, the original length was %d.\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - fcp_rsp_iu->fcp_resid, - (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); } /* check for underrun */ if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { - ZFCP_LOG_INFO("A data underrun was detected for a command. " - "unit 0x%016Lx, port 0x%016Lx, adapter %s. " - "The response data length is " - "%d, the original length was %d.\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - fcp_rsp_iu->fcp_resid, - (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); - scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < scpnt->underflow) @@ -4071,8 +3105,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) } skip_fsfstatus: - ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result); - if (scpnt->result != 0) zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt, fsf_req); else if (scpnt->retries > 0) @@ -4111,7 +3143,6 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) &(fsf_req->qtcb->bottom.io.fcp_rsp); char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); - struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; @@ -4122,36 +3153,15 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) switch (fcp_rsp_info[3]) { case RSP_CODE_GOOD: /* ok, continue */ - ZFCP_LOG_DEBUG("no failure or Task Management " - "Function complete\n"); break; case RSP_CODE_TASKMAN_UNSUPP: - ZFCP_LOG_NORMAL("bug: A reuested task management function " - "is not supported on the target device " - "unit 0x%016Lx, port 0x%016Lx, adapter %s\n ", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP; break; case RSP_CODE_TASKMAN_FAILED: - ZFCP_LOG_NORMAL("bug: A reuested task management function " - "failed to complete successfully. " - "unit 0x%016Lx, port 0x%016Lx, adapter %s.\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; break; default: - ZFCP_LOG_NORMAL("bug: An invalid FCP response " - "code was detected for a command. " - "unit 0x%016Lx, port 0x%016Lx, adapter %s " - "(debug info 0x%x)\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - fcp_rsp_info[3]); + /* invalid FCP response code */ fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; } @@ -4332,9 +3342,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, /* allocate new FSF request */ fsf_req = zfcp_fsf_req_alloc(pool, req_flags); - if (unlikely(NULL == fsf_req)) { - ZFCP_LOG_DEBUG("error: Could not put an FSF request into " - "the outbound (send) queue.\n"); + if (unlikely(!fsf_req)) { ret = -ENOMEM; goto failed_fsf_req; } @@ -4393,9 +3401,6 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, sbale[1].length = sizeof(struct fsf_qtcb); } - ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n", - fsf_req->sbal_number, fsf_req->sbal_first); - goto success; failed_sbals: @@ -4429,13 +3434,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) adapter = fsf_req->adapter; req_q = &adapter->req_q; - - /* FIXME(debug): remove it later */ sbale = zfcp_qdio_sbale_req(fsf_req); - ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags); - ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr, - sbale[1].length); /* put allocated FSF request into hash table */ spin_lock(&adapter->req_list_lock); @@ -4476,5 +3475,3 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) } return retval; } - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 598eba9baa31..6ce2f1e4b00e 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -1,22 +1,9 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Interface to the FSF support functions. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #ifndef FSF_H @@ -342,6 +329,7 @@ struct fsf_qual_latency_info { } __attribute__ ((packed)); union fsf_prot_status_qual { + u32 word[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u32)]; u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; struct fsf_qual_version_error version_error; struct fsf_qual_sequence_error sequence_error; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 4b0c85acb0f0..a96e5c3b9460 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -1,26 +1,11 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * Interface to Linux SCSI midlayer. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI - #include "zfcp_ext.h" #include @@ -44,7 +29,7 @@ static struct device_attribute *zfcp_a_stats_attrs[]; struct zfcp_data zfcp_data = { .scsi_host_template = { - .name = ZFCP_NAME, + .name = "zfcp", .module = THIS_MODULE, .proc_name = "zfcp", .slave_alloc = zfcp_scsi_slave_alloc, @@ -64,7 +49,6 @@ struct zfcp_data zfcp_data = { .max_sectors = ZFCP_MAX_SECTORS, .shost_attrs = zfcp_a_stats_attrs, }, - .driver_version = ZFCP_VERSION, }; /* Find start of Response Information in FCP response unit*/ @@ -181,16 +165,14 @@ zfcp_scsi_slave_alloc(struct scsi_device *sdp) static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) { struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; - + WARN_ON(!unit); if (unit) { atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); sdpnt->hostdata = NULL; unit->device = NULL; zfcp_erp_unit_failed(unit, 12, NULL); zfcp_unit_put(unit); - } else - ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at " - "address %p\n", sdpnt); + } } /* @@ -253,10 +235,6 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, if (unlikely( atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) || !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) { - ZFCP_LOG_DEBUG("stopping SCSI I/O on unit 0x%016Lx on port " - "0x%016Lx on adapter %s\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_adapter(adapter)); zfcp_scsi_command_fail(scpnt, DID_ERROR); goto out; } @@ -264,18 +242,12 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer, ZFCP_REQ_AUTO_CLEANUP); if (unlikely(tmp == -EBUSY)) { - ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx " - "on port 0x%016Lx in recovery\n", - zfcp_get_busid_by_unit(unit), - unit->fcp_lun, unit->port->wwpn); zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); goto out; } - if (unlikely(tmp < 0)) { - ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n"); + if (unlikely(tmp < 0)) retval = SCSI_MLQUEUE_HOST_BUSY; - } out: return retval; @@ -394,9 +366,6 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; unit = (struct zfcp_unit *) scpnt->device->hostdata; - ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n", - scpnt, zfcp_get_busid_by_adapter(adapter)); - /* avoid race condition between late normal completion and abort */ write_lock_irqsave(&adapter->abort_lock, flags); @@ -420,7 +389,6 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); if (!fsf_req) { - ZFCP_LOG_INFO("error: initiation of Abort FCP Cmnd failed\n"); zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, old_req_id); retval = FAILED; @@ -485,10 +453,6 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, fsf_req = zfcp_fsf_send_fcp_command_task_management (adapter, unit, tm_flags, 0); if (!fsf_req) { - ZFCP_LOG_INFO("error: creation of task management request " - "failed for unit 0x%016Lx on port 0x%016Lx on " - "adapter %s\n", unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_adapter(adapter)); zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); retval = -ENOMEM; goto out; @@ -524,12 +488,6 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) unit = (struct zfcp_unit*) scpnt->device->hostdata; adapter = unit->port->adapter; - - ZFCP_LOG_NORMAL("host reset because of problems with " - "unit 0x%016Lx on port 0x%016Lx, adapter %s\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_adapter(unit->port->adapter)); - zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); zfcp_erp_wait(adapter); @@ -549,13 +507,11 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template, sizeof (struct zfcp_adapter *)); if (!adapter->scsi_host) { - ZFCP_LOG_NORMAL("error: registration with SCSI stack failed " - "for adapter %s ", - zfcp_get_busid_by_adapter(adapter)); + dev_err(&adapter->ccw_device->dev, + "registration with SCSI stack failed."); retval = -EIO; goto out; } - ZFCP_LOG_DEBUG("host registered, scsi_host=%p\n", adapter->scsi_host); /* tell the SCSI stack some characteristics of this adapter */ adapter->scsi_host->max_id = 1; @@ -987,5 +943,3 @@ static struct device_attribute *zfcp_a_stats_attrs[] = { &dev_attr_seconds_active, NULL }; - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c index ccbba4dd3a77..1f2a8c21b731 100644 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c @@ -1,28 +1,13 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * sysfs attributes for CCW device. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #include "zfcp_ext.h" -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG - /** * ZFCP_DEFINE_ADAPTER_ATTR * @_name: name of show attribute @@ -266,5 +251,3 @@ zfcp_sysfs_adapter_remove_files(struct device *dev) { sysfs_remove_group(&dev->kobj, &zfcp_adapter_attr_group); } - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c deleted file mode 100644 index 651edd58906a..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_driver.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. - * - * (C) Copyright IBM Corp. 2002, 2006 - * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "zfcp_ext.h" - -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG - -/** - * ZFCP_DEFINE_DRIVER_ATTR - define for all loglevels sysfs attributes - * @_name: name of attribute - * @_define: name of ZFCP loglevel define - * - * Generates store function for a sysfs loglevel attribute of zfcp driver. - */ -#define ZFCP_DEFINE_DRIVER_ATTR(_name, _define) \ -static ssize_t zfcp_sysfs_loglevel_##_name##_store(struct device_driver *drv, \ - const char *buf, \ - size_t count) \ -{ \ - unsigned int loglevel; \ - unsigned int new_loglevel; \ - char *endp; \ - \ - new_loglevel = simple_strtoul(buf, &endp, 0); \ - if ((endp + 1) < (buf + count)) \ - return -EINVAL; \ - if (new_loglevel > 3) \ - return -EINVAL; \ - down(&zfcp_data.config_sema); \ - loglevel = atomic_read(&zfcp_data.loglevel); \ - loglevel &= ~((unsigned int) 0xf << (ZFCP_LOG_AREA_##_define << 2)); \ - loglevel |= new_loglevel << (ZFCP_LOG_AREA_##_define << 2); \ - atomic_set(&zfcp_data.loglevel, loglevel); \ - up(&zfcp_data.config_sema); \ - return count; \ -} \ - \ -static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev, \ - char *buf) \ -{ \ - return sprintf(buf,"%d\n", (unsigned int) \ - ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \ -} \ - \ -static DRIVER_ATTR(loglevel_##_name, S_IWUSR | S_IRUGO, \ - zfcp_sysfs_loglevel_##_name##_show, \ - zfcp_sysfs_loglevel_##_name##_store); - -ZFCP_DEFINE_DRIVER_ATTR(other, OTHER); -ZFCP_DEFINE_DRIVER_ATTR(scsi, SCSI); -ZFCP_DEFINE_DRIVER_ATTR(fsf, FSF); -ZFCP_DEFINE_DRIVER_ATTR(config, CONFIG); -ZFCP_DEFINE_DRIVER_ATTR(cio, CIO); -ZFCP_DEFINE_DRIVER_ATTR(qdio, QDIO); -ZFCP_DEFINE_DRIVER_ATTR(erp, ERP); -ZFCP_DEFINE_DRIVER_ATTR(fc, FC); - -static ssize_t zfcp_sysfs_version_show(struct device_driver *dev, - char *buf) -{ - return sprintf(buf, "%s\n", zfcp_data.driver_version); -} - -static DRIVER_ATTR(version, S_IRUGO, zfcp_sysfs_version_show, NULL); - -static struct attribute *zfcp_driver_attrs[] = { - &driver_attr_loglevel_other.attr, - &driver_attr_loglevel_scsi.attr, - &driver_attr_loglevel_fsf.attr, - &driver_attr_loglevel_config.attr, - &driver_attr_loglevel_cio.attr, - &driver_attr_loglevel_qdio.attr, - &driver_attr_loglevel_erp.attr, - &driver_attr_loglevel_fc.attr, - &driver_attr_version.attr, - NULL -}; - -static struct attribute_group zfcp_driver_attr_group = { - .attrs = zfcp_driver_attrs, -}; - -struct attribute_group *zfcp_driver_attr_groups[] = { - &zfcp_driver_attr_group, - NULL, -}; - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c index 703c1b5cb602..438675f2978e 100644 --- a/drivers/s390/scsi/zfcp_sysfs_port.c +++ b/drivers/s390/scsi/zfcp_sysfs_port.c @@ -1,28 +1,13 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * sysfs attributes for zfcp port. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #include "zfcp_ext.h" -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG - /** * zfcp_sysfs_port_release - gets called when a struct device port is released * @dev: pointer to belonging device @@ -291,5 +276,3 @@ zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) if (!(flags & ZFCP_STATUS_PORT_WKA)) sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group); } - -#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c index 80fb2c2cf48a..587d9e3e12d2 100644 --- a/drivers/s390/scsi/zfcp_sysfs_unit.c +++ b/drivers/s390/scsi/zfcp_sysfs_unit.c @@ -1,28 +1,13 @@ /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver * - * (C) Copyright IBM Corp. 2002, 2006 + * sysfs interface for zfcp unit. * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright IBM Corporation 2002, 2008 */ #include "zfcp_ext.h" -#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG - /** * zfcp_sysfs_unit_release - gets called when a struct device unit is released * @dev: pointer to belonging device @@ -163,5 +148,3 @@ zfcp_sysfs_unit_remove_files(struct device *dev) { sysfs_remove_group(&dev->kobj, &zfcp_unit_attr_group); } - -#undef ZFCP_LOG_AREA -- cgit v1.2.3 From 85a82392fe6fe7620d8fe0eb694f926cefe62e1f Mon Sep 17 00:00:00 2001 From: Sven Schuetz Date: Tue, 10 Jun 2008 18:20:59 +0200 Subject: [SCSI] zfcp: Add port_state attribute to sysfs The sysfs attribute /sys/class/fc_host/hostX/port_state was not set by zfcp so far. Now, the appropriate members of the fc_function_template struct are set during its initialziation. The first is a boolean to show the port state. The second is a function pointer to the function zfcp_get_host_port_state, which reads the port state from our adapter status bits and calls fc_host_port_state with the approriate port state afterwards. Signed-off-by: Sven Schuetz Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_scsi.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index a96e5c3b9460..446fb1da25df 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -704,6 +704,23 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost) } } +static void zfcp_get_host_port_state(struct Scsi_Host *shost) +{ + struct zfcp_adapter *adapter = + (struct zfcp_adapter *)shost->hostdata[0]; + int status = atomic_read(&adapter->status); + + if ((status & ZFCP_STATUS_COMMON_RUNNING) && + !(status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)) + fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; + else if (status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) + fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; + else if (status & ZFCP_STATUS_COMMON_ERP_FAILED) + fc_host_port_state(shost) = FC_PORTSTATE_ERROR; + else + fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; +} + static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) { rport->dev_loss_tmo = timeout; @@ -726,6 +743,8 @@ struct fc_function_template zfcp_transport_functions = { .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, + .get_host_port_state = zfcp_get_host_port_state, + .show_host_port_state = 1, /* no functions registered for following dynamic attributes but directly set by LLDD */ .show_host_port_type = 1, -- cgit v1.2.3 From cc8c282963bd258a5bf49d3aa52675a4ae6d31f6 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 10 Jun 2008 18:21:00 +0200 Subject: [SCSI] zfcp: Automatically attach remote ports Automatically attach the remote ports in zfcp when the adapter is set online. This is done by querying all available ports from the FC namesever. The scan for remote ports is also triggered by RSCNs and can be triggered manually with the sysfs attribute 'port_rescan'. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 36 ++--- drivers/s390/scsi/zfcp_dbf.c | 4 + drivers/s390/scsi/zfcp_def.h | 5 + drivers/s390/scsi/zfcp_erp.c | 42 ++++-- drivers/s390/scsi/zfcp_ext.h | 4 +- drivers/s390/scsi/zfcp_fc.c | 248 +++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_fsf.c | 3 + drivers/s390/scsi/zfcp_sysfs_adapter.c | 25 ++++ 8 files changed, 336 insertions(+), 31 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 47739f4f6709..2bd80fdcceff 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -568,6 +568,19 @@ static void _zfcp_status_read_scheduler(struct work_struct *work) stat_work)); } +static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) +{ + struct zfcp_port *port; + + port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, + ZFCP_DID_DIRECTORY_SERVICE); + if (!port) + return -ENXIO; + zfcp_port_put(port); + + return 0; +} + /* * Enqueues an adapter at the end of the adapter list in the driver data. * All adapter internal structures are set up. @@ -648,6 +661,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) /* initialize lock of associated request queue */ rwlock_init(&adapter->req_q.lock); INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); + INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); /* mark adapter unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); @@ -673,6 +687,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) zfcp_data.adapters++; + zfcp_nameserver_enqueue(adapter); + goto out; generic_services_failed: @@ -704,6 +720,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) int retval = 0; unsigned long flags; + cancel_work_sync(&adapter->scan_work); cancel_work_sync(&adapter->stat_work); zfcp_adapter_scsi_unregister(adapter); device_unregister(&adapter->generic_services); @@ -816,13 +833,15 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, kfree(port); return NULL; } - port->d_id = d_id; port->sysfs_device.parent = &adapter->generic_services; } else { snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", wwpn); port->sysfs_device.parent = &adapter->ccw_device->dev; } + + port->d_id = d_id; + port->sysfs_device.release = zfcp_sysfs_port_release; dev_set_drvdata(&port->sysfs_device, port); @@ -873,21 +892,6 @@ zfcp_port_dequeue(struct zfcp_port *port) device_unregister(&port->sysfs_device); } -/* Enqueues a nameserver port */ -int -zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) -{ - struct zfcp_port *port; - - port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, - ZFCP_DID_DIRECTORY_SERVICE); - if (!port) - return -ENXIO; - zfcp_port_put(port); - - return 0; -} - void zfcp_sg_free_table(struct scatterlist *sg, int count) { int i; diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 7c72f502eb0f..3e9f0abb22f9 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -596,6 +596,10 @@ static const char *zfcp_rec_dbf_ids[] = { [145] = "recovery action being processed", [146] = "recovery action ready for next step", [147] = "qdio error inbound", + [148] = "nameserver needed for port scan", + [149] = "port scan", + [150] = "ptp attach", + [151] = "port validation failed", }; static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 73425dbb2be8..1e837d46ea74 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -282,7 +282,10 @@ struct zfcp_rc_entry { #define ZFCP_CT_DIRECTORY_SERVICE 0xFC #define ZFCP_CT_NAME_SERVER 0x02 #define ZFCP_CT_SYNCHRONOUS 0x00 +#define ZFCP_CT_SCSI_FCP 0x08 +#define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 #define ZFCP_CT_GID_PN 0x0121 +#define ZFCP_CT_GPN_FT 0x0172 #define ZFCP_CT_MAX_SIZE 0x1020 #define ZFCP_CT_ACCEPT 0x8002 #define ZFCP_CT_REJECT 0x8001 @@ -311,6 +314,7 @@ struct zfcp_rc_entry { #define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000 #define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000 #define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000 +#define ZFCP_STATUS_COMMON_NOESC 0x00200000 /* adapter status */ #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 @@ -629,6 +633,7 @@ struct zfcp_adapter { struct fc_host_statistics *fc_stats; struct fsf_qtcb_bottom_port *stats_reset_data; unsigned long stats_reset; + struct work_struct scan_work; }; /* diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c06156b288ea..9b9c999cf39f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1199,6 +1199,10 @@ zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) zfcp_erp_port_unblock(port); break; case ZFCP_ERP_FAILED : + if (atomic_test_mask(ZFCP_STATUS_COMMON_NOESC, &port->status)) { + zfcp_erp_port_block(port, 0); + result = ZFCP_ERP_EXIT; + } atomic_inc(&port->erp_counter); if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) zfcp_erp_port_failed(port, 22, NULL); @@ -1607,6 +1611,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) goto failed_openfcp; atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &erp_action->adapter->status); + schedule_work(&erp_action->adapter->scan_work); goto out; close_only: @@ -1665,10 +1670,19 @@ zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); } +static void zfcp_erp_open_ptp_port(struct zfcp_adapter *adapter) +{ + struct zfcp_port *port; + port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, + adapter->peer_d_id); + if (!port) /* error or port already attached */ + return; + zfcp_erp_port_reopen_internal(port, 0, 150, NULL); +} + static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) { - int retval = ZFCP_ERP_SUCCEEDED; int retries; int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP; struct zfcp_adapter *adapter = erp_action->adapter; @@ -1682,8 +1696,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) zfcp_erp_action_to_running(erp_action); write_unlock_irq(&adapter->erp_lock); if (zfcp_fsf_exchange_config_data(erp_action)) { - retval = ZFCP_ERP_FAILED; - break; + atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + &adapter->status); + return ZFCP_ERP_FAILED; } /* @@ -1719,9 +1734,12 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status)) - retval = ZFCP_ERP_FAILED; + return ZFCP_ERP_FAILED; - return retval; + if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) + zfcp_erp_open_ptp_port(adapter); + + return ZFCP_ERP_SUCCEEDED; } static int @@ -1899,14 +1917,12 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) retval = zfcp_erp_port_strategy_open_port(erp_action); break; } - if (!(adapter->nameserver_port)) { - retval = zfcp_nameserver_enqueue(adapter); - if (retval != 0) { - dev_err(&adapter->ccw_device->dev, - "Nameserver port unavailable.\n"); - retval = ZFCP_ERP_FAILED; - break; - } + + if (!adapter->nameserver_port) { + dev_err(&adapter->ccw_device->dev, + "Nameserver port unavailable.\n"); + retval = ZFCP_ERP_FAILED; + break; } if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->nameserver_port->status)) { diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 9aa412bd6637..c3b51338abfa 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -37,6 +37,8 @@ extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, extern void zfcp_port_dequeue(struct zfcp_port *); extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); extern void zfcp_unit_dequeue(struct zfcp_unit *); +extern int zfcp_scan_ports(struct zfcp_adapter *); +extern void _zfcp_scan_ports_later(struct work_struct *work); /******************************* S/390 IO ************************************/ extern int zfcp_ccw_register(void); @@ -97,8 +99,6 @@ extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); extern void zfcp_test_link(struct zfcp_port *); -extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); - /******************************* SCSI ****************************************/ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index bb07c3bf2258..aa2d9a668d17 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -8,6 +8,37 @@ #include "zfcp_ext.h" +struct ct_iu_gpn_ft_req { + struct ct_hdr header; + u8 flags; + u8 domain_id_scope; + u8 area_id_scope; + u8 fc4_type; +} __attribute__ ((packed)); + +struct gpn_ft_resp_acc { + u8 control; + u8 port_id[3]; + u8 reserved[4]; + u64 wwpn; +} __attribute__ ((packed)); + +#define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ + / sizeof(struct gpn_ft_resp_acc)) +#define ZFCP_GPN_FT_BUFFERS 4 +#define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) + +struct ct_iu_gpn_ft_resp { + struct ct_hdr header; + struct gpn_ft_resp_acc accept[ZFCP_GPN_FT_ENTRIES]; +} __attribute__ ((packed)); + +struct zfcp_gpn_ft { + struct zfcp_send_ct ct; + struct scatterlist sg_req; + struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS]; +}; + static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, struct fcp_rscn_element *elem) { @@ -68,6 +99,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) } _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); } + schedule_work(&fsf_req->adapter->scan_work); } static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) @@ -303,3 +335,219 @@ void zfcp_test_link(struct zfcp_port *port) zfcp_port_put(port); zfcp_erp_port_forced_reopen(port, 0, 65, NULL); } + +static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter) +{ + int ret; + + if (!adapter->nameserver_port) + return -EINTR; + + if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, + &adapter->nameserver_port->status)) { + ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148, + NULL); + if (ret) + return ret; + zfcp_erp_wait(adapter); + zfcp_port_put(adapter->nameserver_port); + } + return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, + &adapter->nameserver_port->status); +} + +static void zfcp_gpn_ft_handler(unsigned long _done) +{ + complete((struct completion *)_done); +} + +static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) +{ + struct scatterlist *sg = &gpn_ft->sg_req; + + kfree(sg_virt(sg)); /* free request buffer */ + zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); + + kfree(gpn_ft); +} + +static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) +{ + struct zfcp_gpn_ft *gpn_ft; + struct ct_iu_gpn_ft_req *req; + + gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL); + if (!gpn_ft) + return NULL; + + req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL); + if (!req) { + kfree(gpn_ft); + gpn_ft = NULL; + goto out; + } + sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); + + if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) { + zfcp_free_sg_env(gpn_ft); + gpn_ft = NULL; + } +out: + return gpn_ft; +} + + +static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, + struct zfcp_adapter *adapter) +{ + struct zfcp_send_ct *ct = &gpn_ft->ct; + struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); + struct completion done; + int ret; + + /* prepare CT IU for GPN_FT */ + req->header.revision = ZFCP_CT_REVISION; + req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; + req->header.gs_subtype = ZFCP_CT_NAME_SERVER; + req->header.options = ZFCP_CT_SYNCHRONOUS; + req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; + req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * + (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; + req->flags = 0; + req->domain_id_scope = 0; + req->area_id_scope = 0; + req->fc4_type = ZFCP_CT_SCSI_FCP; + + /* prepare zfcp_send_ct */ + ct->port = adapter->nameserver_port; + ct->handler = zfcp_gpn_ft_handler; + ct->handler_data = (unsigned long)&done; + ct->timeout = 10; + ct->req = &gpn_ft->sg_req; + ct->resp = gpn_ft->sg_resp; + ct->req_count = 1; + ct->resp_count = ZFCP_GPN_FT_BUFFERS; + + init_completion(&done); + ret = zfcp_fsf_send_ct(ct, NULL, NULL); + if (!ret) + wait_for_completion(&done); + return ret; +} + +static void zfcp_validate_port(struct zfcp_port *port) +{ + struct zfcp_adapter *adapter = port->adapter; + + atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); + + if (port == adapter->nameserver_port) + return; + if ((port->supported_classes != 0) || (port->units != 0)) { + zfcp_port_put(port); + return; + } + zfcp_erp_port_shutdown(port, 0, 151, NULL); + zfcp_erp_wait(adapter); + zfcp_port_put(port); + zfcp_port_dequeue(port); +} + +static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) +{ + struct zfcp_send_ct *ct = &gpn_ft->ct; + struct scatterlist *sg = gpn_ft->sg_resp; + struct ct_hdr *hdr = sg_virt(sg); + struct gpn_ft_resp_acc *acc = sg_virt(sg); + struct zfcp_adapter *adapter = ct->port->adapter; + struct zfcp_port *port, *tmp; + u32 d_id; + int ret = 0, x; + + if (ct->status) + return -EIO; + + if (hdr->cmd_rsp_code != ZFCP_CT_ACCEPT) { + if (hdr->reason_code == ZFCP_CT_UNABLE_TO_PERFORM_CMD) + return -EAGAIN; /* might be a temporary condition */ + return -EIO; + } + + if (hdr->max_res_size) + return -E2BIG; + + down(&zfcp_data.config_sema); + + /* first entry is the header */ + for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES; x++) { + if (x % (ZFCP_GPN_FT_ENTRIES + 1)) + acc++; + else + acc = sg_virt(++sg); + + d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 | + acc->port_id[2]; + + /* skip the adapter's port and known remote ports */ + if (acc->wwpn == fc_host_port_name(adapter->scsi_host) || + zfcp_get_port_by_did(adapter, d_id)) + continue; + + port = zfcp_port_enqueue(adapter, acc->wwpn, + ZFCP_STATUS_PORT_DID_DID | + ZFCP_STATUS_COMMON_NOESC, d_id); + if (port) + zfcp_erp_port_reopen(port, 0, 149, NULL); + else + ret = -ENOMEM; + if (acc->control & 0x80) /* last entry */ + break; + } + + zfcp_erp_wait(adapter); + list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list) + zfcp_validate_port(port); + up(&zfcp_data.config_sema); + return ret; +} + +/** + * zfcp_scan_ports - scan remote ports and attach new ports + * @adapter: pointer to struct zfcp_adapter + */ +int zfcp_scan_ports(struct zfcp_adapter *adapter) +{ + int ret, i; + struct zfcp_gpn_ft *gpn_ft; + + if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) + return 0; + + ret = zfcp_scan_get_nameserver(adapter); + if (ret) + return ret; + + gpn_ft = zfcp_alloc_sg_env(); + if (!gpn_ft) + return -ENOMEM; + + for (i = 0; i < 3; i++) { + ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); + if (!ret) { + ret = zfcp_scan_eval_gpn_ft(gpn_ft); + if (ret == -EAGAIN) + ssleep(1); + else + break; + } + } + zfcp_free_sg_env(gpn_ft); + + return ret; +} + + +void _zfcp_scan_ports_later(struct work_struct *work) +{ + zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); +} diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 01ed5fb46c44..243e792f2407 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -874,6 +874,9 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) if (status_buffer->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) zfcp_erp_adapter_access_changed(adapter, 135, fsf_req); + if (status_buffer->status_subtype & + FSF_STATUS_READ_SUB_INCOMING_ELS) + schedule_work(&adapter->scan_work); break; case FSF_STATUS_READ_CFDC_UPDATED: diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c index 1f2a8c21b731..a4cae60f69d4 100644 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c @@ -84,6 +84,30 @@ zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, con static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); +/** + * zfcp_sysfs_port_rescan - trigger manual port rescan + * @dev: pointer to belonging device + * @attr: pointer to struct device_attribute + * @buf: pointer to input buffer + * @count: number of bytes in buffer + */ +static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zfcp_adapter *adapter; + int ret; + + adapter = dev_get_drvdata(dev); + if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) + return -EBUSY; + + ret = zfcp_scan_ports(adapter); + + return ret ? ret : (ssize_t) count; +} +static DEVICE_ATTR(port_rescan, S_IWUSR, NULL, zfcp_sysfs_port_rescan_store); + /** * zfcp_sysfs_port_remove_store - remove a port from sysfs tree * @dev: pointer to belonging device @@ -214,6 +238,7 @@ static struct attribute *zfcp_adapter_attrs[] = { &dev_attr_in_recovery.attr, &dev_attr_port_remove.attr, &dev_attr_port_add.attr, + &dev_attr_port_rescan.attr, &dev_attr_peer_wwnn.attr, &dev_attr_peer_wwpn.attr, &dev_attr_peer_d_id.attr, -- cgit v1.2.3 From 235f7f25f4928f5075dbebdfb9ca2c5d90db882c Mon Sep 17 00:00:00 2001 From: Martin Peschke Date: Tue, 10 Jun 2008 18:21:01 +0200 Subject: [SCSI] zfcp: Remove sysfs attribute port_add With the automatic scanning of remote ports in place, there is no need to add remote ports manually. So, remove the port_add attribute. Signed-off-by: Martin Peschke Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_sysfs_adapter.c | 46 ---------------------------------- 1 file changed, 46 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c index a4cae60f69d4..3985f1f1c291 100644 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c @@ -39,51 +39,6 @@ ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n", ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)); -/** - * zfcp_sysfs_port_add_store - add a port to sysfs tree - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * @count: number of bytes in buffer - * - * Store function of the "port_add" attribute of an adapter. - */ -static ssize_t -zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - wwn_t wwpn; - char *endp; - struct zfcp_adapter *adapter; - struct zfcp_port *port; - int retval = -EINVAL; - - down(&zfcp_data.config_sema); - - adapter = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { - retval = -EBUSY; - goto out; - } - - wwpn = simple_strtoull(buf, &endp, 0); - if ((endp + 1) < (buf + count)) - goto out; - - port = zfcp_port_enqueue(adapter, wwpn, 0, 0); - if (!port) - goto out; - - retval = 0; - - zfcp_erp_port_reopen(port, 0, 91, NULL); - zfcp_erp_wait(port->adapter); - zfcp_port_put(port); - out: - up(&zfcp_data.config_sema); - return retval ? retval : (ssize_t) count; -} - -static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); - /** * zfcp_sysfs_port_rescan - trigger manual port rescan * @dev: pointer to belonging device @@ -237,7 +192,6 @@ static struct attribute *zfcp_adapter_attrs[] = { &dev_attr_failed.attr, &dev_attr_in_recovery.attr, &dev_attr_port_remove.attr, - &dev_attr_port_add.attr, &dev_attr_port_rescan.attr, &dev_attr_peer_wwnn.attr, &dev_attr_peer_wwpn.attr, -- cgit v1.2.3 From c57a39a45a76bc8ecdd2c8a9bc7cf7be3ed73fe1 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 2 Jul 2008 10:56:31 +0200 Subject: [SCSI] zfcp: wait until adapter is finished with ERP during auto-port In some situations the auto port attachment task is started before the ERP is finished. To prevent this unwanted situation we wait until the adapter is up and running before we start our work. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index aa2d9a668d17..34c9b20ce493 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -520,6 +520,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) int ret, i; struct zfcp_gpn_ft *gpn_ft; + zfcp_erp_wait(adapter); /* wait until adapter is finished with ERP */ if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) return 0; -- cgit v1.2.3 From 3968ce800f45d8795ceb6f186c1efe420c98e1b0 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 2 Jul 2008 10:56:32 +0200 Subject: [SCSI] zfcp: Fix error checking for ELS ADISC requests Correctly check the status for ELS ADISC requests. 0 means success. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 34c9b20ce493..5d9367d9a12d 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -263,7 +263,7 @@ static void zfcp_fc_adisc_handler(unsigned long data) struct zfcp_port *port = adisc->els.port; struct zfcp_ls_adisc_acc *ls_adisc = &adisc->ls_adisc_acc; - if (!adisc->els.status) { + if (adisc->els.status) { /* request rejected or timed out */ zfcp_erp_port_forced_reopen(port, 0, 63, NULL); goto out; -- cgit v1.2.3 From 7afe29f7dd6dccbe454d7fd6cd6a5a7f7bcbc530 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 2 Jul 2008 10:56:33 +0200 Subject: [SCSI] zfcp: Adapter reopen for large number of unsolicited status When zfcp receives 16 unsolicited status messages, this could trigger an adapter reopen. In this case, first try to send a new status read, and only if this fails, go through the recovery. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 15 +++++++-------- drivers/s390/scsi/zfcp_def.h | 3 +-- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 2bd80fdcceff..bfcd1ba28ae1 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -550,15 +550,14 @@ static void zfcp_dummy_release(struct device *dev) int zfcp_status_read_refill(struct zfcp_adapter *adapter) { while (atomic_read(&adapter->stat_miss) > 0) - if (zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL)) + if (zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL)) { + if (atomic_read(&adapter->stat_miss) >= 16) { + zfcp_erp_adapter_reopen(adapter, 0, 103, NULL); + return 1; + } break; - else - atomic_dec(&adapter->stat_miss); - - if (ZFCP_STATUS_READS_RECOM <= atomic_read(&adapter->stat_miss)) { - zfcp_erp_adapter_reopen(adapter, 0, 103, NULL); - return 1; - } + } else + atomic_dec(&adapter->stat_miss); return 0; } diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 1e837d46ea74..202f7e66c446 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -108,7 +108,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) #define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION /* ATTENTION: value must not be used by hardware */ #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 -#define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM /* Do 1st retry in 1 second, then double the timeout for each following retry */ #define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 1 @@ -743,7 +742,7 @@ struct zfcp_data { #define ZFCP_POOL_FSF_REQ_ERP_NR 1 #define ZFCP_POOL_FSF_REQ_SCSI_NR 1 #define ZFCP_POOL_FSF_REQ_ABORT_NR 1 -#define ZFCP_POOL_STATUS_READ_NR ZFCP_STATUS_READS_RECOM +#define ZFCP_POOL_STATUS_READ_NR FSF_STATUS_READS_RECOM #define ZFCP_POOL_DATA_GID_PN_NR 1 /* struct used by memory pools for fsf_requests */ -- cgit v1.2.3 From 5d4e226246331087799a01c267ec72e5931ff190 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 2 Jul 2008 10:56:34 +0200 Subject: [SCSI] zfcp: Small QDIO cleanups QBUFF_PER_PAGE is only used inside the qdio module, so move it to zfcp_qdio.c zfcp_qdio_zero_sbals is now only used in the qdio module, so make it static. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 2 -- drivers/s390/scsi/zfcp_ext.h | 1 - drivers/s390/scsi/zfcp_qdio.c | 27 +++++++++++---------------- 3 files changed, 11 insertions(+), 19 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 202f7e66c446..e8383b7331b4 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -100,8 +100,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) #define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */ -#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) - /********************* FSF SPECIFIC DEFINES *********************************/ #define ZFCP_ULP_INFO_VERSION 26 diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index c3b51338abfa..368b304d1e3f 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -43,7 +43,6 @@ extern void _zfcp_scan_ports_later(struct work_struct *work); /******************************* S/390 IO ************************************/ extern int zfcp_ccw_register(void); -extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int); extern int zfcp_qdio_allocate(struct zfcp_adapter *); extern void zfcp_qdio_free(struct zfcp_adapter *); extern int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index bd6561d53589..b8ed42bb5c9e 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -11,6 +11,7 @@ /* FIXME(tune): free space should be one max. SBAL chain plus what? */ #define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ - (ZFCP_MAX_SBALS_PER_REQ + 4)) +#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) { @@ -63,6 +64,16 @@ static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, u8 id) ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); } +static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) +{ + int i, sbal_idx; + + for (i = first; i < first + cnt; i++) { + sbal_idx = i % QDIO_MAX_BUFFERS_PER_Q; + memset(sbal[sbal_idx], 0, sizeof(struct qdio_buffer)); + } +} + static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int status, unsigned int qdio_err, unsigned int siga_err, unsigned int queue_no, int first, int count, @@ -365,22 +376,6 @@ int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req) return 0; } -/** - * zfcp_qdio_zero_sbals - zero all sbals of the specified area and queue - * @buf: pointer to array of SBALS - * @first: integer specifying the SBAL number to start - * @count: integer specifying the number of SBALS to process - */ -void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int count) -{ - int i, sbal_idx; - - for (i = first; i < first + count; i++) { - sbal_idx = i % QDIO_MAX_BUFFERS_PER_Q; - memset(sbal[sbal_idx], 0, sizeof(struct qdio_buffer)); - } -} - /** * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data * @adapter: pointer to struct zfcp_adapter -- cgit v1.2.3 From feac6a07c4a3578bffd6769bb4927e8a7e1f3ffe Mon Sep 17 00:00:00 2001 From: Martin Petermann Date: Wed, 2 Jul 2008 10:56:35 +0200 Subject: [SCSI] zfcp: Move status accessors from zfcp to SCSI include file. Move the accessor functions for the scsi_cmnd status from zfcp to the SCSI include file. Change the interface to the functions to pass the scsi_cmnd pointer instead of the status pointer. Signed-off-by: Martin Petermann Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ext.h | 2 -- drivers/s390/scsi/zfcp_fsf.c | 20 ++++++++++---------- drivers/s390/scsi/zfcp_scsi.c | 24 +----------------------- include/scsi/scsi.h | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 35 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 368b304d1e3f..f95dc99339fd 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -103,8 +103,6 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *); -extern void set_host_byte(int *, char); -extern void set_driver_byte(int *, char); extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 243e792f2407..150e78dd00b2 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -3040,18 +3040,18 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) * DID_SOFT_ERROR by retrying the request for devices * that allow retries. */ - set_host_byte(&scpnt->result, DID_SOFT_ERROR); - set_driver_byte(&scpnt->result, SUGGEST_RETRY); + set_host_byte(scpnt, DID_SOFT_ERROR); + set_driver_byte(scpnt, SUGGEST_RETRY); goto skip_fsfstatus; } if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { - set_host_byte(&scpnt->result, DID_ERROR); + set_host_byte(scpnt, DID_ERROR); goto skip_fsfstatus; } /* set message byte of result in SCSI command */ - scpnt->result |= COMMAND_COMPLETE << 8; + set_msg_byte(scpnt, COMMAND_COMPLETE); /* * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte @@ -3067,23 +3067,23 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) switch (fcp_rsp_info[3]) { case RSP_CODE_GOOD: /* ok, continue */ - set_host_byte(&scpnt->result, DID_OK); + set_host_byte(scpnt, DID_OK); break; case RSP_CODE_LENGTH_MISMATCH: /* hardware bug */ - set_host_byte(&scpnt->result, DID_ERROR); + set_host_byte(scpnt, DID_ERROR); goto skip_fsfstatus; case RSP_CODE_FIELD_INVALID: /* driver or hardware bug */ - set_host_byte(&scpnt->result, DID_ERROR); + set_host_byte(scpnt, DID_ERROR); goto skip_fsfstatus; case RSP_CODE_RO_MISMATCH: /* hardware bug */ - set_host_byte(&scpnt->result, DID_ERROR); + set_host_byte(scpnt, DID_ERROR); goto skip_fsfstatus; default: /* invalid FCP response code */ - set_host_byte(&scpnt->result, DID_ERROR); + set_host_byte(scpnt, DID_ERROR); goto skip_fsfstatus; } } @@ -3104,7 +3104,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < scpnt->underflow) - set_host_byte(&scpnt->result, DID_ERROR); + set_host_byte(scpnt, DID_ERROR); } skip_fsfstatus: diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 446fb1da25df..160307382d2c 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -107,28 +107,6 @@ zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) *zfcp_get_fcp_dl_ptr(fcp_cmd) = fcp_dl; } -/* - * note: it's a bit-or operation not an assignment - * regarding the specified byte - */ -static inline void -set_byte(int *result, char status, char pos) -{ - *result |= status << (pos * 8); -} - -void -set_host_byte(int *result, char status) -{ - set_byte(result, status, 2); -} - -void -set_driver_byte(int *result, char status) -{ - set_byte(result, status, 3); -} - static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) { @@ -196,7 +174,7 @@ zfcp_scsi_slave_configure(struct scsi_device *sdp) static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) { - set_host_byte(&scpnt->result, result); + 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], diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 2b5b9356c314..00137a7769ee 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -9,6 +9,7 @@ #define _SCSI_SCSI_H #include +#include /* * The maximum number of SG segments that we will put inside a @@ -425,6 +426,22 @@ struct scsi_lun { #define driver_byte(result) (((result) >> 24) & 0xff) #define suggestion(result) (driver_byte(result) & SUGGEST_MASK) +static inline void set_msg_byte(struct scsi_cmnd *cmd, char status) +{ + cmd->result |= status << 8; +} + +static inline void set_host_byte(struct scsi_cmnd *cmd, char status) +{ + cmd->result |= status << 16; +} + +static inline void set_driver_byte(struct scsi_cmnd *cmd, char status) +{ + cmd->result |= status << 24; +} + + #define sense_class(sense) (((sense) >> 4) & 0x7) #define sense_error(sense) ((sense) & 0xf) #define sense_valid(sense) ((sense) & 0x80); -- cgit v1.2.3 From f76af7d7e36373179be7a9e09f6b0aae330549b7 Mon Sep 17 00:00:00 2001 From: Martin Petermann Date: Wed, 2 Jul 2008 10:56:36 +0200 Subject: [SCSI] zfcp: Cleanup of code in zfcp_scsi.c Cleanup code in zfcp_scsi.c, fix coding style issues and simplify the code. Signed-off-by: Martin Petermann Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 3 +- drivers/s390/scsi/zfcp_def.h | 6 - drivers/s390/scsi/zfcp_ext.h | 5 - drivers/s390/scsi/zfcp_fsf.c | 4 +- drivers/s390/scsi/zfcp_scsi.c | 555 ++++++++++++++---------------------------- 5 files changed, 184 insertions(+), 389 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 3e9f0abb22f9..566627f3a69d 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -1065,8 +1065,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, if (fsf_req != NULL) { fcp_rsp = (struct fcp_rsp_iu *) &(fsf_req->qtcb->bottom.io.fcp_rsp); - fcp_rsp_info = - zfcp_get_fcp_rsp_info_ptr(fcp_rsp); + fcp_rsp_info = (unsigned char *) &fcp_rsp[1]; fcp_sns_info = zfcp_get_fcp_sns_info_ptr(fcp_rsp); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index e8383b7331b4..7ac830c39098 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -126,12 +126,6 @@ typedef unsigned int fcp_dl_t; /* timeout for name-server lookup (in seconds) */ #define ZFCP_NS_GID_PN_TIMEOUT 10 -/* largest SCSI command we can process */ -/* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */ -#define ZFCP_MAX_SCSI_CMND_LENGTH 255 -/* maximum number of commands in LUN queue (tagged queueing) */ -#define ZFCP_CMND_PER_LUN 32 - /* task attribute values in FCP-2 FCP_CMND IU */ #define SIMPLE_Q 0 #define HEAD_OF_Q 1 diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index f95dc99339fd..892476c17ff2 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -102,13 +102,8 @@ extern void zfcp_test_link(struct zfcp_port *); extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); -extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *); extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); -extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); -extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *, - struct scsi_cmnd *, int); -extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *, int); extern struct fc_function_template zfcp_transport_functions; /******************************** ERP ****************************************/ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 150e78dd00b2..22e3aa612786 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -3027,7 +3027,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) &(fsf_req->qtcb->bottom.io.fcp_rsp); u32 sns_len; - char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); + char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; unsigned long flags; read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); @@ -3145,7 +3145,7 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) int retval = 0; struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) &(fsf_req->qtcb->bottom.io.fcp_rsp); - char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); + char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 160307382d2c..f8594a2e3f5c 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -9,137 +9,32 @@ #include "zfcp_ext.h" #include -static void zfcp_scsi_slave_destroy(struct scsi_device *sdp); -static int zfcp_scsi_slave_alloc(struct scsi_device *sdp); -static int zfcp_scsi_slave_configure(struct scsi_device *sdp); -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_target_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 device_attribute *zfcp_sysfs_sdev_attrs[]; -static struct device_attribute *zfcp_a_stats_attrs[]; - -struct zfcp_data zfcp_data = { - .scsi_host_template = { - .name = "zfcp", - .module = THIS_MODULE, - .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_target_reset_handler = zfcp_scsi_eh_target_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, - .max_sectors = ZFCP_MAX_SECTORS, - .shost_attrs = zfcp_a_stats_attrs, - }, -}; - -/* Find start of Response Information in FCP response unit*/ -char * -zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) -{ - char *fcp_rsp_info_ptr; - - fcp_rsp_info_ptr = - (unsigned char *) fcp_rsp_iu + (sizeof (struct fcp_rsp_iu)); - - return fcp_rsp_info_ptr; -} - /* Find start of Sense Information in FCP response unit*/ -char * -zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) +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 + (sizeof (struct fcp_rsp_iu)); + fcp_sns_info_ptr = (unsigned char *) &fcp_rsp_iu[1]; if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) - fcp_sns_info_ptr = (char *) fcp_sns_info_ptr + - fcp_rsp_iu->fcp_rsp_len; + fcp_sns_info_ptr += fcp_rsp_iu->fcp_rsp_len; return fcp_sns_info_ptr; } -static fcp_dl_t * -zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd) +void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) { - int additional_length = fcp_cmd->add_fcp_cdb_length << 2; - fcp_dl_t *fcp_dl_addr; + fcp_dl_t *fcp_dl_ptr; - fcp_dl_addr = (fcp_dl_t *) - ((unsigned char *) fcp_cmd + - sizeof (struct fcp_cmnd_iu) + additional_length); /* * fcp_dl_addr = start address of fcp_cmnd structure + * size of fixed part + size of dynamically sized add_dcp_cdb field * SEE FCP-2 documentation */ - return fcp_dl_addr; -} - -fcp_dl_t -zfcp_get_fcp_dl(struct fcp_cmnd_iu * fcp_cmd) -{ - return *zfcp_get_fcp_dl_ptr(fcp_cmd); -} - -void -zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) -{ - *zfcp_get_fcp_dl_ptr(fcp_cmd) = fcp_dl; -} - -static int -zfcp_scsi_slave_alloc(struct scsi_device *sdp) -{ - struct zfcp_adapter *adapter; - struct zfcp_unit *unit; - unsigned long flags; - int retval = -ENXIO; - - 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); - if (unit && atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED, - &unit->status)) { - sdp->hostdata = unit; - unit->device = sdp; - zfcp_unit_get(unit); - retval = 0; - } - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - out: - return retval; + fcp_dl_ptr = (fcp_dl_t *) ((unsigned char *) &fcp_cmd[1] + + (fcp_cmd->add_fcp_cdb_length << 2)); + *fcp_dl_ptr = fcp_dl; } -/** - * zfcp_scsi_slave_destroy - called when scsi device is removed - * - * 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. - */ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) { struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; @@ -153,26 +48,16 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) } } -/* - * called from scsi midlayer to allow finetuning of a device. - */ -static int -zfcp_scsi_slave_configure(struct scsi_device *sdp) +static int zfcp_scsi_slave_configure(struct scsi_device *sdp) { if (sdp->tagged_supported) - scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, ZFCP_CMND_PER_LUN); + scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32); else scsi_adjust_queue_depth(sdp, 0, 1); return 0; } -/** - * zfcp_scsi_command_fail - set result in scsi_cmnd and call scsi_done function - * @scpnt: pointer to struct scsi_cmnd where result is set - * @result: result to be set in scpnt (e.g. DID_ERROR) - */ -static void -zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) +static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) { set_host_byte(scpnt, result); if ((scpnt->device != NULL) && (scpnt->device->host != NULL)) @@ -183,104 +68,13 @@ zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) scpnt->scsi_done(scpnt); } -/** - * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and - * zfcp_scsi_command_sync - * @adapter: adapter where scsi command is issued - * @unit: unit to which scsi command is sent - * @scpnt: scsi command to be sent - * @timer: timer to be started if request is successfully initiated - * - * Note: In scsi_done function must be set in scpnt. - */ -int -zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, - struct scsi_cmnd *scpnt, int use_timer) -{ - int tmp; - int retval; - - retval = 0; - - BUG_ON((adapter == NULL) || (adapter != unit->port->adapter)); - BUG_ON(scpnt->scsi_done == NULL); - - if (unlikely(NULL == unit)) { - zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); - goto out; - } - - if (unlikely( - atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) || - !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) { - zfcp_scsi_command_fail(scpnt, DID_ERROR); - goto out; - } - - tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer, - ZFCP_REQ_AUTO_CLEANUP); - if (unlikely(tmp == -EBUSY)) { - zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); - goto out; - } - - if (unlikely(tmp < 0)) - retval = SCSI_MLQUEUE_HOST_BUSY; - -out: - return retval; -} - -static void -zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt) -{ - struct completion *wait = (struct completion *) scpnt->SCp.ptr; - complete(wait); -} - - -/** - * zfcp_scsi_command_sync - send a SCSI command and wait for completion - * @unit: unit where command is sent to - * @scpnt: scsi command to be sent - * @use_timer: indicates whether timer should be setup or not - * Return: 0 - * - * Errors are indicated in scpnt->result - */ -int -zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt, - int use_timer) -{ - int ret; - DECLARE_COMPLETION_ONSTACK(wait); - - scpnt->SCp.ptr = (void *) &wait; /* silent re-use */ - scpnt->scsi_done = zfcp_scsi_command_sync_handler; - ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt, - use_timer); - if (ret == 0) - wait_for_completion(&wait); - - scpnt->SCp.ptr = NULL; - - return 0; -} - -/* - * function: zfcp_scsi_queuecommand - * - * purpose: enqueues a SCSI command to the specified target device - * - * returns: 0 - success, SCSI command enqueued - * !0 - failure - */ -static int -zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, - void (*done) (struct scsi_cmnd *)) +static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, + void (*done) (struct scsi_cmnd *)) { struct zfcp_unit *unit; struct zfcp_adapter *adapter; + int status; + int ret; /* reset the status for this request */ scpnt->result = 0; @@ -292,44 +86,76 @@ zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, * (stored there by zfcp_scsi_slave_alloc) */ adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; - unit = (struct zfcp_unit *) scpnt->device->hostdata; + 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; + } + + status = atomic_read(&unit->status); + if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || + !(status & ZFCP_STATUS_COMMON_RUNNING))) { + zfcp_scsi_command_fail(scpnt, DID_ERROR); + return 0;; + } + + ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, + ZFCP_REQ_AUTO_CLEANUP); + if (unlikely(ret == -EBUSY)) + zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); + else if (unlikely(ret < 0)) + return SCSI_MLQUEUE_HOST_BUSY; - return zfcp_scsi_command_async(adapter, unit, scpnt, 0); + return ret; } -static struct zfcp_unit * -zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id, - unsigned int lun) +static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter, + int channel, unsigned int id, + unsigned int lun) { struct zfcp_port *port; - struct zfcp_unit *unit, *retval = NULL; + struct zfcp_unit *unit; list_for_each_entry(port, &adapter->port_list_head, list) { if (!port->rport || (id != port->rport->scsi_target_id)) continue; list_for_each_entry(unit, &port->unit_list_head, list) - if (lun == unit->scsi_lun) { - retval = unit; - goto out; - } + if (lun == unit->scsi_lun) + return unit; } - out: + + return NULL; +} + +static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) +{ + struct zfcp_adapter *adapter; + struct zfcp_unit *unit; + unsigned long flags; + int retval = -ENXIO; + + 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); + if (unit && + (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_REGISTERED)) { + sdp->hostdata = unit; + unit->device = sdp; + zfcp_unit_get(unit); + retval = 0; + } + read_unlock_irqrestore(&zfcp_data.config_lock, flags); +out: return retval; } -/** - * zfcp_scsi_eh_abort_handler - abort the specified SCSI command - * @scpnt: pointer to scsi_cmnd to be aborted - * Return: SUCCESS - command has been aborted and cleaned up in internal - * bookkeeping, SCSI stack won't be called for aborted command - * FAILED - otherwise - * - * We do not need to care for a SCSI command which completes normally - * but late during this abort routine runs. We are allowed to return - * late commands to the SCSI stack. It tracks the state of commands and - * will handle late commands. (Usually, the normal completion of late - * commands is ignored with respect to the running abort operation.) - */ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) { struct Scsi_Host *scsi_host; @@ -337,30 +163,27 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) struct zfcp_unit *unit; struct zfcp_fsf_req *fsf_req; unsigned long flags; - unsigned long old_req_id; + unsigned long old_req_id = (unsigned long) scpnt->host_scribble; int retval = SUCCESS; scsi_host = scpnt->device->host; adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; - unit = (struct zfcp_unit *) scpnt->device->hostdata; + unit = scpnt->device->hostdata; /* avoid race condition between late normal completion and abort */ write_lock_irqsave(&adapter->abort_lock, flags); /* Check whether corresponding fsf_req is still pending */ spin_lock(&adapter->req_list_lock); - fsf_req = zfcp_reqlist_find(adapter, - (unsigned long) scpnt->host_scribble); + fsf_req = zfcp_reqlist_find(adapter, old_req_id); spin_unlock(&adapter->req_list_lock); if (!fsf_req) { write_unlock_irqrestore(&adapter->abort_lock, flags); zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); - retval = SUCCESS; - goto out; + return retval; } fsf_req->data = 0; fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; - old_req_id = fsf_req->req_id; /* don't access old fsf_req after releasing the abort_lock */ write_unlock_irqrestore(&adapter->abort_lock, flags); @@ -370,7 +193,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, old_req_id); retval = FAILED; - goto out; + return retval; } __wait_event(fsf_req->completion_wq, @@ -378,62 +201,30 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); - retval = SUCCESS; } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); - retval = SUCCESS; } else { zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); retval = FAILED; } zfcp_fsf_req_free(fsf_req); - out: - return retval; -} - -static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) -{ - int retval; - struct zfcp_unit *unit = scpnt->device->hostdata; - if (!unit) { - WARN_ON(1); - return SUCCESS; - } - retval = zfcp_task_management_function(unit, - FCP_LOGICAL_UNIT_RESET, - scpnt); - return retval ? FAILED : SUCCESS; -} - -static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) -{ - int retval; - struct zfcp_unit *unit = scpnt->device->hostdata; - - if (!unit) { - WARN_ON(1); - return SUCCESS; - } - retval = zfcp_task_management_function(unit, FCP_TARGET_RESET, scpnt); - return retval ? FAILED : SUCCESS; + return retval; } -static int -zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, - struct scsi_cmnd *scpnt) +static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, + struct scsi_cmnd *scpnt) { struct zfcp_adapter *adapter = unit->port->adapter; struct zfcp_fsf_req *fsf_req; - int retval = 0; + int retval = SUCCESS; /* issue task management function */ fsf_req = zfcp_fsf_send_fcp_command_task_management (adapter, unit, tm_flags, 0); if (!fsf_req) { zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); - retval = -ENOMEM; - goto out; + return FAILED; } __wait_event(fsf_req->completion_wq, @@ -444,27 +235,46 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, */ if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); - retval = -EIO; + retval = FAILED; } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt); - retval = -ENOTSUPP; + retval = FAILED; } else zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); zfcp_fsf_req_free(fsf_req); - out: + return retval; } -/** - * zfcp_scsi_eh_host_reset_handler - handler for host reset - */ +static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) +{ + struct zfcp_unit *unit = scpnt->device->hostdata; + + if (!unit) { + WARN_ON(1); + return SUCCESS; + } + return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt); +} + +static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) +{ + struct zfcp_unit *unit = scpnt->device->hostdata; + + if (!unit) { + WARN_ON(1); + return SUCCESS; + } + return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt); +} + static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_unit *unit; struct zfcp_adapter *adapter; - unit = (struct zfcp_unit*) scpnt->device->hostdata; + unit = scpnt->device->hostdata; adapter = unit->port->adapter; zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); zfcp_erp_wait(adapter); @@ -472,51 +282,43 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) return SUCCESS; } -int -zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) +int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) { - int retval = 0; - static unsigned int unique_id = 0; + struct ccw_dev_id dev_id; if (adapter->scsi_host) - goto out; + return 0; + ccw_device_get_id(adapter->ccw_device, &dev_id); /* register adapter as SCSI host with mid layer of SCSI stack */ adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template, sizeof (struct zfcp_adapter *)); if (!adapter->scsi_host) { dev_err(&adapter->ccw_device->dev, "registration with SCSI stack failed."); - retval = -EIO; - goto out; + return -EIO; } /* tell the SCSI stack some characteristics of this adapter */ adapter->scsi_host->max_id = 1; adapter->scsi_host->max_lun = 1; adapter->scsi_host->max_channel = 0; - adapter->scsi_host->unique_id = unique_id++; /* FIXME */ - adapter->scsi_host->max_cmd_len = ZFCP_MAX_SCSI_CMND_LENGTH; + adapter->scsi_host->unique_id = dev_id.devno; + adapter->scsi_host->max_cmd_len = 255; adapter->scsi_host->transportt = zfcp_data.scsi_transport_template; - /* - * save a pointer to our own adapter data structure within - * hostdata field of SCSI host data structure - */ adapter->scsi_host->hostdata[0] = (unsigned long) adapter; if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { scsi_host_put(adapter->scsi_host); - retval = -EIO; - goto out; + return -EIO; } atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); - out: - return retval; + + return 0; } -void -zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) +void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) { struct Scsi_Host *shost; struct zfcp_port *port; @@ -524,10 +326,12 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) shost = adapter->scsi_host; 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_unlock_irq(&zfcp_data.config_lock); fc_remove_host(shost); scsi_remove_host(shost); @@ -538,9 +342,6 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) return; } -/* - * Support functions for FC transport class - */ static struct fc_host_statistics* zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) { @@ -556,13 +357,12 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) return adapter->fc_stats; } -static void -zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, - struct fsf_qtcb_bottom_port *data, - struct fsf_qtcb_bottom_port *old) +static void zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, + struct fsf_qtcb_bottom_port *data, + struct fsf_qtcb_bottom_port *old) { - fc_stats->seconds_since_last_reset = data->seconds_since_last_reset - - old->seconds_since_last_reset; + fc_stats->seconds_since_last_reset = + data->seconds_since_last_reset - old->seconds_since_last_reset; fc_stats->tx_frames = data->tx_frames - old->tx_frames; fc_stats->tx_words = data->tx_words - old->tx_words; fc_stats->rx_frames = data->rx_frames - old->rx_frames; @@ -573,26 +373,25 @@ zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames; fc_stats->link_failure_count = data->link_failure - old->link_failure; fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync; - fc_stats->loss_of_signal_count = data->loss_of_signal - - old->loss_of_signal; - fc_stats->prim_seq_protocol_err_count = data->psp_error_counts - - old->psp_error_counts; - fc_stats->invalid_tx_word_count = data->invalid_tx_words - - old->invalid_tx_words; + fc_stats->loss_of_signal_count = + data->loss_of_signal - old->loss_of_signal; + fc_stats->prim_seq_protocol_err_count = + data->psp_error_counts - old->psp_error_counts; + fc_stats->invalid_tx_word_count = + data->invalid_tx_words - old->invalid_tx_words; fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs; - fc_stats->fcp_input_requests = data->input_requests - - old->input_requests; - fc_stats->fcp_output_requests = data->output_requests - - old->output_requests; - fc_stats->fcp_control_requests = data->control_requests - - old->control_requests; + fc_stats->fcp_input_requests = + data->input_requests - old->input_requests; + fc_stats->fcp_output_requests = + data->output_requests - old->output_requests; + fc_stats->fcp_control_requests = + data->control_requests - old->control_requests; fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb; fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; } -static void -zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, - struct fsf_qtcb_bottom_port *data) +static void zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, + struct fsf_qtcb_bottom_port *data) { fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; fc_stats->tx_frames = data->tx_frames; @@ -616,22 +415,14 @@ zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, fc_stats->fcp_output_megabytes = data->output_mb; } -/** - * zfcp_get_fc_host_stats - provide fc_host_statistics for scsi_transport_fc - * - * assumption: scsi_transport_fc synchronizes calls of - * get_fc_host_stats and reset_fc_host_stats - * (XXX to be checked otherwise introduce locking) - */ -static struct fc_host_statistics * -zfcp_get_fc_host_stats(struct Scsi_Host *shost) +static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host) { struct zfcp_adapter *adapter; struct fc_host_statistics *fc_stats; struct fsf_qtcb_bottom_port *data; int ret; - adapter = (struct zfcp_adapter *)shost->hostdata[0]; + adapter = (struct zfcp_adapter *)host->hostdata[0]; fc_stats = zfcp_init_fc_host_stats(adapter); if (!fc_stats) return NULL; @@ -643,26 +434,25 @@ zfcp_get_fc_host_stats(struct Scsi_Host *shost) ret = zfcp_fsf_exchange_port_data_sync(adapter, data); if (ret) { kfree(data); - return NULL; /* XXX return zeroed fc_stats? */ + return NULL; } if (adapter->stats_reset && ((jiffies/HZ - adapter->stats_reset) < - data->seconds_since_last_reset)) { + data->seconds_since_last_reset)) zfcp_adjust_fc_host_stats(fc_stats, data, adapter->stats_reset_data); - } else + else zfcp_set_fc_host_stats(fc_stats, data); kfree(data); return fc_stats; } -static void -zfcp_reset_fc_host_stats(struct Scsi_Host *shost) +static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) { struct zfcp_adapter *adapter; - struct fsf_qtcb_bottom_port *data, *old_data; + struct fsf_qtcb_bottom_port *data; int ret; adapter = (struct zfcp_adapter *)shost->hostdata[0]; @@ -671,14 +461,13 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost) return; ret = zfcp_fsf_exchange_port_data_sync(adapter, data); - if (ret) { + if (ret) kfree(data); - } else { + else { adapter->stats_reset = jiffies/HZ; - old_data = adapter->stats_reset_data; + kfree(adapter->stats_reset_data); adapter->stats_reset_data = data; /* finally freed in - adater_dequeue */ - kfree(old_data); + adapter_dequeue */ } } @@ -793,14 +582,6 @@ ZFCP_DEFINE_LATENCY_ATTR(read); ZFCP_DEFINE_LATENCY_ATTR(write); ZFCP_DEFINE_LATENCY_ATTR(cmd); -/** - * ZFCP_DEFINE_SCSI_ATTR - * @_name: name of show attribute - * @_format: format string - * @_value: value to print - * - * Generates attribute for a unit. - */ #define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -815,7 +596,8 @@ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, struct device_ \ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); -ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", zfcp_get_busid_by_unit(unit)); +ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", + unit->port->adapter->ccw_device->dev.bus_id); ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); @@ -835,8 +617,8 @@ static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, { struct Scsi_Host *scsi_host = dev_to_shost(dev); struct fsf_qtcb_bottom_port *qtcb_port; - int retval; struct zfcp_adapter *adapter; + int retval; adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) @@ -857,17 +639,17 @@ static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, static int zfcp_sysfs_adapter_ex_config(struct device *dev, struct fsf_statistics_info *stat_inf) { - int retval; - struct fsf_qtcb_bottom_config *qtcb_config; struct Scsi_Host *scsi_host = dev_to_shost(dev); + struct fsf_qtcb_bottom_config *qtcb_config; struct zfcp_adapter *adapter; + int retval; adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) return -EOPNOTSUPP; qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), - GFP_KERNEL); + GFP_KERNEL); if (!qtcb_config) return -ENOMEM; @@ -940,3 +722,28 @@ static struct device_attribute *zfcp_a_stats_attrs[] = { &dev_attr_seconds_active, NULL }; + +struct zfcp_data zfcp_data = { + .scsi_host_template = { + .name = "zfcp", + .module = THIS_MODULE, + .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_target_reset_handler = zfcp_scsi_eh_target_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, + .max_sectors = (ZFCP_MAX_SBALES_PER_REQ * 8), + .shost_attrs = zfcp_a_stats_attrs, + }, +}; + -- cgit v1.2.3 From 317e6b6519b5a34263a33f150ed57ad468b26a64 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 2 Jul 2008 10:56:37 +0200 Subject: [SCSI] zfcp: Cleanup of code in zfcp_aux.c Overall cleanup of zfcp_aux.c to simplify code and follow kernel coding style. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 583 ++++++++++++++---------------------- drivers/s390/scsi/zfcp_ccw.c | 4 +- drivers/s390/scsi/zfcp_def.h | 13 - drivers/s390/scsi/zfcp_erp.c | 2 +- drivers/s390/scsi/zfcp_ext.h | 4 +- drivers/s390/scsi/zfcp_fc.c | 18 +- drivers/s390/scsi/zfcp_sysfs_port.c | 2 +- 7 files changed, 238 insertions(+), 388 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index bfcd1ba28ae1..7777729419eb 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -29,48 +29,14 @@ #include "zfcp_ext.h" static char *device; -/*********************** FUNCTION PROTOTYPES *********************************/ - -/* written against the module interface */ -static int __init zfcp_module_init(void); - -/*********************** KERNEL/MODULE PARAMETERS ***************************/ - -/* declare driver module init/cleanup functions */ -module_init(zfcp_module_init); MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); -MODULE_DESCRIPTION - ("FCP (SCSI over Fibre Channel) HBA driver for IBM System z9 and zSeries"); +MODULE_DESCRIPTION("FCP HBA driver"); MODULE_LICENSE("GPL"); module_param(device, charp, 0400); MODULE_PARM_DESC(device, "specify initial device"); -/****************************************************************/ -/************** Functions without logging ***********************/ -/****************************************************************/ - -void -_zfcp_hex_dump(char *addr, int count) -{ - int i; - for (i = 0; i < count; i++) { - printk("%02x", addr[i]); - if ((i % 4) == 3) - printk(" "); - if ((i % 32) == 31) - printk("\n"); - } - if (((i-1) % 32) != 31) - printk("\n"); -} - - -/****************************************************************/ -/****** Functions to handle the request ID hash table ********/ -/****************************************************************/ - static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) { int idx; @@ -85,11 +51,12 @@ static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) return 0; } -static void zfcp_reqlist_free(struct zfcp_adapter *adapter) -{ - kfree(adapter->req_list); -} - +/** + * zfcp_reqlist_isempty - is the request list empty + * @adapter: pointer to struct zfcp_adapter + * + * Returns: true if list is empty, false otherwise + */ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) { unsigned int idx; @@ -100,62 +67,58 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) return 1; } -/****************************************************************/ -/************** Uncategorised Functions *************************/ -/****************************************************************/ - -/** - * zfcp_device_setup - setup function - * @str: pointer to parameter string - * - * Parse "device=..." parameter string. - */ -static int __init -zfcp_device_setup(char *devstr) +static int __init zfcp_device_setup(char *devstr) { - char *tmp, *str; - size_t len; + char *token; + char *str; if (!devstr) return 0; - len = strlen(devstr) + 1; - str = kmalloc(len, GFP_KERNEL); - if (!str) { - pr_err("zfcp: Could not allocate memory for " - "device parameter string, device not attached.\n"); + /* duplicate devstr and keep the original for sysfs presentation*/ + str = kmalloc(strlen(devstr) + 1, GFP_KERNEL); + if (!str) return 0; - } - memcpy(str, devstr, len); - tmp = strchr(str, ','); - if (!tmp) - goto err_out; - *tmp++ = '\0'; - strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE); - zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0'; + strcpy(str, devstr); - zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0); - if (*tmp++ != ',') + token = strsep(&str, ","); + if (!token || strlen(token) >= BUS_ID_SIZE) goto err_out; - if (*tmp == '\0') + strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE); + + token = strsep(&str, ","); + if (!token || strict_strtoull(token, 0, &zfcp_data.init_wwpn)) goto err_out; - zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0); - if (*tmp != '\0') + token = strsep(&str, ","); + if (!token || strict_strtoull(token, 0, &zfcp_data.init_fcp_lun)) goto err_out; + kfree(str); return 1; err_out: - pr_err("zfcp: Parse error for device parameter string %s, " - "device not attached.\n", str); kfree(str); + pr_err("zfcp: Parse error for device parameter string %s, " + "device not attached.\n", devstr); return 0; } -static void __init -zfcp_init_device_configure(void) +static struct zfcp_adapter *zfcp_get_adapter_by_busid(char *bus_id) +{ + struct zfcp_adapter *adapter; + + list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) + if ((strncmp(bus_id, adapter->ccw_device->dev.bus_id, + BUS_ID_SIZE) == 0) && + !(atomic_read(&adapter->status) & + ZFCP_STATUS_COMMON_REMOVE)) + return adapter; + return NULL; +} + +static void __init zfcp_init_device_configure(void) { struct zfcp_adapter *adapter; struct zfcp_port *port; @@ -168,92 +131,72 @@ zfcp_init_device_configure(void) zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); - if (adapter == NULL) + if (!adapter) goto out_adapter; port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); - if (!port) + if (IS_ERR(port)) goto out_port; unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); - if (!unit) + if (IS_ERR(unit)) goto out_unit; up(&zfcp_data.config_sema); ccw_device_set_online(adapter->ccw_device); zfcp_erp_wait(adapter); down(&zfcp_data.config_sema); zfcp_unit_put(unit); - out_unit: +out_unit: zfcp_port_put(port); - out_port: +out_port: zfcp_adapter_put(adapter); - out_adapter: +out_adapter: up(&zfcp_data.config_sema); return; } -static int calc_alignment(int size) +static struct kmem_cache *zfcp_cache_create(int size, char *name) { int align = 1; - - if (!size) - return 0; - while ((size - align) > 0) align <<= 1; - - return align; + return kmem_cache_create(name , size, align, 0, NULL); } -static int __init -zfcp_module_init(void) +static int __init zfcp_module_init(void) { int retval = -ENOMEM; - int size, align; - size = sizeof(struct zfcp_fsf_req_qtcb); - align = calc_alignment(size); - zfcp_data.fsf_req_qtcb_cache = - kmem_cache_create("zfcp_fsf", size, align, 0, NULL); + zfcp_data.fsf_req_qtcb_cache = zfcp_cache_create( + sizeof(struct zfcp_fsf_req_qtcb), "zfcp_fsf"); if (!zfcp_data.fsf_req_qtcb_cache) goto out; - size = sizeof(struct fsf_status_read_buffer); - align = calc_alignment(size); - zfcp_data.sr_buffer_cache = - kmem_cache_create("zfcp_sr", size, align, 0, NULL); + zfcp_data.sr_buffer_cache = zfcp_cache_create( + sizeof(struct fsf_status_read_buffer), "zfcp_sr"); if (!zfcp_data.sr_buffer_cache) goto out_sr_cache; - size = sizeof(struct zfcp_gid_pn_data); - align = calc_alignment(size); - zfcp_data.gid_pn_cache = - kmem_cache_create("zfcp_gid", size, align, 0, NULL); + zfcp_data.gid_pn_cache = zfcp_cache_create( + sizeof(struct zfcp_gid_pn_data), "zfcp_gid"); if (!zfcp_data.gid_pn_cache) goto out_gid_cache; - /* initialize adapter list */ INIT_LIST_HEAD(&zfcp_data.adapter_list_head); - - /* initialize adapters to be removed list head */ INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh); + sema_init(&zfcp_data.config_sema, 1); + rwlock_init(&zfcp_data.config_lock); + zfcp_data.scsi_transport_template = fc_attach_transport(&zfcp_transport_functions); if (!zfcp_data.scsi_transport_template) goto out_transport; retval = misc_register(&zfcp_cfdc_misc); - if (retval != 0) { + if (retval) { pr_err("zfcp: registration of misc device zfcp_cfdc failed\n"); goto out_misc; } - /* Initialise proc semaphores */ - sema_init(&zfcp_data.config_sema, 1); - - /* initialise configuration rw lock */ - rwlock_init(&zfcp_data.config_lock); - - /* setup dynamic I/O */ retval = zfcp_ccw_register(); if (retval) { pr_err("zfcp: Registration with common I/O layer failed.\n"); @@ -265,157 +208,83 @@ zfcp_module_init(void) goto out; - out_ccw_register: +out_ccw_register: misc_deregister(&zfcp_cfdc_misc); - out_misc: +out_misc: fc_release_transport(zfcp_data.scsi_transport_template); - out_transport: +out_transport: kmem_cache_destroy(zfcp_data.gid_pn_cache); - out_gid_cache: +out_gid_cache: kmem_cache_destroy(zfcp_data.sr_buffer_cache); - out_sr_cache: +out_sr_cache: kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); - out: +out: return retval; } -/****************************************************************/ -/****** Functions for configuration/set-up of structures ********/ -/****************************************************************/ +module_init(zfcp_module_init); /** * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN * @port: pointer to port to search for unit * @fcp_lun: FCP LUN to search for - * Traverse list of all units of a port and return pointer to a unit - * with the given FCP LUN. + * + * Returns: pointer to zfcp_unit or NULL */ -struct zfcp_unit * -zfcp_get_unit_by_lun(struct zfcp_port *port, fcp_lun_t fcp_lun) +struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, + fcp_lun_t fcp_lun) { struct zfcp_unit *unit; - int found = 0; - list_for_each_entry(unit, &port->unit_list_head, list) { + list_for_each_entry(unit, &port->unit_list_head, list) if ((unit->fcp_lun == fcp_lun) && - !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status)) - { - found = 1; - break; - } - } - return found ? unit : NULL; + !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) + return unit; + return NULL; } /** * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn * @adapter: pointer to adapter to search for port * @wwpn: wwpn to search for - * Traverse list of all ports of an adapter and return pointer to a port - * with the given wwpn. + * + * Returns: pointer to zfcp_port or NULL */ -struct zfcp_port * -zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, wwn_t wwpn) +struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, + wwn_t wwpn) { struct zfcp_port *port; - int found = 0; - list_for_each_entry(port, &adapter->port_list_head, list) { - if ((port->wwpn == wwpn) && - !(atomic_read(&port->status) & - (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) { - found = 1; - break; - } - } - return found ? port : NULL; -} - -/** - * zfcp_get_port_by_did - find port in port list of adapter by d_id - * @adapter: pointer to adapter to search for port - * @d_id: d_id to search for - * Traverse list of all ports of an adapter and return pointer to a port - * with the given d_id. - */ -struct zfcp_port * -zfcp_get_port_by_did(struct zfcp_adapter *adapter, u32 d_id) -{ - struct zfcp_port *port; - int found = 0; - - list_for_each_entry(port, &adapter->port_list_head, list) { - if ((port->d_id == d_id) && - !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) - { - found = 1; - break; - } - } - return found ? port : NULL; -} - -/** - * zfcp_get_adapter_by_busid - find adpater in adapter list by bus_id - * @bus_id: bus_id to search for - * Traverse list of all adapters and return pointer to an adapter - * with the given bus_id. - */ -struct zfcp_adapter * -zfcp_get_adapter_by_busid(char *bus_id) -{ - struct zfcp_adapter *adapter; - int found = 0; - - list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) { - if ((strncmp(bus_id, zfcp_get_busid_by_adapter(adapter), - BUS_ID_SIZE) == 0) && - !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, - &adapter->status)){ - found = 1; - break; - } - } - return found ? adapter : NULL; + list_for_each_entry(port, &adapter->port_list_head, list) + if ((port->wwpn == wwpn) && !(atomic_read(&port->status) & + (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) + return port; + return NULL; } /** * zfcp_unit_enqueue - enqueue unit to unit list of a port. * @port: pointer to port where unit is added * @fcp_lun: FCP LUN of unit to be enqueued - * Return: pointer to enqueued unit on success, NULL on error + * Returns: pointer to enqueued unit on success, ERR_PTR on error * Locks: config_sema must be held to serialize changes to the unit list * * Sets up some unit internal structures and creates sysfs entry. */ -struct zfcp_unit * -zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) +struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) { struct zfcp_unit *unit; - /* - * check that there is no unit with this FCP_LUN already in list - * and enqueue it. - * Note: Unlike for the adapter and the port, this is an error - */ - read_lock_irq(&zfcp_data.config_lock); - unit = zfcp_get_unit_by_lun(port, fcp_lun); - read_unlock_irq(&zfcp_data.config_lock); - if (unit) - return NULL; - - unit = kzalloc(sizeof (struct zfcp_unit), GFP_KERNEL); + unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); if (!unit) - return NULL; + return ERR_PTR(-ENOMEM); - /* initialise reference count stuff */ atomic_set(&unit->refcount, 0); init_waitqueue_head(&unit->remove_wq); unit->port = port; unit->fcp_lun = fcp_lun; - /* setup for sysfs registration */ snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun); unit->sysfs_device.parent = &port->sysfs_device; unit->sysfs_device.release = zfcp_sysfs_unit_release; @@ -432,14 +301,19 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) unit->latencies.cmd.channel.min = 0xFFFFFFFF; unit->latencies.cmd.fabric.min = 0xFFFFFFFF; - if (device_register(&unit->sysfs_device)) { - kfree(unit); - return NULL; + read_lock_irq(&zfcp_data.config_lock); + if (zfcp_get_unit_by_lun(port, fcp_lun)) { + read_unlock_irq(&zfcp_data.config_lock); + goto err_out_free; } + read_unlock_irq(&zfcp_data.config_lock); + + if (device_register(&unit->sysfs_device)) + goto err_out_free; if (zfcp_sysfs_unit_create_files(&unit->sysfs_device)) { device_unregister(&unit->sysfs_device); - return NULL; + return ERR_PTR(-EIO); } zfcp_unit_get(unit); @@ -449,16 +323,27 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) list_add_tail(&unit->list, &port->unit_list_head); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); + write_unlock_irq(&zfcp_data.config_lock); port->units++; zfcp_port_get(port); return unit; + +err_out_free: + kfree(unit); + return ERR_PTR(-EINVAL); } -void -zfcp_unit_dequeue(struct zfcp_unit *unit) +/** + * zfcp_unit_dequeue - dequeue unit + * @unit: pointer to zfcp_unit + * + * waits until all work is done on unit and removes it then from the unit->list + * of the associated port. + */ +void zfcp_unit_dequeue(struct zfcp_unit *unit) { zfcp_unit_wait(unit); write_lock_irq(&zfcp_data.config_lock); @@ -470,64 +355,47 @@ zfcp_unit_dequeue(struct zfcp_unit *unit) device_unregister(&unit->sysfs_device); } -/* - * Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI - * commands. - * It also genrates fcp-nameserver request/response buffer and unsolicited - * status read fsf_req buffers. - * - * locks: must only be called with zfcp_data.config_sema taken - */ -static int -zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) +static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) { + /* must only be called with zfcp_data.config_sema taken */ adapter->pool.fsf_req_erp = - mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ERP_NR, - zfcp_data.fsf_req_qtcb_cache); + mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); if (!adapter->pool.fsf_req_erp) return -ENOMEM; adapter->pool.fsf_req_scsi = - mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_SCSI_NR, - zfcp_data.fsf_req_qtcb_cache); + mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); if (!adapter->pool.fsf_req_scsi) return -ENOMEM; adapter->pool.fsf_req_abort = - mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ABORT_NR, - zfcp_data.fsf_req_qtcb_cache); + mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); if (!adapter->pool.fsf_req_abort) return -ENOMEM; adapter->pool.fsf_req_status_read = - mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR, + mempool_create_kmalloc_pool(FSF_STATUS_READS_RECOM, sizeof(struct zfcp_fsf_req)); if (!adapter->pool.fsf_req_status_read) return -ENOMEM; adapter->pool.data_status_read = - mempool_create_slab_pool(ZFCP_POOL_STATUS_READ_NR, + mempool_create_slab_pool(FSF_STATUS_READS_RECOM, zfcp_data.sr_buffer_cache); if (!adapter->pool.data_status_read) return -ENOMEM; adapter->pool.data_gid_pn = - mempool_create_slab_pool(ZFCP_POOL_DATA_GID_PN_NR, - zfcp_data.gid_pn_cache); + mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); if (!adapter->pool.data_gid_pn) return -ENOMEM; return 0; } -/** - * zfcp_free_low_mem_buffers - free memory pools of an adapter - * @adapter: pointer to zfcp_adapter for which memory pools should be freed - * locking: zfcp_data.config_sema must be held - */ -static void -zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) +static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) { + /* zfcp_data.config_sema must be held */ if (adapter->pool.fsf_req_erp) mempool_destroy(adapter->pool.fsf_req_erp); if (adapter->pool.fsf_req_scsi) @@ -547,6 +415,15 @@ static void zfcp_dummy_release(struct device *dev) return; } +/** + * zfcp_status_read_refill - refill the long running status_read_requests + * @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled + * + * Returns: 0 on success, 1 otherwise + * + * if there are 16 or more status_read requests missing an adapter_reopen + * is triggered + */ int zfcp_status_read_refill(struct zfcp_adapter *adapter) { while (atomic_read(&adapter->stat_miss) > 0) @@ -573,27 +450,25 @@ static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, ZFCP_DID_DIRECTORY_SERVICE); - if (!port) - return -ENXIO; + if (IS_ERR(port)) + return PTR_ERR(port); zfcp_port_put(port); return 0; } -/* +/** + * zfcp_adapter_enqueue - enqueue a new adapter to the list + * @ccw_device: pointer to the struct cc_device + * + * Returns: 0 if a new adapter was successfully enqueued + * -ENOMEM if alloc failed * Enqueues an adapter at the end of the adapter list in the driver data. * All adapter internal structures are set up. * Proc-fs entries are also created. - * - * FIXME: Use -ENOMEM as return code for allocation failures - * - * returns: 0 if a new adapter was successfully enqueued - * ZFCP_KNOWN if an adapter with this devno was already present - * -ENOMEM if alloc failed * locks: config_sema must be held to serialise changes to the adapter list */ -struct zfcp_adapter * -zfcp_adapter_enqueue(struct ccw_device *ccw_device) +int zfcp_adapter_enqueue(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; @@ -602,15 +477,13 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) * are protected by the config_sema, which must be held to get here */ - /* try to allocate new adapter data structure (zeroed) */ - adapter = kzalloc(sizeof (struct zfcp_adapter), GFP_KERNEL); + adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); if (!adapter) - goto out; + return -ENOMEM; ccw_device->handler = NULL; - - /* save ccw_device pointer */ adapter->ccw_device = ccw_device; + atomic_set(&adapter->refcount, 0); if (zfcp_qdio_allocate(adapter)) goto qdio_allocate_failed; @@ -618,47 +491,34 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (zfcp_allocate_low_mem_buffers(adapter)) goto failed_low_mem_buffers; - /* initialise reference count stuff */ - atomic_set(&adapter->refcount, 0); + if (zfcp_reqlist_alloc(adapter)) + goto failed_low_mem_buffers; + + if (zfcp_adapter_debug_register(adapter)) + goto debug_register_failed; + init_waitqueue_head(&adapter->remove_wq); + init_waitqueue_head(&adapter->erp_thread_wqh); + init_waitqueue_head(&adapter->erp_done_wqh); - /* initialise list of ports */ INIT_LIST_HEAD(&adapter->port_list_head); - - /* initialise list of ports to be removed */ INIT_LIST_HEAD(&adapter->port_remove_lh); + INIT_LIST_HEAD(&adapter->erp_ready_head); + INIT_LIST_HEAD(&adapter->erp_running_head); - /* initialize list of fsf requests */ spin_lock_init(&adapter->req_list_lock); - if (zfcp_reqlist_alloc(adapter)) - goto failed_low_mem_buffers; - - /* initialize debug locks */ spin_lock_init(&adapter->hba_dbf_lock); spin_lock_init(&adapter->san_dbf_lock); spin_lock_init(&adapter->scsi_dbf_lock); spin_lock_init(&adapter->rec_dbf_lock); - if (zfcp_adapter_debug_register(adapter)) - goto debug_register_failed; - - /* initialize error recovery stuff */ - rwlock_init(&adapter->erp_lock); - sema_init(&adapter->erp_ready_sem, 0); - INIT_LIST_HEAD(&adapter->erp_ready_head); - INIT_LIST_HEAD(&adapter->erp_running_head); - - /* initialize abort lock */ rwlock_init(&adapter->abort_lock); + rwlock_init(&adapter->req_q.lock); - /* initialise some erp stuff */ - init_waitqueue_head(&adapter->erp_thread_wqh); - init_waitqueue_head(&adapter->erp_done_wqh); + sema_init(&adapter->erp_ready_sem, 0); - /* initialize lock of associated request queue */ - rwlock_init(&adapter->req_q.lock); INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); @@ -678,7 +538,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (device_register(&adapter->generic_services)) goto generic_services_failed; - /* put allocated adapter at list tail */ write_lock_irq(&zfcp_data.config_lock); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); @@ -688,33 +547,29 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) zfcp_nameserver_enqueue(adapter); - goto out; + return 0; - generic_services_failed: +generic_services_failed: zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); - sysfs_failed: +sysfs_failed: zfcp_adapter_debug_unregister(adapter); - debug_register_failed: +debug_register_failed: dev_set_drvdata(&ccw_device->dev, NULL); - zfcp_reqlist_free(adapter); - failed_low_mem_buffers: + kfree(adapter->req_list); +failed_low_mem_buffers: zfcp_free_low_mem_buffers(adapter); - qdio_allocate_failed: +qdio_allocate_failed: zfcp_qdio_free(adapter); kfree(adapter); - adapter = NULL; - out: - return adapter; + return -ENOMEM; } -/* - * returns: 0 - struct zfcp_adapter data structure successfully removed - * !0 - struct zfcp_adapter data structure could not be removed - * (e.g. still used) +/** + * zfcp_adapter_dequeue - remove the adapter from the resource list + * @adapter: pointer to struct zfcp_adapter which should be removed * locks: adapter list write lock is assumed to be held by caller */ -void -zfcp_adapter_dequeue(struct zfcp_adapter *adapter) +void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) { int retval = 0; unsigned long flags; @@ -729,10 +584,8 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) spin_lock_irqsave(&adapter->req_list_lock, flags); retval = zfcp_reqlist_isempty(adapter); spin_unlock_irqrestore(&adapter->req_list_lock, flags); - if (!retval) { - retval = -EBUSY; - goto out; - } + if (!retval) + return; zfcp_adapter_debug_unregister(adapter); @@ -747,12 +600,10 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) zfcp_qdio_free(adapter); zfcp_free_low_mem_buffers(adapter); - zfcp_reqlist_free(adapter); + kfree(adapter->req_list); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); kfree(adapter); - out: - return; } /** @@ -761,77 +612,58 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) * @wwpn: WWPN of the remote port to be enqueued * @status: initial status for the port * @d_id: destination id of the remote port to be enqueued - * Return: pointer to enqueued port on success, NULL on error + * Returns: pointer to enqueued port on success, ERR_PTR on error * Locks: config_sema must be held to serialize changes to the port list * * All port internal structures are set up and the sysfs entry is generated. * d_id is used to enqueue ports with a well known address like the Directory * Service for nameserver lookup. */ -struct zfcp_port * -zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, - u32 d_id) +struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, + u32 status, u32 d_id) { struct zfcp_port *port; - int check_wwpn; + char *bus_id; - check_wwpn = !(status & ZFCP_STATUS_PORT_NO_WWPN); - /* - * check that there is no port with this WWPN already in list - */ - if (check_wwpn) { - read_lock_irq(&zfcp_data.config_lock); - port = zfcp_get_port_by_wwpn(adapter, wwpn); - read_unlock_irq(&zfcp_data.config_lock); - if (port) - return NULL; - } - - port = kzalloc(sizeof (struct zfcp_port), GFP_KERNEL); + port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); if (!port) - return NULL; + return ERR_PTR(-ENOMEM); - /* initialise reference count stuff */ - atomic_set(&port->refcount, 0); init_waitqueue_head(&port->remove_wq); INIT_LIST_HEAD(&port->unit_list_head); INIT_LIST_HEAD(&port->unit_remove_lh); port->adapter = adapter; + port->d_id = d_id; + port->wwpn = wwpn; - if (check_wwpn) - port->wwpn = wwpn; - - atomic_set_mask(status, &port->status); + /* mark port unusable as long as sysfs registration is not complete */ + atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); + atomic_set(&port->refcount, 0); - /* setup for sysfs registration */ if (status & ZFCP_STATUS_PORT_WKA) { switch (d_id) { case ZFCP_DID_DIRECTORY_SERVICE: - snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, - "directory"); + bus_id = "directory"; break; case ZFCP_DID_MANAGEMENT_SERVICE: - snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, - "management"); + bus_id = "management"; break; case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: - snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, - "key_distribution"); + bus_id = "key_distribution"; break; case ZFCP_DID_ALIAS_SERVICE: - snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, - "alias"); + bus_id = "alias"; break; case ZFCP_DID_TIME_SERVICE: - snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, - "time"); + bus_id = "time"; break; default: kfree(port); - return NULL; + return ERR_PTR(-EINVAL); } + snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "%s", bus_id); port->sysfs_device.parent = &adapter->generic_services; } else { snprintf(port->sysfs_device.bus_id, @@ -839,22 +671,23 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, port->sysfs_device.parent = &adapter->ccw_device->dev; } - port->d_id = d_id; - port->sysfs_device.release = zfcp_sysfs_port_release; dev_set_drvdata(&port->sysfs_device, port); - /* mark port unusable as long as sysfs registration is not complete */ - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + read_lock_irq(&zfcp_data.config_lock); + if (!(status & ZFCP_STATUS_PORT_NO_WWPN)) + if (zfcp_get_port_by_wwpn(adapter, wwpn)) { + read_unlock_irq(&zfcp_data.config_lock); + goto err_out_free; + } + read_unlock_irq(&zfcp_data.config_lock); - if (device_register(&port->sysfs_device)) { - kfree(port); - return NULL; - } + if (device_register(&port->sysfs_device)) + goto err_out_free; if (zfcp_sysfs_port_create_files(&port->sysfs_device, status)) { device_unregister(&port->sysfs_device); - return NULL; + goto err_out; } zfcp_port_get(port); @@ -867,15 +700,23 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, if (!adapter->nameserver_port) adapter->nameserver_port = port; adapter->ports++; + write_unlock_irq(&zfcp_data.config_lock); zfcp_adapter_get(adapter); - return port; + +err_out_free: + kfree(port); +err_out: + return ERR_PTR(-EINVAL); } -void -zfcp_port_dequeue(struct zfcp_port *port) +/** + * zfcp_port_dequeue - dequeues a port from the port list of the adapter + * @port: pointer to struct zfcp_port which should be removed + */ +void zfcp_port_dequeue(struct zfcp_port *port) { zfcp_port_wait(port); write_lock_irq(&zfcp_data.config_lock); @@ -891,6 +732,12 @@ zfcp_port_dequeue(struct zfcp_port *port) device_unregister(&port->sysfs_device); } +/** + * zfcp_sg_free_table - free memory used by scatterlists + * @sg: pointer to scatterlist + * @count: number of scatterlist which are to be free'ed + * the scatterlist are expected to reference pages always + */ void zfcp_sg_free_table(struct scatterlist *sg, int count) { int i; @@ -902,6 +749,14 @@ void zfcp_sg_free_table(struct scatterlist *sg, int count) break; } +/** + * zfcp_sg_setup_table - init scatterlist and allocate, assign buffers + * @sg: pointer to struct scatterlist + * @count: number of scatterlists which should be assigned with buffers + * of size page + * + * Returns: 0 on success, -ENOMEM otherwise + */ int zfcp_sg_setup_table(struct scatterlist *sg, int count) { void *addr; diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index da472e865e58..391dd29749f8 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -20,12 +20,10 @@ */ static int zfcp_ccw_probe(struct ccw_device *ccw_device) { - struct zfcp_adapter *adapter; int retval = 0; down(&zfcp_data.config_sema); - adapter = zfcp_adapter_enqueue(ccw_device); - if (!adapter) { + if (zfcp_adapter_enqueue(ccw_device)) { dev_err(&ccw_device->dev, "Setup of data structures failed.\n"); retval = -EINVAL; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 7ac830c39098..d69d280359da 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -730,13 +730,6 @@ struct zfcp_data { struct kmem_cache *gid_pn_cache; }; -/* number of elements for various memory pools */ -#define ZFCP_POOL_FSF_REQ_ERP_NR 1 -#define ZFCP_POOL_FSF_REQ_SCSI_NR 1 -#define ZFCP_POOL_FSF_REQ_ABORT_NR 1 -#define ZFCP_POOL_STATUS_READ_NR FSF_STATUS_READS_RECOM -#define ZFCP_POOL_DATA_GID_PN_NR 1 - /* struct used by memory pools for fsf_requests */ struct zfcp_fsf_req_qtcb { struct zfcp_fsf_req fsf_req; @@ -757,12 +750,6 @@ struct zfcp_fsf_req_qtcb { ((atomic_read(target) & mask) == mask) #endif -extern void _zfcp_hex_dump(char *, int); -#define ZFCP_HEX_DUMP(level, addr, count) \ - if (ZFCP_LOG_CHECK(level)) { \ - _zfcp_hex_dump(addr, count); \ - } - #define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id) #define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter)) #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port)) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 9b9c999cf39f..4d797e5264d9 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1675,7 +1675,7 @@ static void zfcp_erp_open_ptp_port(struct zfcp_adapter *adapter) struct zfcp_port *port; port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, adapter->peer_d_id); - if (!port) /* error or port already attached */ + if (IS_ERR(port)) /* error or port already attached */ return; zfcp_erp_port_reopen_internal(port, 0, 150, NULL); } diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 892476c17ff2..9caa081e52ed 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -26,9 +26,7 @@ extern void zfcp_sysfs_unit_release(struct device *); /**************************** CONFIGURATION *********************************/ extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, fcp_lun_t); extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, wwn_t); -extern struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *, u32); -struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); -extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); +extern int zfcp_adapter_enqueue(struct ccw_device *); extern int zfcp_adapter_debug_register(struct zfcp_adapter *); extern void zfcp_adapter_dequeue(struct zfcp_adapter *); extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 5d9367d9a12d..fbe2c76df4d7 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -39,6 +39,18 @@ struct zfcp_gpn_ft { struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS]; }; +static struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *adapter, + u32 d_id) +{ + struct zfcp_port *port; + + list_for_each_entry(port, &adapter->port_list_head, list) + if ((port->d_id == d_id) && + !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) + return port; + return NULL; +} + static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, struct fcp_rscn_element *elem) { @@ -496,10 +508,10 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) port = zfcp_port_enqueue(adapter, acc->wwpn, ZFCP_STATUS_PORT_DID_DID | ZFCP_STATUS_COMMON_NOESC, d_id); - if (port) - zfcp_erp_port_reopen(port, 0, 149, NULL); + if (IS_ERR(port)) + ret = PTR_ERR(port); else - ret = -ENOMEM; + zfcp_erp_port_reopen(port, 0, 149, NULL); if (acc->control & 0x80) /* last entry */ break; } diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c index 438675f2978e..e183ff8bdb2a 100644 --- a/drivers/s390/scsi/zfcp_sysfs_port.c +++ b/drivers/s390/scsi/zfcp_sysfs_port.c @@ -74,7 +74,7 @@ zfcp_sysfs_unit_add_store(struct device *dev, struct device_attribute *attr, con goto out; unit = zfcp_unit_enqueue(port, fcp_lun); - if (!unit) + if (IS_ERR(unit)) goto out; retval = 0; -- cgit v1.2.3 From 60221920706a01bef89af2577f9a90a8eeb4e662 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 2 Jul 2008 10:56:38 +0200 Subject: [SCSI] zfcp: consolidate sysfs things into one file. zfcp was using three files to deal with sysfs representation for adapters, ports and units. The consolidation into one file prevents code-duplication and eases maintainability. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/Makefile | 3 +- drivers/s390/scsi/zfcp_aux.c | 42 ++- drivers/s390/scsi/zfcp_def.h | 9 - drivers/s390/scsi/zfcp_ext.h | 16 +- drivers/s390/scsi/zfcp_scsi.c | 206 +------------- drivers/s390/scsi/zfcp_sysfs.c | 496 +++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_sysfs_adapter.c | 232 --------------- drivers/s390/scsi/zfcp_sysfs_port.c | 278 ------------------ drivers/s390/scsi/zfcp_sysfs_unit.c | 150 ---------- 9 files changed, 539 insertions(+), 893 deletions(-) create mode 100644 drivers/s390/scsi/zfcp_sysfs.c delete mode 100644 drivers/s390/scsi/zfcp_sysfs_adapter.c delete mode 100644 drivers/s390/scsi/zfcp_sysfs_port.c delete mode 100644 drivers/s390/scsi/zfcp_sysfs_unit.c (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index 1aa46500f650..cb301cc6178c 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -3,7 +3,6 @@ # zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ - zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ - zfcp_sysfs_unit.o zfcp_fc.o zfcp_cfdc.o + zfcp_fsf.o zfcp_dbf.o zfcp_sysfs.o zfcp_fc.o zfcp_cfdc.o obj-$(CONFIG_ZFCP) += zfcp.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 7777729419eb..5b9ca3cde898 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -262,6 +262,11 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, return NULL; } +static void zfcp_sysfs_unit_release(struct device *dev) +{ + kfree(container_of(dev, struct zfcp_unit, sysfs_device)); +} + /** * zfcp_unit_enqueue - enqueue unit to unit list of a port. * @port: pointer to port where unit is added @@ -311,7 +316,8 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) if (device_register(&unit->sysfs_device)) goto err_out_free; - if (zfcp_sysfs_unit_create_files(&unit->sysfs_device)) { + if (sysfs_create_group(&unit->sysfs_device.kobj, + &zfcp_sysfs_unit_attrs)) { device_unregister(&unit->sysfs_device); return ERR_PTR(-EIO); } @@ -351,7 +357,7 @@ void zfcp_unit_dequeue(struct zfcp_unit *unit) write_unlock_irq(&zfcp_data.config_lock); unit->port->units--; zfcp_port_put(unit->port); - zfcp_sysfs_unit_remove_files(&unit->sysfs_device); + sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); device_unregister(&unit->sysfs_device); } @@ -527,7 +533,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) dev_set_drvdata(&ccw_device->dev, adapter); - if (zfcp_sysfs_adapter_create_files(&ccw_device->dev)) + if (sysfs_create_group(&ccw_device->dev.kobj, + &zfcp_sysfs_adapter_attrs)) goto sysfs_failed; adapter->generic_services.parent = &adapter->ccw_device->dev; @@ -550,7 +557,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) return 0; generic_services_failed: - zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); + sysfs_remove_group(&ccw_device->dev.kobj, + &zfcp_sysfs_adapter_attrs); sysfs_failed: zfcp_adapter_debug_unregister(adapter); debug_register_failed: @@ -578,7 +586,8 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) cancel_work_sync(&adapter->stat_work); zfcp_adapter_scsi_unregister(adapter); device_unregister(&adapter->generic_services); - zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); + sysfs_remove_group(&adapter->ccw_device->dev.kobj, + &zfcp_sysfs_adapter_attrs); dev_set_drvdata(&adapter->ccw_device->dev, NULL); /* sanity check: no pending FSF requests */ spin_lock_irqsave(&adapter->req_list_lock, flags); @@ -606,6 +615,11 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) kfree(adapter); } +static void zfcp_sysfs_port_release(struct device *dev) +{ + kfree(container_of(dev, struct zfcp_port, sysfs_device)); +} + /** * zfcp_port_enqueue - enqueue port to port list of adapter * @adapter: adapter where remote port is added @@ -623,6 +637,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, u32 d_id) { struct zfcp_port *port; + int retval; char *bus_id; port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); @@ -685,7 +700,14 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, if (device_register(&port->sysfs_device)) goto err_out_free; - if (zfcp_sysfs_port_create_files(&port->sysfs_device, status)) { + if (status & ZFCP_STATUS_PORT_WKA) + retval = sysfs_create_group(&port->sysfs_device.kobj, + &zfcp_sysfs_ns_port_attrs); + else + retval = sysfs_create_group(&port->sysfs_device.kobj, + &zfcp_sysfs_port_attrs); + + if (retval) { device_unregister(&port->sysfs_device); goto err_out; } @@ -727,8 +749,12 @@ void zfcp_port_dequeue(struct zfcp_port *port) fc_remote_port_delete(port->rport); port->rport = NULL; zfcp_adapter_put(port->adapter); - zfcp_sysfs_port_remove_files(&port->sysfs_device, - atomic_read(&port->status)); + if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) + sysfs_remove_group(&port->sysfs_device.kobj, + &zfcp_sysfs_ns_port_attrs); + else + sysfs_remove_group(&port->sysfs_device.kobj, + &zfcp_sysfs_port_attrs); device_unregister(&port->sysfs_device); } diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index d69d280359da..2af043a5c74b 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -627,11 +627,6 @@ struct zfcp_adapter { struct work_struct scan_work; }; -/* - * the struct device sysfs_device must be at the beginning of this structure. - * pointer to struct device is used to free port structure in release function - * of the device. don't change! - */ struct zfcp_port { struct device sysfs_device; /* sysfs device */ struct fc_rport *rport; /* rport of fc transport class */ @@ -655,10 +650,6 @@ struct zfcp_port { u32 supported_classes; }; -/* the struct device sysfs_device must be at the beginning of this structure. - * pointer to struct device is used to free unit structure in release function - * of the device. don't change! - */ struct zfcp_unit { struct device sysfs_device; /* sysfs device */ struct list_head list; /* list of logical units */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 9caa081e52ed..f0d6947ae073 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -13,15 +13,13 @@ extern struct zfcp_data zfcp_data; -/******************************** SYSFS *************************************/ -extern int zfcp_sysfs_adapter_create_files(struct device *); -extern void zfcp_sysfs_adapter_remove_files(struct device *); -extern int zfcp_sysfs_port_create_files(struct device *, u32); -extern void zfcp_sysfs_port_remove_files(struct device *, u32); -extern int zfcp_sysfs_unit_create_files(struct device *); -extern void zfcp_sysfs_unit_remove_files(struct device *); -extern void zfcp_sysfs_port_release(struct device *); -extern void zfcp_sysfs_unit_release(struct device *); +/* zfcp_sysfs.c */ +extern struct attribute_group zfcp_sysfs_unit_attrs; +extern struct attribute_group zfcp_sysfs_adapter_attrs; +extern struct attribute_group zfcp_sysfs_ns_port_attrs; +extern struct attribute_group zfcp_sysfs_port_attrs; +extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; +extern struct device_attribute *zfcp_sysfs_shost_attrs[]; /**************************** CONFIGURATION *********************************/ extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, fcp_lun_t); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index f8594a2e3f5c..e6d8ea8051af 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -520,209 +520,6 @@ struct fc_function_template zfcp_transport_functions = { .disable_target_scan = 1, }; -#define ZFCP_DEFINE_LATENCY_ATTR(_name) \ -static ssize_t \ -zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) { \ - struct scsi_device *sdev = to_scsi_device(dev); \ - struct zfcp_unit *unit = sdev->hostdata; \ - struct zfcp_latencies *lat = &unit->latencies; \ - struct zfcp_adapter *adapter = unit->port->adapter; \ - unsigned long flags; \ - unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \ - \ - spin_lock_irqsave(&lat->lock, flags); \ - fsum = lat->_name.fabric.sum * adapter->timer_ticks; \ - fmin = lat->_name.fabric.min * adapter->timer_ticks; \ - fmax = lat->_name.fabric.max * adapter->timer_ticks; \ - csum = lat->_name.channel.sum * adapter->timer_ticks; \ - cmin = lat->_name.channel.min * adapter->timer_ticks; \ - cmax = lat->_name.channel.max * adapter->timer_ticks; \ - cc = lat->_name.counter; \ - spin_unlock_irqrestore(&lat->lock, flags); \ - \ - do_div(fsum, 1000); \ - do_div(fmin, 1000); \ - do_div(fmax, 1000); \ - do_div(csum, 1000); \ - do_div(cmin, 1000); \ - do_div(cmax, 1000); \ - \ - return sprintf(buf, "%llu %llu %llu %llu %llu %llu %llu\n", \ - fmin, fmax, fsum, cmin, cmax, csum, cc); \ -} \ -static ssize_t \ -zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct scsi_device *sdev = to_scsi_device(dev); \ - struct zfcp_unit *unit = sdev->hostdata; \ - struct zfcp_latencies *lat = &unit->latencies; \ - unsigned long flags; \ - \ - spin_lock_irqsave(&lat->lock, flags); \ - lat->_name.fabric.sum = 0; \ - lat->_name.fabric.min = 0xFFFFFFFF; \ - lat->_name.fabric.max = 0; \ - lat->_name.channel.sum = 0; \ - lat->_name.channel.min = 0xFFFFFFFF; \ - lat->_name.channel.max = 0; \ - lat->_name.counter = 0; \ - spin_unlock_irqrestore(&lat->lock, flags); \ - \ - return (ssize_t) count; \ -} \ -static DEVICE_ATTR(_name##_latency, S_IWUSR | S_IRUGO, \ - zfcp_sysfs_unit_##_name##_latency_show, \ - zfcp_sysfs_unit_##_name##_latency_store); - -ZFCP_DEFINE_LATENCY_ATTR(read); -ZFCP_DEFINE_LATENCY_ATTR(write); -ZFCP_DEFINE_LATENCY_ATTR(cmd); - -#define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ -static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct scsi_device *sdev; \ - struct zfcp_unit *unit; \ - \ - sdev = to_scsi_device(dev); \ - unit = sdev->hostdata; \ - return sprintf(buf, _format, _value); \ -} \ - \ -static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); - -ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", - unit->port->adapter->ccw_device->dev.bus_id); -ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); -ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); - -static struct device_attribute *zfcp_sysfs_sdev_attrs[] = { - &dev_attr_fcp_lun, - &dev_attr_wwpn, - &dev_attr_hba_id, - &dev_attr_read_latency, - &dev_attr_write_latency, - &dev_attr_cmd_latency, - NULL -}; - -static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *scsi_host = dev_to_shost(dev); - struct fsf_qtcb_bottom_port *qtcb_port; - struct zfcp_adapter *adapter; - int retval; - - adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; - if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) - return -EOPNOTSUPP; - - qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL); - if (!qtcb_port) - return -ENOMEM; - - retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); - if (!retval) - retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, - qtcb_port->cb_util, qtcb_port->a_util); - kfree(qtcb_port); - return retval; -} - -static int zfcp_sysfs_adapter_ex_config(struct device *dev, - struct fsf_statistics_info *stat_inf) -{ - struct Scsi_Host *scsi_host = dev_to_shost(dev); - struct fsf_qtcb_bottom_config *qtcb_config; - struct zfcp_adapter *adapter; - int retval; - - adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; - if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) - return -EOPNOTSUPP; - - qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), - GFP_KERNEL); - if (!qtcb_config) - return -ENOMEM; - - retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); - if (!retval) - *stat_inf = qtcb_config->stat_info; - - kfree(qtcb_config); - return retval; -} - -static ssize_t zfcp_sysfs_adapter_request_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct fsf_statistics_info stat_info; - int retval; - - retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); - if (retval) - return retval; - - return sprintf(buf, "%llu %llu %llu\n", - (unsigned long long) stat_info.input_req, - (unsigned long long) stat_info.output_req, - (unsigned long long) stat_info.control_req); -} - -static ssize_t zfcp_sysfs_adapter_mb_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct fsf_statistics_info stat_info; - int retval; - - retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); - if (retval) - return retval; - - return sprintf(buf, "%llu %llu\n", - (unsigned long long) stat_info.input_mb, - (unsigned long long) stat_info.output_mb); -} - -static ssize_t zfcp_sysfs_adapter_sec_active_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct fsf_statistics_info stat_info; - int retval; - - retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); - if (retval) - return retval; - - return sprintf(buf, "%llu\n", - (unsigned long long) stat_info.seconds_act); -} - -static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL); -static DEVICE_ATTR(requests, S_IRUGO, zfcp_sysfs_adapter_request_show, NULL); -static DEVICE_ATTR(megabytes, S_IRUGO, zfcp_sysfs_adapter_mb_show, NULL); -static DEVICE_ATTR(seconds_active, S_IRUGO, - zfcp_sysfs_adapter_sec_active_show, NULL); - -static struct device_attribute *zfcp_a_stats_attrs[] = { - &dev_attr_utilization, - &dev_attr_requests, - &dev_attr_megabytes, - &dev_attr_seconds_active, - NULL -}; - struct zfcp_data zfcp_data = { .scsi_host_template = { .name = "zfcp", @@ -743,7 +540,6 @@ struct zfcp_data zfcp_data = { .use_clustering = 1, .sdev_attrs = zfcp_sysfs_sdev_attrs, .max_sectors = (ZFCP_MAX_SBALES_PER_REQ * 8), - .shost_attrs = zfcp_a_stats_attrs, + .shost_attrs = zfcp_sysfs_shost_attrs, }, }; - diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c new file mode 100644 index 000000000000..2e85c6c49e7d --- /dev/null +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -0,0 +1,496 @@ +/* + * zfcp device driver + * + * sysfs attributes. + * + * Copyright IBM Corporation 2008 + */ + +#include "zfcp_ext.h" + +#define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ +struct device_attribute dev_attr_##_feat##_##_name = __ATTR(_name, _mode,\ + _show, _store) +#define ZFCP_DEFINE_ATTR(_feat_def, _feat, _name, _format, _value) \ +static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ + struct device_attribute *at,\ + char *buf) \ +{ \ + struct _feat_def *_feat = dev_get_drvdata(dev); \ + \ + return sprintf(buf, _format, _value); \ +} \ +static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ + zfcp_sysfs_##_feat##_##_name##_show, NULL); + +ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n", + atomic_read(&adapter->status)); +ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n", + adapter->peer_wwnn); +ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n", + adapter->peer_wwpn); +ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n", + adapter->peer_d_id); +ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n", + adapter->hydra_version); +ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, lic_version, "0x%08x\n", + adapter->fsf_lic_version); +ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, hardware_version, "0x%08x\n", + adapter->hardware_version); +ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, in_recovery, "%d\n", + (atomic_read(&adapter->status) & + ZFCP_STATUS_COMMON_ERP_INUSE) != 0); + +ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n", + atomic_read(&port->status)); +ZFCP_DEFINE_ATTR(zfcp_port, port, in_recovery, "%d\n", + (atomic_read(&port->status) & + ZFCP_STATUS_COMMON_ERP_INUSE) != 0); +ZFCP_DEFINE_ATTR(zfcp_port, port, access_denied, "%d\n", + (atomic_read(&port->status) & + ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); + +ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n", + atomic_read(&unit->status)); +ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n", + (atomic_read(&unit->status) & + ZFCP_STATUS_COMMON_ERP_INUSE) != 0); +ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n", + (atomic_read(&unit->status) & + ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); +ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_shared, "%d\n", + (atomic_read(&unit->status) & + ZFCP_STATUS_UNIT_SHARED) != 0); +ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_readonly, "%d\n", + (atomic_read(&unit->status) & + ZFCP_STATUS_UNIT_READONLY) != 0); + +#define ZFCP_SYSFS_FAILED(_feat_def, _feat, _adapter, _mod_id, _reopen_id) \ +static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct _feat_def *_feat = dev_get_drvdata(dev); \ + \ + if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \ + return sprintf(buf, "1\n"); \ + else \ + return sprintf(buf, "0\n"); \ +} \ +static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ + struct device_attribute *attr,\ + const char *buf, size_t count)\ +{ \ + struct _feat_def *_feat = dev_get_drvdata(dev); \ + unsigned long val; \ + int retval = 0; \ + \ + down(&zfcp_data.config_sema); \ + if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \ + retval = -EBUSY; \ + goto out; \ + } \ + \ + if (strict_strtoul(buf, 0, &val) || val != 0) { \ + retval = -EINVAL; \ + goto out; \ + } \ + \ + zfcp_erp_modify_##_feat##_status(_feat, _mod_id, NULL, \ + ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);\ + zfcp_erp_##_feat##_reopen(_feat, ZFCP_STATUS_COMMON_ERP_FAILED, \ + _reopen_id, NULL); \ + zfcp_erp_wait(_adapter); \ +out: \ + up(&zfcp_data.config_sema); \ + return retval ? retval : (ssize_t) count; \ +} \ +static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ + zfcp_sysfs_##_feat##_failed_show, \ + zfcp_sysfs_##_feat##_failed_store); + +ZFCP_SYSFS_FAILED(zfcp_adapter, adapter, adapter, 44, 93); +ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, 45, 96); +ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, 46, 97); + +static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zfcp_adapter *adapter = dev_get_drvdata(dev); + int ret; + + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) + return -EBUSY; + + ret = zfcp_scan_ports(adapter); + return ret ? ret : (ssize_t) count; +} +static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, + zfcp_sysfs_port_rescan_store); + +static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zfcp_adapter *adapter = dev_get_drvdata(dev); + struct zfcp_port *port; + wwn_t wwpn; + int retval = 0; + + down(&zfcp_data.config_sema); + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { + retval = -EBUSY; + goto out; + } + + if (strict_strtoull(buf, 0, &wwpn)) { + retval = -EINVAL; + goto out; + } + + write_lock_irq(&zfcp_data.config_lock); + port = zfcp_get_port_by_wwpn(adapter, wwpn); + if (port && (atomic_read(&port->refcount) == 0)) { + zfcp_port_get(port); + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + list_move(&port->list, &adapter->port_remove_lh); + } else + port = NULL; + write_unlock_irq(&zfcp_data.config_lock); + + if (!port) { + retval = -ENXIO; + goto out; + } + + zfcp_erp_port_shutdown(port, 0, 92, NULL); + zfcp_erp_wait(adapter); + zfcp_port_put(port); + zfcp_port_dequeue(port); + out: + up(&zfcp_data.config_sema); + return retval ? retval : (ssize_t) count; +} +static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, + zfcp_sysfs_port_remove_store); + +static struct attribute *zfcp_adapter_attrs[] = { + &dev_attr_adapter_failed.attr, + &dev_attr_adapter_in_recovery.attr, + &dev_attr_adapter_port_remove.attr, + &dev_attr_adapter_port_rescan.attr, + &dev_attr_adapter_peer_wwnn.attr, + &dev_attr_adapter_peer_wwpn.attr, + &dev_attr_adapter_peer_d_id.attr, + &dev_attr_adapter_card_version.attr, + &dev_attr_adapter_lic_version.attr, + &dev_attr_adapter_status.attr, + &dev_attr_adapter_hardware_version.attr, + NULL +}; + +struct attribute_group zfcp_sysfs_adapter_attrs = { + .attrs = zfcp_adapter_attrs, +}; + +static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zfcp_port *port = dev_get_drvdata(dev); + struct zfcp_unit *unit; + fcp_lun_t fcp_lun; + int retval = -EINVAL; + + down(&zfcp_data.config_sema); + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { + retval = -EBUSY; + goto out; + } + + if (strict_strtoull(buf, 0, &fcp_lun)) + goto out; + + unit = zfcp_unit_enqueue(port, fcp_lun); + if (IS_ERR(unit)) + goto out; + + retval = 0; + + zfcp_erp_unit_reopen(unit, 0, 94, NULL); + zfcp_erp_wait(unit->port->adapter); + zfcp_unit_put(unit); +out: + up(&zfcp_data.config_sema); + return retval ? retval : (ssize_t) count; +} +static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); + +static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zfcp_port *port = dev_get_drvdata(dev); + struct zfcp_unit *unit; + fcp_lun_t fcp_lun; + int retval = 0; + + down(&zfcp_data.config_sema); + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { + retval = -EBUSY; + goto out; + } + + if (strict_strtoull(buf, 0, &fcp_lun)) { + retval = -EINVAL; + goto out; + } + + write_lock_irq(&zfcp_data.config_lock); + unit = zfcp_get_unit_by_lun(port, fcp_lun); + if (unit && (atomic_read(&unit->refcount) == 0)) { + zfcp_unit_get(unit); + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); + list_move(&unit->list, &port->unit_remove_lh); + } else + unit = NULL; + + write_unlock_irq(&zfcp_data.config_lock); + + if (!unit) { + retval = -ENXIO; + goto out; + } + + zfcp_erp_unit_shutdown(unit, 0, 95, NULL); + zfcp_erp_wait(unit->port->adapter); + zfcp_unit_put(unit); + zfcp_unit_dequeue(unit); +out: + up(&zfcp_data.config_sema); + return retval ? retval : (ssize_t) count; +} +static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); + +static struct attribute *zfcp_port_ns_attrs[] = { + &dev_attr_port_failed.attr, + &dev_attr_port_in_recovery.attr, + &dev_attr_port_status.attr, + &dev_attr_port_access_denied.attr, + NULL +}; + +/** + * zfcp_sysfs_ns_port_attrs - sysfs attributes for nameserver + */ +struct attribute_group zfcp_sysfs_ns_port_attrs = { + .attrs = zfcp_port_ns_attrs, +}; + +static struct attribute *zfcp_port_no_ns_attrs[] = { + &dev_attr_unit_add.attr, + &dev_attr_unit_remove.attr, + &dev_attr_port_failed.attr, + &dev_attr_port_in_recovery.attr, + &dev_attr_port_status.attr, + &dev_attr_port_access_denied.attr, + NULL +}; + +/** + * zfcp_sysfs_port_attrs - sysfs attributes for all other ports + */ +struct attribute_group zfcp_sysfs_port_attrs = { + .attrs = zfcp_port_no_ns_attrs, +}; + +static struct attribute *zfcp_unit_attrs[] = { + &dev_attr_unit_failed.attr, + &dev_attr_unit_in_recovery.attr, + &dev_attr_unit_status.attr, + &dev_attr_unit_access_denied.attr, + &dev_attr_unit_access_shared.attr, + &dev_attr_unit_access_readonly.attr, + NULL +}; + +struct attribute_group zfcp_sysfs_unit_attrs = { + .attrs = zfcp_unit_attrs, +}; + +#define ZFCP_DEFINE_LATENCY_ATTR(_name) \ +static ssize_t \ +zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) { \ + struct scsi_device *sdev = to_scsi_device(dev); \ + struct zfcp_unit *unit = sdev->hostdata; \ + struct zfcp_latencies *lat = &unit->latencies; \ + struct zfcp_adapter *adapter = unit->port->adapter; \ + unsigned long flags; \ + unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \ + \ + spin_lock_irqsave(&lat->lock, flags); \ + fsum = lat->_name.fabric.sum * adapter->timer_ticks; \ + fmin = lat->_name.fabric.min * adapter->timer_ticks; \ + fmax = lat->_name.fabric.max * adapter->timer_ticks; \ + csum = lat->_name.channel.sum * adapter->timer_ticks; \ + cmin = lat->_name.channel.min * adapter->timer_ticks; \ + cmax = lat->_name.channel.max * adapter->timer_ticks; \ + cc = lat->_name.counter; \ + spin_unlock_irqrestore(&lat->lock, flags); \ + \ + do_div(fsum, 1000); \ + do_div(fmin, 1000); \ + do_div(fmax, 1000); \ + do_div(csum, 1000); \ + do_div(cmin, 1000); \ + do_div(cmax, 1000); \ + \ + return sprintf(buf, "%llu %llu %llu %llu %llu %llu %llu\n", \ + fmin, fmax, fsum, cmin, cmax, csum, cc); \ +} \ +static ssize_t \ +zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct scsi_device *sdev = to_scsi_device(dev); \ + struct zfcp_unit *unit = sdev->hostdata; \ + struct zfcp_latencies *lat = &unit->latencies; \ + unsigned long flags; \ + \ + spin_lock_irqsave(&lat->lock, flags); \ + lat->_name.fabric.sum = 0; \ + lat->_name.fabric.min = 0xFFFFFFFF; \ + lat->_name.fabric.max = 0; \ + lat->_name.channel.sum = 0; \ + lat->_name.channel.min = 0xFFFFFFFF; \ + lat->_name.channel.max = 0; \ + lat->_name.counter = 0; \ + spin_unlock_irqrestore(&lat->lock, flags); \ + \ + return (ssize_t) count; \ +} \ +static DEVICE_ATTR(_name##_latency, S_IWUSR | S_IRUGO, \ + zfcp_sysfs_unit_##_name##_latency_show, \ + zfcp_sysfs_unit_##_name##_latency_store); + +ZFCP_DEFINE_LATENCY_ATTR(read); +ZFCP_DEFINE_LATENCY_ATTR(write); +ZFCP_DEFINE_LATENCY_ATTR(cmd); + +#define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ +static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \ + struct device_attribute *attr,\ + char *buf) \ +{ \ + struct scsi_device *sdev = to_scsi_device(dev); \ + struct zfcp_unit *unit = sdev->hostdata; \ + \ + return sprintf(buf, _format, _value); \ +} \ +static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); + +ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", + unit->port->adapter->ccw_device->dev.bus_id); +ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); +ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); + +struct device_attribute *zfcp_sysfs_sdev_attrs[] = { + &dev_attr_fcp_lun, + &dev_attr_wwpn, + &dev_attr_hba_id, + &dev_attr_read_latency, + &dev_attr_write_latency, + &dev_attr_cmd_latency, + NULL +}; + +static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *scsi_host = dev_to_shost(dev); + struct fsf_qtcb_bottom_port *qtcb_port; + struct zfcp_adapter *adapter; + int retval; + + adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; + if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) + return -EOPNOTSUPP; + + qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL); + if (!qtcb_port) + return -ENOMEM; + + retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); + if (!retval) + retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, + qtcb_port->cb_util, qtcb_port->a_util); + kfree(qtcb_port); + return retval; +} +static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL); + +static int zfcp_sysfs_adapter_ex_config(struct device *dev, + struct fsf_statistics_info *stat_inf) +{ + struct Scsi_Host *scsi_host = dev_to_shost(dev); + struct fsf_qtcb_bottom_config *qtcb_config; + struct zfcp_adapter *adapter; + int retval; + + adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; + if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) + return -EOPNOTSUPP; + + qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), + GFP_KERNEL); + if (!qtcb_config) + return -ENOMEM; + + retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); + if (!retval) + *stat_inf = qtcb_config->stat_info; + + kfree(qtcb_config); + return retval; +} + +#define ZFCP_SHOST_ATTR(_name, _format, _arg...) \ +static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ + struct device_attribute *attr,\ + char *buf) \ +{ \ + struct fsf_statistics_info stat_info; \ + int retval; \ + \ + retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); \ + if (retval) \ + return retval; \ + \ + return sprintf(buf, _format, ## _arg); \ +} \ +static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); + +ZFCP_SHOST_ATTR(requests, "%llu %llu %llu\n", + (unsigned long long) stat_info.input_req, + (unsigned long long) stat_info.output_req, + (unsigned long long) stat_info.control_req); + +ZFCP_SHOST_ATTR(megabytes, "%llu %llu\n", + (unsigned long long) stat_info.input_mb, + (unsigned long long) stat_info.output_mb); + +ZFCP_SHOST_ATTR(seconds_active, "%llu\n", + (unsigned long long) stat_info.seconds_act); + +struct device_attribute *zfcp_sysfs_shost_attrs[] = { + &dev_attr_utilization, + &dev_attr_requests, + &dev_attr_megabytes, + &dev_attr_seconds_active, + NULL +}; diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c deleted file mode 100644 index 3985f1f1c291..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * zfcp device driver - * - * sysfs attributes for CCW device. - * - * Copyright IBM Corporation 2002, 2008 - */ - -#include "zfcp_ext.h" - -/** - * ZFCP_DEFINE_ADAPTER_ATTR - * @_name: name of show attribute - * @_format: format string - * @_value: value to print - * - * Generates attributes for an adapter. - */ -#define ZFCP_DEFINE_ADAPTER_ATTR(_name, _format, _value) \ -static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct zfcp_adapter *adapter; \ - \ - adapter = dev_get_drvdata(dev); \ - return sprintf(buf, _format, _value); \ -} \ - \ -static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); - -ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status)); -ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn); -ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn); -ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id); -ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version); -ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version); -ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n", - adapter->hardware_version); -ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)); - -/** - * zfcp_sysfs_port_rescan - trigger manual port rescan - * @dev: pointer to belonging device - * @attr: pointer to struct device_attribute - * @buf: pointer to input buffer - * @count: number of bytes in buffer - */ -static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct zfcp_adapter *adapter; - int ret; - - adapter = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) - return -EBUSY; - - ret = zfcp_scan_ports(adapter); - - return ret ? ret : (ssize_t) count; -} -static DEVICE_ATTR(port_rescan, S_IWUSR, NULL, zfcp_sysfs_port_rescan_store); - -/** - * zfcp_sysfs_port_remove_store - remove a port from sysfs tree - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * @count: number of bytes in buffer - * - * Store function of the "port_remove" attribute of an adapter. - */ -static ssize_t -zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct zfcp_adapter *adapter; - struct zfcp_port *port; - wwn_t wwpn; - char *endp; - int retval = 0; - - down(&zfcp_data.config_sema); - - adapter = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { - retval = -EBUSY; - goto out; - } - - wwpn = simple_strtoull(buf, &endp, 0); - if ((endp + 1) < (buf + count)) { - retval = -EINVAL; - goto out; - } - - write_lock_irq(&zfcp_data.config_lock); - port = zfcp_get_port_by_wwpn(adapter, wwpn); - if (port && (atomic_read(&port->refcount) == 0)) { - zfcp_port_get(port); - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); - list_move(&port->list, &adapter->port_remove_lh); - } - else { - port = NULL; - } - write_unlock_irq(&zfcp_data.config_lock); - - if (!port) { - retval = -ENXIO; - goto out; - } - - zfcp_erp_port_shutdown(port, 0, 92, NULL); - zfcp_erp_wait(adapter); - zfcp_port_put(port); - zfcp_port_dequeue(port); - out: - up(&zfcp_data.config_sema); - return retval ? retval : (ssize_t) count; -} - -static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store); - -/** - * zfcp_sysfs_adapter_failed_store - failed state of adapter - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * @count: number of bytes in buffer - * - * Store function of the "failed" attribute of an adapter. - * If a "0" gets written to "failed", error recovery will be - * started for the belonging adapter. - */ -static ssize_t -zfcp_sysfs_adapter_failed_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct zfcp_adapter *adapter; - unsigned int val; - char *endp; - int retval = 0; - - down(&zfcp_data.config_sema); - - adapter = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { - retval = -EBUSY; - goto out; - } - - val = simple_strtoul(buf, &endp, 0); - if (((endp + 1) < (buf + count)) || (val != 0)) { - retval = -EINVAL; - goto out; - } - - zfcp_erp_modify_adapter_status(adapter, 44, NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); - zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 93, - NULL); - zfcp_erp_wait(adapter); - out: - up(&zfcp_data.config_sema); - return retval ? retval : (ssize_t) count; -} - -/** - * zfcp_sysfs_adapter_failed_show - failed state of adapter - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * - * Show function of "failed" attribute of adapter. Will be - * "0" if adapter is working, otherwise "1". - */ -static ssize_t -zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct zfcp_adapter *adapter; - - adapter = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_adapter_failed_show, - zfcp_sysfs_adapter_failed_store); - -static struct attribute *zfcp_adapter_attrs[] = { - &dev_attr_failed.attr, - &dev_attr_in_recovery.attr, - &dev_attr_port_remove.attr, - &dev_attr_port_rescan.attr, - &dev_attr_peer_wwnn.attr, - &dev_attr_peer_wwpn.attr, - &dev_attr_peer_d_id.attr, - &dev_attr_card_version.attr, - &dev_attr_lic_version.attr, - &dev_attr_status.attr, - &dev_attr_hardware_version.attr, - NULL -}; - -static struct attribute_group zfcp_adapter_attr_group = { - .attrs = zfcp_adapter_attrs, -}; - -/** - * zfcp_sysfs_create_adapter_files - create sysfs adapter files - * @dev: pointer to belonging device - * - * Create all attributes of the sysfs representation of an adapter. - */ -int -zfcp_sysfs_adapter_create_files(struct device *dev) -{ - return sysfs_create_group(&dev->kobj, &zfcp_adapter_attr_group); -} - -/** - * zfcp_sysfs_remove_adapter_files - remove sysfs adapter files - * @dev: pointer to belonging device - * - * Remove all attributes of the sysfs representation of an adapter. - */ -void -zfcp_sysfs_adapter_remove_files(struct device *dev) -{ - sysfs_remove_group(&dev->kobj, &zfcp_adapter_attr_group); -} diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c deleted file mode 100644 index e183ff8bdb2a..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_port.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * zfcp device driver - * - * sysfs attributes for zfcp port. - * - * Copyright IBM Corporation 2002, 2008 - */ - -#include "zfcp_ext.h" - -/** - * zfcp_sysfs_port_release - gets called when a struct device port is released - * @dev: pointer to belonging device - */ -void -zfcp_sysfs_port_release(struct device *dev) -{ - kfree(dev); -} - -/** - * ZFCP_DEFINE_PORT_ATTR - * @_name: name of show attribute - * @_format: format string - * @_value: value to print - * - * Generates attributes for a port. - */ -#define ZFCP_DEFINE_PORT_ATTR(_name, _format, _value) \ -static ssize_t zfcp_sysfs_port_##_name##_show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct zfcp_port *port; \ - \ - port = dev_get_drvdata(dev); \ - return sprintf(buf, _format, _value); \ -} \ - \ -static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL); - -ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status)); -ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)); -ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask - (ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status)); - -/** - * zfcp_sysfs_unit_add_store - add a unit to sysfs tree - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * @count: number of bytes in buffer - * - * Store function of the "unit_add" attribute of a port. - */ -static ssize_t -zfcp_sysfs_unit_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - fcp_lun_t fcp_lun; - char *endp; - struct zfcp_port *port; - struct zfcp_unit *unit; - int retval = -EINVAL; - - down(&zfcp_data.config_sema); - - port = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { - retval = -EBUSY; - goto out; - } - - fcp_lun = simple_strtoull(buf, &endp, 0); - if ((endp + 1) < (buf + count)) - goto out; - - unit = zfcp_unit_enqueue(port, fcp_lun); - if (IS_ERR(unit)) - goto out; - - retval = 0; - - zfcp_erp_unit_reopen(unit, 0, 94, NULL); - zfcp_erp_wait(unit->port->adapter); - zfcp_unit_put(unit); - out: - up(&zfcp_data.config_sema); - return retval ? retval : (ssize_t) count; -} - -static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); - -/** - * zfcp_sysfs_unit_remove_store - remove a unit from sysfs tree - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * @count: number of bytes in buffer - */ -static ssize_t -zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct zfcp_port *port; - struct zfcp_unit *unit; - fcp_lun_t fcp_lun; - char *endp; - int retval = 0; - - down(&zfcp_data.config_sema); - - port = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { - retval = -EBUSY; - goto out; - } - - fcp_lun = simple_strtoull(buf, &endp, 0); - if ((endp + 1) < (buf + count)) { - retval = -EINVAL; - goto out; - } - - write_lock_irq(&zfcp_data.config_lock); - unit = zfcp_get_unit_by_lun(port, fcp_lun); - if (unit && (atomic_read(&unit->refcount) == 0)) { - zfcp_unit_get(unit); - atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); - list_move(&unit->list, &port->unit_remove_lh); - } - else { - unit = NULL; - } - write_unlock_irq(&zfcp_data.config_lock); - - if (!unit) { - retval = -ENXIO; - goto out; - } - - zfcp_erp_unit_shutdown(unit, 0, 95, NULL); - zfcp_erp_wait(unit->port->adapter); - zfcp_unit_put(unit); - zfcp_unit_dequeue(unit); - out: - up(&zfcp_data.config_sema); - return retval ? retval : (ssize_t) count; -} - -static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); - -/** - * zfcp_sysfs_port_failed_store - failed state of port - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * @count: number of bytes in buffer - * - * Store function of the "failed" attribute of a port. - * If a "0" gets written to "failed", error recovery will be - * started for the belonging port. - */ -static ssize_t -zfcp_sysfs_port_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct zfcp_port *port; - unsigned int val; - char *endp; - int retval = 0; - - down(&zfcp_data.config_sema); - - port = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { - retval = -EBUSY; - goto out; - } - - val = simple_strtoul(buf, &endp, 0); - if (((endp + 1) < (buf + count)) || (val != 0)) { - retval = -EINVAL; - goto out; - } - - zfcp_erp_modify_port_status(port, 45, NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, 96, NULL); - zfcp_erp_wait(port->adapter); - out: - up(&zfcp_data.config_sema); - return retval ? retval : (ssize_t) count; -} - -/** - * zfcp_sysfs_port_failed_show - failed state of port - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * - * Show function of "failed" attribute of port. Will be - * "0" if port is working, otherwise "1". - */ -static ssize_t -zfcp_sysfs_port_failed_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct zfcp_port *port; - - port = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_port_failed_show, - zfcp_sysfs_port_failed_store); - -/** - * zfcp_port_common_attrs - * sysfs attributes that are common for all kind of fc ports. - */ -static struct attribute *zfcp_port_common_attrs[] = { - &dev_attr_failed.attr, - &dev_attr_in_recovery.attr, - &dev_attr_status.attr, - &dev_attr_access_denied.attr, - NULL -}; - -static struct attribute_group zfcp_port_common_attr_group = { - .attrs = zfcp_port_common_attrs, -}; - -/** - * zfcp_port_no_ns_attrs - * sysfs attributes not to be used for nameserver ports. - */ -static struct attribute *zfcp_port_no_ns_attrs[] = { - &dev_attr_unit_add.attr, - &dev_attr_unit_remove.attr, - NULL -}; - -static struct attribute_group zfcp_port_no_ns_attr_group = { - .attrs = zfcp_port_no_ns_attrs, -}; - -/** - * zfcp_sysfs_port_create_files - create sysfs port files - * @dev: pointer to belonging device - * - * Create all attributes of the sysfs representation of a port. - */ -int -zfcp_sysfs_port_create_files(struct device *dev, u32 flags) -{ - int retval; - - retval = sysfs_create_group(&dev->kobj, &zfcp_port_common_attr_group); - - if ((flags & ZFCP_STATUS_PORT_WKA) || retval) - return retval; - - retval = sysfs_create_group(&dev->kobj, &zfcp_port_no_ns_attr_group); - if (retval) - sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); - - return retval; -} - -/** - * zfcp_sysfs_port_remove_files - remove sysfs port files - * @dev: pointer to belonging device - * - * Remove all attributes of the sysfs representation of a port. - */ -void -zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) -{ - sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); - if (!(flags & ZFCP_STATUS_PORT_WKA)) - sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group); -} diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c deleted file mode 100644 index 587d9e3e12d2..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_unit.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * zfcp device driver - * - * sysfs interface for zfcp unit. - * - * Copyright IBM Corporation 2002, 2008 - */ - -#include "zfcp_ext.h" - -/** - * zfcp_sysfs_unit_release - gets called when a struct device unit is released - * @dev: pointer to belonging device - */ -void -zfcp_sysfs_unit_release(struct device *dev) -{ - kfree(dev); -} - -/** - * ZFCP_DEFINE_UNIT_ATTR - * @_name: name of show attribute - * @_format: format string - * @_value: value to print - * - * Generates attribute for a unit. - */ -#define ZFCP_DEFINE_UNIT_ATTR(_name, _format, _value) \ -static ssize_t zfcp_sysfs_unit_##_name##_show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct zfcp_unit *unit; \ - \ - unit = dev_get_drvdata(dev); \ - return sprintf(buf, _format, _value); \ -} \ - \ -static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_unit_##_name##_show, NULL); - -ZFCP_DEFINE_UNIT_ATTR(status, "0x%08x\n", atomic_read(&unit->status)); -ZFCP_DEFINE_UNIT_ATTR(in_recovery, "%d\n", atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)); -ZFCP_DEFINE_UNIT_ATTR(access_denied, "%d\n", atomic_test_mask - (ZFCP_STATUS_COMMON_ACCESS_DENIED, &unit->status)); -ZFCP_DEFINE_UNIT_ATTR(access_shared, "%d\n", atomic_test_mask - (ZFCP_STATUS_UNIT_SHARED, &unit->status)); -ZFCP_DEFINE_UNIT_ATTR(access_readonly, "%d\n", atomic_test_mask - (ZFCP_STATUS_UNIT_READONLY, &unit->status)); - -/** - * zfcp_sysfs_unit_failed_store - failed state of unit - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * @count: number of bytes in buffer - * - * Store function of the "failed" attribute of a unit. - * If a "0" gets written to "failed", error recovery will be - * started for the belonging unit. - */ -static ssize_t -zfcp_sysfs_unit_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct zfcp_unit *unit; - unsigned int val; - char *endp; - int retval = 0; - - down(&zfcp_data.config_sema); - unit = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status)) { - retval = -EBUSY; - goto out; - } - - val = simple_strtoul(buf, &endp, 0); - if (((endp + 1) < (buf + count)) || (val != 0)) { - retval = -EINVAL; - goto out; - } - - zfcp_erp_modify_unit_status(unit, 46, NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, 97, NULL); - zfcp_erp_wait(unit->port->adapter); - out: - up(&zfcp_data.config_sema); - return retval ? retval : (ssize_t) count; -} - -/** - * zfcp_sysfs_unit_failed_show - failed state of unit - * @dev: pointer to belonging device - * @buf: pointer to input buffer - * - * Show function of "failed" attribute of unit. Will be - * "0" if unit is working, otherwise "1". - */ -static ssize_t -zfcp_sysfs_unit_failed_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct zfcp_unit *unit; - - unit = dev_get_drvdata(dev); - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_unit_failed_show, - zfcp_sysfs_unit_failed_store); - -static struct attribute *zfcp_unit_attrs[] = { - &dev_attr_failed.attr, - &dev_attr_in_recovery.attr, - &dev_attr_status.attr, - &dev_attr_access_denied.attr, - &dev_attr_access_shared.attr, - &dev_attr_access_readonly.attr, - NULL -}; - -static struct attribute_group zfcp_unit_attr_group = { - .attrs = zfcp_unit_attrs, -}; - -/** - * zfcp_sysfs_create_unit_files - create sysfs unit files - * @dev: pointer to belonging device - * - * Create all attributes of the sysfs representation of a unit. - */ -int -zfcp_sysfs_unit_create_files(struct device *dev) -{ - return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group); -} - -/** - * zfcp_sysfs_remove_unit_files - remove sysfs unit files - * @dev: pointer to belonging device - * - * Remove all attributes of the sysfs representation of a unit. - */ -void -zfcp_sysfs_unit_remove_files(struct device *dev) -{ - sysfs_remove_group(&dev->kobj, &zfcp_unit_attr_group); -} -- cgit v1.2.3 From c41f8cbddd4e0e72951e0575165dea8ea26f1c4b Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 2 Jul 2008 10:56:39 +0200 Subject: [SCSI] zfcp: zfcp_fsf cleanup. Code cleanup for the zfcp_fsf.c file. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 4 +- drivers/s390/scsi/zfcp_dbf.c | 2 +- drivers/s390/scsi/zfcp_def.h | 31 +- drivers/s390/scsi/zfcp_ext.h | 12 +- drivers/s390/scsi/zfcp_fc.c | 11 +- drivers/s390/scsi/zfcp_fsf.c | 4135 +++++++++++++++-------------------------- drivers/s390/scsi/zfcp_fsf.h | 31 +- drivers/s390/scsi/zfcp_qdio.c | 6 +- drivers/s390/scsi/zfcp_scsi.c | 5 +- 9 files changed, 1585 insertions(+), 2652 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 5b9ca3cde898..90abfd06ed55 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -433,7 +433,7 @@ static void zfcp_dummy_release(struct device *dev) int zfcp_status_read_refill(struct zfcp_adapter *adapter) { while (atomic_read(&adapter->stat_miss) > 0) - if (zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL)) { + if (zfcp_fsf_status_read(adapter)) { if (atomic_read(&adapter->stat_miss) >= 16) { zfcp_erp_adapter_reopen(adapter, 0, 103, NULL); return 1; @@ -518,10 +518,10 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) spin_lock_init(&adapter->san_dbf_lock); spin_lock_init(&adapter->scsi_dbf_lock); spin_lock_init(&adapter->rec_dbf_lock); + spin_lock_init(&adapter->req_q.lock); rwlock_init(&adapter->erp_lock); rwlock_init(&adapter->abort_lock); - rwlock_init(&adapter->req_q.lock); sema_init(&adapter->erp_ready_sem, 0); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 566627f3a69d..36169c6944fd 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -961,7 +961,7 @@ void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) zfcp_san_dbf_event_els("iels", 1, fsf_req, buf->d_id, fc_host_port_id(adapter->scsi_host), - *(u8 *)buf->payload, (void *)buf->payload, + buf->payload.data[0], (void *)buf->payload.data, length); } diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 2af043a5c74b..206b6e7a8bfd 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -76,11 +76,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) #define ZFCP_DEVICE_MODEL 0x03 #define ZFCP_DEVICE_MODEL_PRIV 0x04 -/* allow as many chained SBALs as are supported by hardware */ -#define ZFCP_MAX_SBALS_PER_REQ FSF_MAX_SBALS_PER_REQ -#define ZFCP_MAX_SBALS_PER_CT_REQ FSF_MAX_SBALS_PER_REQ -#define ZFCP_MAX_SBALS_PER_ELS_REQ FSF_MAX_SBALS_PER_ELS_REQ - /* DMQ bug workaround: don't use last SBALE */ #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) @@ -89,21 +84,17 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) /* max. number of (data buffer) SBALEs in largest SBAL chain */ #define ZFCP_MAX_SBALES_PER_REQ \ - (ZFCP_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2) + (FSF_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2) /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ #define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8) /* max. number of (data buffer) SBALEs in largest SBAL chain multiplied with number of sectors per 4k block */ -#define ZFCP_SBAL_TIMEOUT (5*HZ) - #define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */ /********************* FSF SPECIFIC DEFINES *********************************/ -#define ZFCP_ULP_INFO_VERSION 26 -#define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION /* ATTENTION: value must not be used by hardware */ #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 @@ -121,8 +112,6 @@ typedef unsigned long long fcp_lun_t; /* data length field may be at variable position in FCP-2 FCP_CMND IU */ typedef unsigned int fcp_dl_t; -#define ZFCP_FC_SERVICE_CLASS_DEFAULT FSF_CLASS_3 - /* timeout for name-server lookup (in seconds) */ #define ZFCP_NS_GID_PN_TIMEOUT 10 @@ -228,7 +217,6 @@ struct fcp_logo { * FC-FS stuff */ #define R_A_TOV 10 /* seconds */ -#define ZFCP_ELS_TIMEOUT (2 * R_A_TOV) #define ZFCP_LS_RLS 0x0f #define ZFCP_LS_ADISC 0x52 @@ -521,7 +509,7 @@ struct zfcp_qdio_queue { in queue (free_count>0) */ atomic_t count; /* number of free buffers in queue */ - rwlock_t lock; /* lock for operations on queue */ + spinlock_t lock; /* lock for operations on queue */ int pci_batch; /* SBALs since PCI indication was last set */ }; @@ -686,7 +674,7 @@ struct zfcp_fsf_req { u32 fsf_command; /* FSF Command copy */ struct fsf_qtcb *qtcb; /* address of associated QTCB */ u32 seq_no; /* Sequence number of request */ - unsigned long data; /* private data of request */ + void *data; /* private data of request */ struct timer_list timer; /* used for erp or scsi er */ struct zfcp_erp_action *erp_action; /* used if this request is issued on behalf of erp */ @@ -694,10 +682,9 @@ struct zfcp_fsf_req { from emergency pool */ unsigned long long issued; /* request sent time (STCK) */ struct zfcp_unit *unit; + void (*handler)(struct zfcp_fsf_req *); }; -typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*); - /* driver data */ struct zfcp_data { struct scsi_host_template scsi_host_template; @@ -730,7 +717,6 @@ struct zfcp_fsf_req_qtcb { /********************** ZFCP SPECIFIC DEFINES ********************************/ #define ZFCP_REQ_AUTO_CLEANUP 0x00000002 -#define ZFCP_WAIT_FOR_SBAL 0x00000004 #define ZFCP_REQ_NO_QTCB 0x00000008 #define ZFCP_SET 0x00000100 @@ -753,15 +739,6 @@ static inline int zfcp_reqlist_hash(unsigned long req_id) return req_id % REQUEST_LIST_SIZE; } -static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter, - struct zfcp_fsf_req *fsf_req) -{ - unsigned int idx; - - idx = zfcp_reqlist_hash(fsf_req->req_id); - list_add_tail(&fsf_req->list, &adapter->req_list[idx]); -} - static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter, struct zfcp_fsf_req *fsf_req) { diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index f0d6947ae073..2845693413fb 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -70,21 +70,19 @@ extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); -extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); +extern int zfcp_fsf_status_read(struct zfcp_adapter *); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); -extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, - unsigned long *, struct zfcp_fsf_req **) - __acquires(adapter->req_q.lock); extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, struct zfcp_erp_action *); extern int zfcp_fsf_send_els(struct zfcp_send_els *); extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, struct zfcp_unit *, struct scsi_cmnd *, int, int); -extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); +extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); -extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management( - struct zfcp_adapter *, struct zfcp_unit *, u8, int); +extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *, + struct zfcp_unit *, u8, + int); extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command( unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index fbe2c76df4d7..e984469bb98b 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -83,8 +83,8 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) u16 no_entries; u32 range_mask; - fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; - fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; + fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload.data; + fcp_rscn_element = (struct fcp_rscn_element *) fcp_rscn_head; /* see FC-FS */ no_entries = fcp_rscn_head->payload_len / @@ -135,7 +135,7 @@ static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) struct fsf_status_read_buffer *status_buffer = (struct fsf_status_read_buffer *)req->data; struct fsf_plogi *els_plogi = - (struct fsf_plogi *) status_buffer->payload; + (struct fsf_plogi *) status_buffer->payload.data; zfcp_fc_incoming_wwpn(req, els_plogi->serv_param.wwpn); } @@ -144,7 +144,8 @@ static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req) { struct fsf_status_read_buffer *status_buffer = (struct fsf_status_read_buffer *)req->data; - struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; + struct fcp_logo *els_logo = + (struct fcp_logo *) status_buffer->payload.data; zfcp_fc_incoming_wwpn(req, els_logo->nport_wwpn); } @@ -157,7 +158,7 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) { struct fsf_status_read_buffer *status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; - unsigned int els_type = status_buffer->payload[0]; + unsigned int els_type = status_buffer->payload.data[0]; zfcp_san_dbf_event_incoming_els(fsf_req); if (els_type == LS_PLOGI) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 22e3aa612786..e6d815593b49 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -8,35 +8,6 @@ #include "zfcp_ext.h" -static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *); -static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_send_fcp_command_task_management_handler( - struct zfcp_fsf_req *); -static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); -static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); -static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); -static inline int zfcp_fsf_req_sbal_check( - unsigned long *, struct zfcp_qdio_queue *, int); -static inline int zfcp_use_one_sbal( - struct scatterlist *, int, struct scatterlist *, int); -static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int); -static int zfcp_fsf_req_send(struct zfcp_fsf_req *); -static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *); -static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *); -static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); -static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *, u8, - struct fsf_link_down_info *); -static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); - /* association between FSF command and FSF QTCB type */ static u32 fsf_qtcb_type[] = { [FSF_QTCB_FCP_CMND] = FSF_IO_COMMAND, @@ -54,21 +25,19 @@ static u32 fsf_qtcb_type[] = { [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND }; -static const char zfcp_act_subtable_type[5][8] = { +static const char *zfcp_act_subtable_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" }; static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) { - u16 subtable = (table & 0xffff0000) >> 16; + u16 subtable = table >> 16; u16 rule = table & 0xffff; - if (subtable > 0 && - subtable < ARRAY_SIZE(zfcp_act_subtable_type)) { + if (subtable && subtable < ARRAY_SIZE(zfcp_act_subtable_type)) dev_warn(&adapter->ccw_device->dev, "Access denied in subtable %s, rule %d.\n", zfcp_act_subtable_type[subtable], rule); - } } static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req, @@ -106,90 +75,27 @@ static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ERROR; } -/****************************************************************/ -/*************** FSF related Functions *************************/ -/****************************************************************/ - -/* - * function: zfcp_fsf_req_alloc - * - * purpose: Obtains an fsf_req and potentially a qtcb (for all but - * unsolicited requests) via helper functions - * Does some initial fsf request set-up. - * - * returns: pointer to allocated fsf_req if successfull - * NULL otherwise - * - * locks: none - * - */ -static struct zfcp_fsf_req * -zfcp_fsf_req_alloc(mempool_t *pool, int req_flags) -{ - size_t size; - void *ptr; - struct zfcp_fsf_req *fsf_req = NULL; - - if (req_flags & ZFCP_REQ_NO_QTCB) - size = sizeof(struct zfcp_fsf_req); - else - size = sizeof(struct zfcp_fsf_req_qtcb); - - if (likely(pool)) - ptr = mempool_alloc(pool, GFP_ATOMIC); - else { - if (req_flags & ZFCP_REQ_NO_QTCB) - ptr = kmalloc(size, GFP_ATOMIC); - else - ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, - GFP_ATOMIC); - } - - if (unlikely(!ptr)) - goto out; - - memset(ptr, 0, size); - - if (req_flags & ZFCP_REQ_NO_QTCB) { - fsf_req = (struct zfcp_fsf_req *) ptr; - } else { - fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req; - fsf_req->qtcb = &((struct zfcp_fsf_req_qtcb *) ptr)->qtcb; - } - - fsf_req->pool = pool; - - out: - return fsf_req; -} - -/* - * function: zfcp_fsf_req_free - * - * purpose: Frees the memory of an fsf_req (and potentially a qtcb) or - * returns it into the pool via helper functions. - * - * returns: sod all - * - * locks: none +/** + * zfcp_fsf_req_free - free memory used by fsf request + * @fsf_req: pointer to struct zfcp_fsf_req */ -void -zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) +void zfcp_fsf_req_free(struct zfcp_fsf_req *req) { - if (likely(fsf_req->pool)) { - mempool_free(fsf_req, fsf_req->pool); + if (likely(req->pool)) { + mempool_free(req, req->pool); return; } - if (fsf_req->qtcb) { - kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req); + if (req->qtcb) { + kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req); return; } - - kfree(fsf_req); } -/* +/** + * zfcp_fsf_req_dismiss_all - dismiss all fsf requests + * @adapter: pointer to struct zfcp_adapter + * * Never ever call this without shutting down the adapter first. * Otherwise the adapter would continue using and corrupting s390 storage. * Included BUG_ON() call to ensure this is done. @@ -197,1815 +103,1359 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) */ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) { - struct zfcp_fsf_req *fsf_req, *tmp; + struct zfcp_fsf_req *req, *tmp; unsigned long flags; LIST_HEAD(remove_queue); unsigned int i; - BUG_ON(atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)); + BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP); spin_lock_irqsave(&adapter->req_list_lock, flags); for (i = 0; i < REQUEST_LIST_SIZE; i++) list_splice_init(&adapter->req_list[i], &remove_queue); spin_unlock_irqrestore(&adapter->req_list_lock, flags); - list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) { - list_del(&fsf_req->list); - fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; - zfcp_fsf_req_complete(fsf_req); - } -} - -/* - * function: zfcp_fsf_req_complete - * - * purpose: Updates active counts and timers for openfcp-reqs - * May cleanup request after req_eval returns - * - * returns: 0 - success - * !0 - failure - * - * context: - */ -int -zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) -{ - int retval = 0; - int cleanup; - - if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { - /* - * Note: all cleanup handling is done in the callchain of - * the function call-chain below. - */ - zfcp_fsf_status_read_handler(fsf_req); - goto out; - } else { - del_timer(&fsf_req->timer); - zfcp_fsf_protstatus_eval(fsf_req); - } - - /* - * fsf_req may be deleted due to waking up functions, so - * cleanup is saved here and used later - */ - if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) - cleanup = 1; - else - cleanup = 0; - - fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; - - /* cleanup request if requested by initiator */ - if (likely(cleanup)) { - /* - * lock must not be held here since it will be - * grabed by the called routine, too - */ - zfcp_fsf_req_free(fsf_req); - } else { - /* notify initiator waiting for the requests completion */ - /* - * FIXME: Race! We must not access fsf_req here as it might have been - * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED - * flag. It's an improbable case. But, we have the same paranoia for - * the cleanup flag already. - * Might better be handled using complete()? - * (setting the flag and doing wakeup ought to be atomic - * with regard to checking the flag as long as waitqueue is - * part of the to be released structure) - */ - wake_up(&fsf_req->completion_wq); - } - - out: - return retval; -} - -/* - * function: zfcp_fsf_protstatus_eval - * - * purpose: evaluates the QTCB of the finished FSF request - * and initiates appropriate actions - * (usually calling FSF command specific handlers) - * - * returns: - * - * context: - * - * locks: - */ -static int -zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) -{ - int retval = 0; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct fsf_qtcb *qtcb = fsf_req->qtcb; - union fsf_prot_status_qual *prot_status_qual = - &qtcb->prefix.prot_status_qual; - - zfcp_hba_dbf_event_fsf_response(fsf_req); - - if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ - goto skip_protstatus; - } - - /* evaluate FSF Protocol Status */ - switch (qtcb->prefix.prot_status) { - - case FSF_PROT_GOOD: - case FSF_PROT_FSF_STATUS_PRESENTED: - break; - - case FSF_PROT_QTCB_VERSION_ERROR: - dev_err(&adapter->ccw_device->dev, - "The QTCB version requested by zfcp (0x%x) is not " - "supported by the FCP adapter (lowest supported 0x%x, " - "highest supported 0x%x).\n", - ZFCP_QTCB_VERSION, prot_status_qual->word[0], - prot_status_qual->word[1]); - zfcp_erp_adapter_shutdown(adapter, 0, 117, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_PROT_SEQ_NUMB_ERROR: - zfcp_erp_adapter_reopen(adapter, 0, 98, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_PROT_UNSUPP_QTCB_TYPE: - dev_err(&adapter->ccw_device->dev, - "Packet header type used by the device driver is " - "incompatible with that used on the adapter.\n"); - zfcp_erp_adapter_shutdown(adapter, 0, 118, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_PROT_HOST_CONNECTION_INITIALIZING: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, - &(adapter->status)); - break; - - case FSF_PROT_DUPLICATE_REQUEST_ID: - dev_err(&adapter->ccw_device->dev, - "The request identifier 0x%Lx is ambiguous.\n", - (unsigned long long)qtcb->bottom.support.req_handle); - zfcp_erp_adapter_shutdown(adapter, 0, 78, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_PROT_LINK_DOWN: - zfcp_fsf_link_down_info_eval(fsf_req, 37, - &prot_status_qual->link_down_info); - /* FIXME: reopening adapter now? better wait for link up */ - zfcp_erp_adapter_reopen(adapter, 0, 79, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_PROT_REEST_QUEUE: - /* All ports should be marked as ready to run again */ - zfcp_erp_modify_adapter_status(adapter, 28, NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); - zfcp_erp_adapter_reopen(adapter, - ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED - | ZFCP_STATUS_COMMON_ERP_FAILED, - 99, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_PROT_ERROR_STATE: - zfcp_erp_adapter_reopen(adapter, 0, 100, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - default: - dev_err(&adapter->ccw_device->dev, - "Transfer protocol status information" - "provided by the adapter (0x%x) " - "is not compatible with the device driver.\n", - qtcb->prefix.prot_status); - zfcp_erp_adapter_shutdown(adapter, 0, 119, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + list_for_each_entry_safe(req, tmp, &remove_queue, list) { + list_del(&req->list); + req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; + zfcp_fsf_req_complete(req); } - - skip_protstatus: - /* - * always call specific handlers to give them a chance to do - * something meaningful even in error cases - */ - zfcp_fsf_fsfstatus_eval(fsf_req); - return retval; } -/* - * function: zfcp_fsf_fsfstatus_eval - * - * purpose: evaluates FSF status of completed FSF request - * and acts accordingly - * - * returns: - */ -static int -zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) { - int retval = 0; - - if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { - goto skip_fsfstatus; - } - - /* evaluate FSF Status */ - switch (fsf_req->qtcb->header.fsf_status) { - case FSF_UNKNOWN_COMMAND: - dev_err(&fsf_req->adapter->ccw_device->dev, - "Command issued by the device driver (0x%x) is " - "not known by the adapter.\n", - fsf_req->qtcb->header.fsf_command); - zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 120, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_ADAPTER_STATUS_AVAILABLE: - zfcp_fsf_fsfstatus_qual_eval(fsf_req); - break; - } - - skip_fsfstatus: - /* - * always call specific handlers to give them a chance to do - * something meaningful even in error cases - */ - zfcp_fsf_req_dispatch(fsf_req); + struct fsf_status_read_buffer *sr_buf = req->data; + struct zfcp_adapter *adapter = req->adapter; + struct zfcp_port *port; + int d_id = sr_buf->d_id & ZFCP_DID_MASK; + unsigned long flags; - return retval; + read_lock_irqsave(&zfcp_data.config_lock, flags); + list_for_each_entry(port, &adapter->port_list_head, list) + if (port->d_id == d_id) { + read_unlock_irqrestore(&zfcp_data.config_lock, flags); + switch (sr_buf->status_subtype) { + case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT: + zfcp_erp_port_reopen(port, 0, 101, req); + break; + case FSF_STATUS_READ_SUB_ERROR_PORT: + zfcp_erp_port_shutdown(port, 0, 122, req); + break; + } + return; + } + read_unlock_irqrestore(&zfcp_data.config_lock, flags); } -/* - * function: zfcp_fsf_fsfstatus_qual_eval - * - * purpose: evaluates FSF status-qualifier of completed FSF request - * and acts accordingly - * - * returns: - */ -static int -zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req) { - int retval = 0; - - switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { - case FSF_SQ_FCP_RSP_AVAILABLE: - break; - case FSF_SQ_RETRY_IF_POSSIBLE: - /* The SCSI-stack may now issue retries or escalate */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_SQ_COMMAND_ABORTED: - /* Carry the aborted state on to upper layer */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED; - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_SQ_NO_RECOM: - dev_err(&fsf_req->adapter->ccw_device->dev, - "No recommendation could be given for a " - "problem on the adapter.\n"); - zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 121, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_SQ_ULP_PROGRAMMING_ERROR: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - case FSF_SQ_NO_RETRY_POSSIBLE: - case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - /* dealt with in the respective functions */ - break; - default: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - } + struct zfcp_adapter *adapter = req->adapter; + struct fsf_status_read_buffer *sr_buf = req->data; + struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; - return retval; + dev_warn(&adapter->ccw_device->dev, + "Warning: bit error threshold data " + "received for the adapter: " + "link failures = %i, loss of sync errors = %i, " + "loss of signal errors = %i, " + "primitive sequence errors = %i, " + "invalid transmission word errors = %i, " + "CRC errors = %i).\n", + err->link_failure_error_count, + err->loss_of_sync_error_count, + err->loss_of_signal_error_count, + err->primitive_sequence_error_count, + err->invalid_transmission_word_error_count, + err->crc_error_count); + dev_warn(&adapter->ccw_device->dev, + "Additional bit error threshold data of the adapter: " + "primitive sequence event time-outs = %i, " + "elastic buffer overrun errors = %i, " + "advertised receive buffer-to-buffer credit = %i, " + "current receice buffer-to-buffer credit = %i, " + "advertised transmit buffer-to-buffer credit = %i, " + "current transmit buffer-to-buffer credit = %i).\n", + err->primitive_sequence_event_timeout_count, + err->elastic_buffer_overrun_error_count, + err->advertised_receive_b2b_credit, + err->current_receive_b2b_credit, + err->advertised_transmit_b2b_credit, + err->current_transmit_b2b_credit); } -/** - * zfcp_fsf_link_down_info_eval - evaluate link down information block - */ -static void -zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *fsf_req, u8 id, - struct fsf_link_down_info *link_down) +static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id, + struct fsf_link_down_info *link_down) { - struct zfcp_adapter *adapter = fsf_req->adapter; + struct zfcp_adapter *adapter = req->adapter; - if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, - &adapter->status)) + if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) return; atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); - if (link_down == NULL) + if (!link_down) goto out; switch (link_down->error_code) { case FSF_PSQ_LINK_NO_LIGHT: - dev_warn(&fsf_req->adapter->ccw_device->dev, - "The local link is down: " - "no light detected.\n"); + dev_warn(&req->adapter->ccw_device->dev, + "The local link is down: no light detected.\n"); break; case FSF_PSQ_LINK_WRAP_PLUG: - dev_warn(&fsf_req->adapter->ccw_device->dev, - "The local link is down: " - "wrap plug detected.\n"); + dev_warn(&req->adapter->ccw_device->dev, + "The local link is down: wrap plug detected.\n"); break; case FSF_PSQ_LINK_NO_FCP: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The local link is down: " "adjacent node on link does not support FCP.\n"); break; case FSF_PSQ_LINK_FIRMWARE_UPDATE: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The local link is down: " "firmware update in progress.\n"); break; case FSF_PSQ_LINK_INVALID_WWPN: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The local link is down: " "duplicate or invalid WWPN detected.\n"); break; case FSF_PSQ_LINK_NO_NPIV_SUPPORT: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The local link is down: " "no support for NPIV by Fabric.\n"); break; case FSF_PSQ_LINK_NO_FCP_RESOURCES: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The local link is down: " "out of resource in FCP daughtercard.\n"); break; case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The local link is down: " "out of resource in Fabric.\n"); break; case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The local link is down: " "unable to login to Fabric.\n"); break; case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "WWPN assignment file corrupted on adapter.\n"); break; case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "Mode table corrupted on adapter.\n"); break; case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "No WWPN for assignment table on adapter.\n"); break; default: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The local link to adapter is down.\n"); } - - out: - zfcp_erp_adapter_failed(adapter, id, fsf_req); +out: + zfcp_erp_adapter_failed(adapter, id, req); } -/* - * function: zfcp_fsf_req_dispatch - * - * purpose: calls the appropriate command specific handler - * - * returns: - */ -static int -zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) { - struct zfcp_erp_action *erp_action = fsf_req->erp_action; - int retval = 0; - - - switch (fsf_req->fsf_command) { - - case FSF_QTCB_FCP_CMND: - zfcp_fsf_send_fcp_command_handler(fsf_req); - break; - - case FSF_QTCB_ABORT_FCP_CMND: - zfcp_fsf_abort_fcp_command_handler(fsf_req); - break; - - case FSF_QTCB_SEND_GENERIC: - zfcp_fsf_send_ct_handler(fsf_req); - break; + struct zfcp_adapter *adapter = req->adapter; + struct fsf_status_read_buffer *sr_buf = req->data; + struct fsf_link_down_info *ldi = + (struct fsf_link_down_info *) &sr_buf->payload; - case FSF_QTCB_OPEN_PORT_WITH_DID: - zfcp_fsf_open_port_handler(fsf_req); + switch (sr_buf->status_subtype) { + case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: + dev_warn(&adapter->ccw_device->dev, + "Physical link is down.\n"); + zfcp_fsf_link_down_info_eval(req, 38, ldi); break; - - case FSF_QTCB_OPEN_LUN: - zfcp_fsf_open_unit_handler(fsf_req); + case FSF_STATUS_READ_SUB_FDISC_FAILED: + dev_warn(&adapter->ccw_device->dev, + "Local link is down " + "due to failed FDISC login.\n"); + zfcp_fsf_link_down_info_eval(req, 39, ldi); break; + case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: + dev_warn(&adapter->ccw_device->dev, + "Local link is down " + "due to firmware update on adapter.\n"); + zfcp_fsf_link_down_info_eval(req, 40, NULL); + }; +} - case FSF_QTCB_CLOSE_LUN: - zfcp_fsf_close_unit_handler(fsf_req); - break; +static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) +{ + struct zfcp_adapter *adapter = req->adapter; + struct fsf_status_read_buffer *sr_buf = req->data; - case FSF_QTCB_CLOSE_PORT: - zfcp_fsf_close_port_handler(fsf_req); - break; + if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { + zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf); + mempool_free(sr_buf, adapter->pool.data_status_read); + zfcp_fsf_req_free(req); + return; + } - case FSF_QTCB_CLOSE_PHYSICAL_PORT: - zfcp_fsf_close_physical_port_handler(fsf_req); - break; + zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf); - case FSF_QTCB_EXCHANGE_CONFIG_DATA: - zfcp_fsf_exchange_config_data_handler(fsf_req); + switch (sr_buf->status_type) { + case FSF_STATUS_READ_PORT_CLOSED: + zfcp_fsf_status_read_port_closed(req); break; - - case FSF_QTCB_EXCHANGE_PORT_DATA: - zfcp_fsf_exchange_port_data_handler(fsf_req); + case FSF_STATUS_READ_INCOMING_ELS: + zfcp_fc_incoming_els(req); break; - - case FSF_QTCB_SEND_ELS: - zfcp_fsf_send_els_handler(fsf_req); + case FSF_STATUS_READ_SENSE_DATA_AVAIL: break; - - case FSF_QTCB_DOWNLOAD_CONTROL_FILE: - zfcp_fsf_control_file_handler(fsf_req); + case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: + zfcp_fsf_bit_error_threshold(req); break; - - case FSF_QTCB_UPLOAD_CONTROL_FILE: - zfcp_fsf_control_file_handler(fsf_req); + case FSF_STATUS_READ_LINK_DOWN: + zfcp_fsf_status_read_link_down(req); + break; + case FSF_STATUS_READ_LINK_UP: + dev_info(&adapter->ccw_device->dev, + "Local link was replugged.\n"); + /* All ports should be marked as ready to run again */ + zfcp_erp_modify_adapter_status(adapter, 30, NULL, + ZFCP_STATUS_COMMON_RUNNING, + ZFCP_SET); + zfcp_erp_adapter_reopen(adapter, + ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | + ZFCP_STATUS_COMMON_ERP_FAILED, + 102, req); + break; + case FSF_STATUS_READ_NOTIFICATION_LOST: + if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) + zfcp_erp_adapter_access_changed(adapter, 135, req); + if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) + schedule_work(&adapter->scan_work); + break; + case FSF_STATUS_READ_CFDC_UPDATED: + zfcp_erp_adapter_access_changed(adapter, 136, req); + break; + case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: + adapter->adapter_features = sr_buf->payload.word[0]; break; } - if (!erp_action) - return retval; + mempool_free(sr_buf, adapter->pool.data_status_read); + zfcp_fsf_req_free(req); - zfcp_erp_async_handler(erp_action, 0); + atomic_inc(&adapter->stat_miss); + schedule_work(&adapter->stat_work); +} - return retval; +static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) +{ + switch (req->qtcb->header.fsf_status_qual.word[0]) { + case FSF_SQ_FCP_RSP_AVAILABLE: + case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: + case FSF_SQ_NO_RETRY_POSSIBLE: + case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: + return; + case FSF_SQ_COMMAND_ABORTED: + req->status |= ZFCP_STATUS_FSFREQ_ABORTED; + break; + case FSF_SQ_NO_RECOM: + dev_err(&req->adapter->ccw_device->dev, + "No recommendation could be given for a " + "problem on the adapter.\n"); + zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req); + break; + } + /* all non-return stats set FSFREQ_ERROR*/ + req->status |= ZFCP_STATUS_FSFREQ_ERROR; } -/* - * function: zfcp_fsf_status_read - * - * purpose: initiates a Status Read command at the specified adapter - * - * returns: - */ -int -zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) +static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req) { - struct zfcp_fsf_req *fsf_req; - struct fsf_status_read_buffer *status_buffer; - unsigned long lock_flags; - volatile struct qdio_buffer_element *sbale; - int retval; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, - req_flags | ZFCP_REQ_NO_QTCB, - adapter->pool.fsf_req_status_read, - &lock_flags, &fsf_req); - if (retval < 0) - goto failed_req_create; - - sbale = zfcp_qdio_sbale_req(fsf_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; - sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; - fsf_req->sbale_curr = 2; - - retval = -ENOMEM; - status_buffer = - mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); - if (!status_buffer) - goto failed_buf; - memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer)); - fsf_req->data = (unsigned long) status_buffer; + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) + return; - /* insert pointer to respective buffer */ - sbale = zfcp_qdio_sbale_curr(fsf_req); - sbale->addr = (void *) status_buffer; - sbale->length = sizeof(struct fsf_status_read_buffer); + switch (req->qtcb->header.fsf_status) { + case FSF_UNKNOWN_COMMAND: + dev_err(&req->adapter->ccw_device->dev, + "Command issued by the device driver (0x%x) is " + "not known by the adapter.\n", + req->qtcb->header.fsf_command); + zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_ADAPTER_STATUS_AVAILABLE: + zfcp_fsf_fsfstatus_qual_eval(req); + break; + } +} - retval = zfcp_fsf_req_send(fsf_req); - if (retval) - goto failed_req_send; +static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) +{ + struct zfcp_adapter *adapter = req->adapter; + struct fsf_qtcb *qtcb = req->qtcb; + union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual; - goto out; + zfcp_hba_dbf_event_fsf_response(req); - failed_req_send: - mempool_free(status_buffer, adapter->pool.data_status_read); + if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ + return; + } - failed_buf: - zfcp_fsf_req_free(fsf_req); - failed_req_create: - zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); - out: - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return retval; + switch (qtcb->prefix.prot_status) { + case FSF_PROT_GOOD: + case FSF_PROT_FSF_STATUS_PRESENTED: + return; + case FSF_PROT_QTCB_VERSION_ERROR: + dev_err(&adapter->ccw_device->dev, + "The QTCB version requested by zfcp (0x%x) is not " + "supported by the FCP adapter (lowest supported " + "0x%x, highest supported 0x%x).\n", + FSF_QTCB_CURRENT_VERSION, psq->word[0], + psq->word[1]); + zfcp_erp_adapter_shutdown(adapter, 0, 117, req); + break; + case FSF_PROT_ERROR_STATE: + case FSF_PROT_SEQ_NUMB_ERROR: + zfcp_erp_adapter_reopen(adapter, 0, 98, req); + req->status |= ZFCP_STATUS_FSFREQ_RETRY; + break; + case FSF_PROT_UNSUPP_QTCB_TYPE: + dev_err(&adapter->ccw_device->dev, + "Packet header type used by the device driver is " + "incompatible with that used on the adapter.\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 118, req); + break; + case FSF_PROT_HOST_CONNECTION_INITIALIZING: + atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + &adapter->status); + break; + case FSF_PROT_DUPLICATE_REQUEST_ID: + dev_err(&adapter->ccw_device->dev, + "The request identifier 0x%Lx is ambiguous.\n", + (unsigned long long)qtcb->bottom.support.req_handle); + zfcp_erp_adapter_shutdown(adapter, 0, 78, req); + break; + case FSF_PROT_LINK_DOWN: + zfcp_fsf_link_down_info_eval(req, 37, &psq->link_down_info); + /* FIXME: reopening adapter now? better wait for link up */ + zfcp_erp_adapter_reopen(adapter, 0, 79, req); + break; + case FSF_PROT_REEST_QUEUE: + /* All ports should be marked as ready to run again */ + zfcp_erp_modify_adapter_status(adapter, 28, NULL, + ZFCP_STATUS_COMMON_RUNNING, + ZFCP_SET); + zfcp_erp_adapter_reopen(adapter, + ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | + ZFCP_STATUS_COMMON_ERP_FAILED, 99, req); + break; + default: + dev_err(&adapter->ccw_device->dev, + "Transfer protocol status information" + "provided by the adapter (0x%x) " + "is not compatible with the device driver.\n", + qtcb->prefix.prot_status); + zfcp_erp_adapter_shutdown(adapter, 0, 119, req); + } + req->status |= ZFCP_STATUS_FSFREQ_ERROR; } -static int -zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) +/** + * zfcp_fsf_req_complete - process completion of a FSF request + * @fsf_req: The FSF request that has been completed. + * + * When a request has been completed either from the FCP adapter, + * or it has been dismissed due to a queue shutdown, this function + * is called to process the completion status and trigger further + * events related to the FSF request. + */ +void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) { - struct fsf_status_read_buffer *status_buffer; - struct zfcp_adapter *adapter; - struct zfcp_port *port; - unsigned long flags; + if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { + zfcp_fsf_status_read_handler(req); + return; + } - status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; - adapter = fsf_req->adapter; + del_timer(&req->timer); + zfcp_fsf_protstatus_eval(req); + zfcp_fsf_fsfstatus_eval(req); + req->handler(req); - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) - if (port->d_id == (status_buffer->d_id & ZFCP_DID_MASK)) - break; - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + if (req->erp_action) + zfcp_erp_async_handler(req->erp_action, 0); + req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; - if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) - goto out; + if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) + zfcp_fsf_req_free(req); + else + /* notify initiator waiting for the requests completion */ + /* + * FIXME: Race! We must not access fsf_req here as it might have been + * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED + * flag. It's an improbable case. But, we have the same paranoia for + * the cleanup flag already. + * Might better be handled using complete()? + * (setting the flag and doing wakeup ought to be atomic + * with regard to checking the flag as long as waitqueue is + * part of the to be released structure) + */ + wake_up(&req->completion_wq); +} - switch (status_buffer->status_subtype) { +static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) +{ + struct fsf_qtcb_bottom_config *bottom; + struct zfcp_adapter *adapter = req->adapter; + struct Scsi_Host *shost = adapter->scsi_host; - case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT: - zfcp_erp_port_reopen(port, 0, 101, fsf_req); - break; + bottom = &req->qtcb->bottom.config; - case FSF_STATUS_READ_SUB_ERROR_PORT: - zfcp_erp_port_shutdown(port, 0, 122, fsf_req); - break; + if (req->data) + memcpy(req->data, bottom, sizeof(*bottom)); + + fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; + fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; + fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; + fc_host_speed(shost) = bottom->fc_link_speed; + fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; + + adapter->hydra_version = bottom->adapter_type; + adapter->timer_ticks = bottom->timer_interval; + + if (fc_host_permanent_port_name(shost) == -1) + fc_host_permanent_port_name(shost) = fc_host_port_name(shost); + + switch (bottom->fc_topology) { + case FSF_TOPO_P2P: + adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; + adapter->peer_wwpn = bottom->plogi_payload.wwpn; + adapter->peer_wwnn = bottom->plogi_payload.wwnn; + fc_host_port_type(shost) = FC_PORTTYPE_PTP; + if (req->erp_action) + dev_info(&adapter->ccw_device->dev, + "Point-to-Point fibrechannel " + "configuration detected.\n"); + break; + case FSF_TOPO_FABRIC: + fc_host_port_type(shost) = FC_PORTTYPE_NPORT; + if (req->erp_action) + dev_info(&adapter->ccw_device->dev, + "Switched fabric fibrechannel " + "network detected.\n"); + break; + case FSF_TOPO_AL: + fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; + dev_err(&adapter->ccw_device->dev, + "Unsupported arbitrated loop fibrechannel " + "topology detected, shutting down " + "adapter.\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 127, req); + return -EIO; + default: + fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; + dev_err(&adapter->ccw_device->dev, + "The fibrechannel topology reported by the" + " adapter is not known by the zfcp driver," + " shutting down adapter.\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 128, req); + return -EIO; } - out: + return 0; } -static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req) +static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; - struct fsf_status_read_buffer *buf = - (struct fsf_status_read_buffer *) req->data; - struct fsf_bit_error_payload *err = - (struct fsf_bit_error_payload *) buf->payload; - dev_warn(&adapter->ccw_device->dev, - "Warning: bit error threshold data " - "received for the adapter: " - "link failures = %i, loss of sync errors = %i, " - "loss of signal errors = %i, " - "primitive sequence errors = %i, " - "invalid transmission word errors = %i, " - "CRC errors = %i).\n", - err->link_failure_error_count, - err->loss_of_sync_error_count, - err->loss_of_signal_error_count, - err->primitive_sequence_error_count, - err->invalid_transmission_word_error_count, - err->crc_error_count); - dev_warn(&adapter->ccw_device->dev, - "Additional bit error threshold data of the adapter: " - "primitive sequence event time-outs = %i, " - "elastic buffer overrun errors = %i, " - "advertised receive buffer-to-buffer credit = %i, " - "current receice buffer-to-buffer credit = %i, " - "advertised transmit buffer-to-buffer credit = %i, " - "current transmit buffer-to-buffer credit = %i).\n", - err->primitive_sequence_event_timeout_count, - err->elastic_buffer_overrun_error_count, - err->advertised_receive_b2b_credit, - err->current_receive_b2b_credit, - err->advertised_transmit_b2b_credit, - err->current_transmit_b2b_credit); -} + struct fsf_qtcb *qtcb = req->qtcb; + struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config; + struct Scsi_Host *shost = adapter->scsi_host; -/* - * function: zfcp_fsf_status_read_handler - * - * purpose: is called for finished Open Port command - * - * returns: - */ -static int -zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) -{ - int retval = 0; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct fsf_status_read_buffer *status_buffer = - (struct fsf_status_read_buffer *) fsf_req->data; - - if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { - zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer); - mempool_free(status_buffer, adapter->pool.data_status_read); - zfcp_fsf_req_free(fsf_req); - goto out; - } + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) + return; - zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer); + adapter->fsf_lic_version = bottom->lic_version; + adapter->adapter_features = bottom->adapter_features; + adapter->connection_features = bottom->connection_features; + adapter->peer_wwpn = 0; + adapter->peer_wwnn = 0; + adapter->peer_d_id = 0; - switch (status_buffer->status_type) { + switch (qtcb->header.fsf_status) { + case FSF_GOOD: + if (zfcp_fsf_exchange_config_evaluate(req)) + return; - case FSF_STATUS_READ_PORT_CLOSED: - zfcp_fsf_status_read_port_closed(fsf_req); + if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { + dev_err(&adapter->ccw_device->dev, + "Maximum QTCB size (%d bytes) allowed by " + "the adapter is lower than the minimum " + "required by the driver (%ld bytes).\n", + bottom->max_qtcb_size, + sizeof(struct fsf_qtcb)); + zfcp_erp_adapter_shutdown(adapter, 0, 129, req); + return; + } + atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, + &adapter->status); break; + case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: + fc_host_node_name(shost) = 0; + fc_host_port_name(shost) = 0; + fc_host_port_id(shost) = 0; + fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; + fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; + adapter->hydra_version = 0; - case FSF_STATUS_READ_INCOMING_ELS: - zfcp_fc_incoming_els(fsf_req); - break; + atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, + &adapter->status); - case FSF_STATUS_READ_SENSE_DATA_AVAIL: + zfcp_fsf_link_down_info_eval(req, 42, + &qtcb->header.fsf_status_qual.link_down_info); break; + default: + zfcp_erp_adapter_shutdown(adapter, 0, 130, req); + return; + } - case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: - zfcp_fsf_bit_error_threshold(fsf_req); - break; + if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { + adapter->hardware_version = bottom->hardware_version; + memcpy(fc_host_serial_number(shost), bottom->serial_number, + min(FC_SERIAL_NUMBER_SIZE, 17)); + EBCASC(fc_host_serial_number(shost), + min(FC_SERIAL_NUMBER_SIZE, 17)); + } - case FSF_STATUS_READ_LINK_DOWN: - switch (status_buffer->status_subtype) { - case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: - dev_warn(&adapter->ccw_device->dev, - "Physical link is down.\n"); - zfcp_fsf_link_down_info_eval(fsf_req, 38, - (struct fsf_link_down_info *) - &status_buffer->payload); - break; - case FSF_STATUS_READ_SUB_FDISC_FAILED: - dev_warn(&adapter->ccw_device->dev, - "Local link is down " - "due to failed FDISC login.\n"); - zfcp_fsf_link_down_info_eval(fsf_req, 39, - (struct fsf_link_down_info *) - &status_buffer->payload); - break; - case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: - dev_warn(&adapter->ccw_device->dev, - "Local link is down " - "due to firmware update on adapter.\n"); - zfcp_fsf_link_down_info_eval(fsf_req, 40, NULL); - break; - default: - dev_warn(&adapter->ccw_device->dev, - "Local link is down.\n"); - zfcp_fsf_link_down_info_eval(fsf_req, 41, NULL); - }; - break; + if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) { + dev_err(&adapter->ccw_device->dev, + "The adapter only supports newer control block " + "versions, try updated device driver.\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 125, req); + return; + } + if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) { + dev_err(&adapter->ccw_device->dev, + "The adapter only supports older control block " + "versions, consider a microcode upgrade.\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 126, req); + } +} - case FSF_STATUS_READ_LINK_UP: - dev_info(&adapter->ccw_device->dev, - "Local link was replugged.\n"); - /* All ports should be marked as ready to run again */ - zfcp_erp_modify_adapter_status(adapter, 30, NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); - zfcp_erp_adapter_reopen(adapter, - ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED - | ZFCP_STATUS_COMMON_ERP_FAILED, - 102, fsf_req); - break; +static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req) +{ + struct zfcp_adapter *adapter = req->adapter; + struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port; + struct Scsi_Host *shost = adapter->scsi_host; - case FSF_STATUS_READ_NOTIFICATION_LOST: - if (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_ACT_UPDATED) - zfcp_erp_adapter_access_changed(adapter, 135, fsf_req); - if (status_buffer->status_subtype & - FSF_STATUS_READ_SUB_INCOMING_ELS) - schedule_work(&adapter->scan_work); - break; + if (req->data) + memcpy(req->data, bottom, sizeof(*bottom)); - case FSF_STATUS_READ_CFDC_UPDATED: - zfcp_erp_adapter_access_changed(adapter, 136, fsf_req); - break; + if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) + fc_host_permanent_port_name(shost) = bottom->wwpn; + else + fc_host_permanent_port_name(shost) = fc_host_port_name(shost); + fc_host_maxframe_size(shost) = bottom->maximum_frame_size; + fc_host_supported_speeds(shost) = bottom->supported_speed; +} - case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: - adapter->adapter_features = *(u32*) status_buffer->payload; +static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) +{ + struct zfcp_adapter *adapter = req->adapter; + struct fsf_qtcb *qtcb = req->qtcb; + + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) + return; + + switch (qtcb->header.fsf_status) { + case FSF_GOOD: + zfcp_fsf_exchange_port_evaluate(req); + atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); + break; + case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: + zfcp_fsf_exchange_port_evaluate(req); + atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); + zfcp_fsf_link_down_info_eval(req, 43, + &qtcb->header.fsf_status_qual.link_down_info); break; } - mempool_free(status_buffer, adapter->pool.data_status_read); - zfcp_fsf_req_free(fsf_req); - /* - * recycle buffer and start new request repeat until outbound - * queue is empty or adapter shutdown is requested - */ - /* - * FIXME(qdio): - * we may wait in the req_create for 5s during shutdown, so - * qdio_cleanup will have to wait at least that long before returning - * with failure to allow us a proper cleanup under all circumstances - */ - /* - * FIXME: - * allocation failure possible? (Is this code needed?) - */ +} - atomic_inc(&adapter->stat_miss); - schedule_work(&adapter->stat_work); - out: - return retval; +static int zfcp_fsf_sbal_check(struct zfcp_qdio_queue *queue) +{ + spin_lock(&queue->lock); + if (atomic_read(&queue->count)) + return 1; + spin_unlock(&queue->lock); + return 0; } -/* - * function: zfcp_fsf_abort_fcp_command - * - * purpose: tells FSF to abort a running SCSI command - * - * returns: address of initiated FSF request - * NULL - request could not be initiated - * - * FIXME(design): should be watched by a timeout !!! - * FIXME(design) shouldn't this be modified to return an int - * also...don't know how though - */ -struct zfcp_fsf_req * -zfcp_fsf_abort_fcp_command(unsigned long old_req_id, - struct zfcp_adapter *adapter, - struct zfcp_unit *unit, int req_flags) +static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) +{ + long ret; + struct zfcp_qdio_queue *req_q = &adapter->req_q; + + spin_unlock(&req_q->lock); + ret = wait_event_interruptible_timeout(adapter->request_wq, + zfcp_fsf_sbal_check(req_q), 5 * HZ); + if (ret > 0) + return 0; + + spin_lock(&req_q->lock); + return -EIO; +} + +static struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool) +{ + struct zfcp_fsf_req *req; + req = mempool_alloc(pool, GFP_ATOMIC); + if (!req) + return NULL; + memset(req, 0, sizeof(*req)); + return req; +} + +static struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool) +{ + struct zfcp_fsf_req_qtcb *qtcb; + + if (likely(pool)) + qtcb = mempool_alloc(pool, GFP_ATOMIC); + else + qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, + GFP_ATOMIC); + if (unlikely(!qtcb)) + return NULL; + + memset(qtcb, 0, sizeof(*qtcb)); + qtcb->fsf_req.qtcb = &qtcb->qtcb; + qtcb->fsf_req.pool = pool; + + return &qtcb->fsf_req; +} + +static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, + u32 fsf_cmd, int req_flags, + mempool_t *pool) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req = NULL; - unsigned long lock_flags; - int retval = 0; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, - req_flags, adapter->pool.fsf_req_abort, - &lock_flags, &fsf_req); - if (retval < 0) - goto out; - if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, - &unit->status))) - goto unit_blocked; + struct zfcp_fsf_req *req; + struct zfcp_qdio_queue *req_q = &adapter->req_q; - sbale = zfcp_qdio_sbale_req(fsf_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + if (req_flags & ZFCP_REQ_NO_QTCB) + req = zfcp_fsf_alloc_noqtcb(pool); + else + req = zfcp_fsf_alloc_qtcb(pool); - fsf_req->data = (unsigned long) unit; + if (unlikely(!req)) + return ERR_PTR(-EIO); - /* set handles of unit and its parent port in QTCB */ - fsf_req->qtcb->header.lun_handle = unit->handle; - fsf_req->qtcb->header.port_handle = unit->port->handle; + if (adapter->req_no == 0) + adapter->req_no++; - /* set handle of request which should be aborted */ - fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id; + INIT_LIST_HEAD(&req->list); + init_timer(&req->timer); + init_waitqueue_head(&req->completion_wq); - zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); - retval = zfcp_fsf_req_send(fsf_req); - if (!retval) - goto out; + req->adapter = adapter; + req->fsf_command = fsf_cmd; + req->req_id = adapter->req_no++; + req->sbal_number = 1; + req->sbal_first = req_q->first; + req->sbal_last = req_q->first; + req->sbale_curr = 1; + + sbale = zfcp_qdio_sbale_req(req); + sbale[0].addr = (void *) req->req_id; + sbale[0].flags |= SBAL_FLAGS0_COMMAND; + + if (likely(req->qtcb)) { + req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no; + req->qtcb->prefix.req_id = req->req_id; + req->qtcb->prefix.ulp_info = 26; + req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command]; + req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION; + req->qtcb->header.req_handle = req->req_id; + req->qtcb->header.fsf_command = req->fsf_command; + req->seq_no = adapter->fsf_req_seq_no; + req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; + sbale[1].addr = (void *) req->qtcb; + sbale[1].length = sizeof(struct fsf_qtcb); + } + + if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) { + zfcp_fsf_req_free(req); + return ERR_PTR(-EIO); + } - unit_blocked: - zfcp_fsf_req_free(fsf_req); - fsf_req = NULL; + if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - out: - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return fsf_req; + return req; } -/* - * function: zfcp_fsf_abort_fcp_command_handler - * - * purpose: is called for finished Abort FCP Command request - * - * returns: +static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) +{ + struct zfcp_adapter *adapter = req->adapter; + struct zfcp_qdio_queue *req_q = &adapter->req_q; + int idx; + + /* put allocated FSF request into hash table */ + spin_lock(&adapter->req_list_lock); + idx = zfcp_reqlist_hash(req->req_id); + list_add_tail(&req->list, &adapter->req_list[idx]); + spin_unlock(&adapter->req_list_lock); + + req->issued = get_clock(); + if (zfcp_qdio_send(req)) { + /* Queues are down..... */ + del_timer(&req->timer); + spin_lock(&adapter->req_list_lock); + zfcp_reqlist_remove(adapter, req); + spin_unlock(&adapter->req_list_lock); + /* undo changes in request queue made for this request */ + atomic_add(req->sbal_number, &req_q->count); + req_q->first -= req->sbal_number; + req_q->first += QDIO_MAX_BUFFERS_PER_Q; + req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ + zfcp_erp_adapter_reopen(adapter, 0, 116, req); + return -EIO; + } + + /* Don't increase for unsolicited status */ + if (req->qtcb) + adapter->fsf_req_seq_no++; + + return 0; +} + +/** + * zfcp_fsf_status_read - send status read request + * @adapter: pointer to struct zfcp_adapter + * @req_flags: request flags + * Returns: 0 on success, ERROR otherwise */ -static int -zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) +int zfcp_fsf_status_read(struct zfcp_adapter *adapter) { - int retval = -EINVAL; - struct zfcp_unit *unit; - union fsf_status_qual *fsf_stat_qual = - &new_fsf_req->qtcb->header.fsf_status_qual; + struct zfcp_fsf_req *req; + struct fsf_status_read_buffer *sr_buf; + volatile struct qdio_buffer_element *sbale; + int retval = -EIO; - if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - /* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */ - goto skip_fsfstatus; + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, + ZFCP_REQ_NO_QTCB, + adapter->pool.fsf_req_status_read); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; } - unit = (struct zfcp_unit *) new_fsf_req->data; + sbale = zfcp_qdio_sbale_req(req); + sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; + sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; + req->sbale_curr = 2; + + sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); + if (!sr_buf) { + retval = -ENOMEM; + goto failed_buf; + } + memset(sr_buf, 0, sizeof(*sr_buf)); + req->data = sr_buf; + sbale = zfcp_qdio_sbale_curr(req); + sbale->addr = (void *) sr_buf; + sbale->length = sizeof(*sr_buf); - /* evaluate FSF status in QTCB */ - switch (new_fsf_req->qtcb->header.fsf_status) { + retval = zfcp_fsf_req_send(req); + if (retval) + goto failed_req_send; + goto out; + +failed_req_send: + mempool_free(sr_buf, adapter->pool.data_status_read); +failed_buf: + zfcp_fsf_req_free(req); + zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); +out: + spin_unlock(&adapter->req_q.lock); + return retval; +} + +static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) +{ + struct zfcp_unit *unit = req->data; + union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; + + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) + return; + + switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { - /* - * In this case a command that was sent prior to a port - * reopen was aborted (handles are different). This is - * fine. - */ - } else { - /* Let's hope this sorts out the mess */ + if (fsq->word[0] == fsq->word[1]) { zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104, - new_fsf_req); - new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; - case FSF_LUN_HANDLE_NOT_VALID: - if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { - /* - * In this case a command that was sent prior to a unit - * reopen was aborted (handles are different). - * This is fine. - */ - } else { - /* Let's hope this sorts out the mess */ - zfcp_erp_port_reopen(unit->port, 0, 105, new_fsf_req); - new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + if (fsq->word[0] == fsq->word[1]) { + zfcp_erp_port_reopen(unit->port, 0, 105, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; - case FSF_FCP_COMMAND_DOES_NOT_EXIST: - retval = 0; - new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; + req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; break; - case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, 47, new_fsf_req); - new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR - | ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_port_boxed(unit->port, 47, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; break; - case FSF_LUN_BOXED: - zfcp_erp_unit_boxed(unit, 48, new_fsf_req); - new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR - | ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_unit_boxed(unit, 48, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; break; - case FSF_ADAPTER_STATUS_AVAILABLE: - switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) { + switch (fsq->word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: zfcp_test_link(unit->port); - new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - /* SCSI stack will escalate */ - new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } break; - case FSF_GOOD: - retval = 0; - new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; + req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; break; } - skip_fsfstatus: - return retval; } /** - * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into - * one SBALE - * Two scatter-gather lists are passed, one for the reqeust and one for the - * response. + * zfcp_fsf_abort_fcp_command - abort running SCSI command + * @old_req_id: unsigned long + * @adapter: pointer to struct zfcp_adapter + * @unit: pointer to struct zfcp_unit + * @req_flags: integer specifying the request flags + * Returns: pointer to struct zfcp_fsf_req + * + * FIXME(design): should be watched by a timeout !!! */ -static inline int -zfcp_use_one_sbal(struct scatterlist *req, int req_count, - struct scatterlist *resp, int resp_count) -{ - return ((req_count == 1) && - (resp_count == 1) && - (((unsigned long) zfcp_sg_to_address(&req[0]) & - PAGE_MASK) == - ((unsigned long) (zfcp_sg_to_address(&req[0]) + - req[0].length - 1) & PAGE_MASK)) && - (((unsigned long) zfcp_sg_to_address(&resp[0]) & - PAGE_MASK) == - ((unsigned long) (zfcp_sg_to_address(&resp[0]) + - resp[0].length - 1) & PAGE_MASK))); -} -/** - * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) - * @ct: pointer to struct zfcp_send_ct which conatins all needed data for - * the request - * @pool: pointer to memory pool, if non-null this pool is used to allocate - * a struct zfcp_fsf_req - * @erp_action: pointer to erp_action, if non-null the Generic Service request - * is sent within error recovery - */ -int -zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, - struct zfcp_erp_action *erp_action) +struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, + struct zfcp_adapter *adapter, + struct zfcp_unit *unit, + int req_flags) { volatile struct qdio_buffer_element *sbale; - struct zfcp_port *port; - struct zfcp_adapter *adapter; - struct zfcp_fsf_req *fsf_req; - unsigned long lock_flags; - int bytes; - int ret = 0; - - port = ct->port; - adapter = port->adapter; - - ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, - ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, - pool, &lock_flags, &fsf_req); - if (ret < 0) - goto failed_req; - - sbale = zfcp_qdio_sbale_req(fsf_req); - if (zfcp_use_one_sbal(ct->req, ct->req_count, - ct->resp, ct->resp_count)){ - /* both request buffer and response buffer - fit into one sbale each */ - sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; - sbale[2].addr = zfcp_sg_to_address(&ct->req[0]); - sbale[2].length = ct->req[0].length; - sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]); - sbale[3].length = ct->resp[0].length; - sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; - } else if (adapter->adapter_features & - FSF_FEATURE_ELS_CT_CHAINED_SBALS) { - /* try to use chained SBALs */ - bytes = zfcp_qdio_sbals_from_sg(fsf_req, - SBAL_FLAGS0_TYPE_WRITE_READ, - ct->req, - ZFCP_MAX_SBALS_PER_CT_REQ); - if (bytes <= 0) { - if (bytes == 0) - ret = -ENOMEM; - else - ret = bytes; - - goto failed_send; - } - fsf_req->qtcb->bottom.support.req_buf_length = bytes; - fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; - bytes = zfcp_qdio_sbals_from_sg(fsf_req, - SBAL_FLAGS0_TYPE_WRITE_READ, - ct->resp, - ZFCP_MAX_SBALS_PER_CT_REQ); - if (bytes <= 0) { - if (bytes == 0) - ret = -ENOMEM; - else - ret = bytes; - - goto failed_send; - } - fsf_req->qtcb->bottom.support.resp_buf_length = bytes; - } else { - /* reject send generic request */ - ret = -EOPNOTSUPP; - goto failed_send; - } - - /* settings in QTCB */ - fsf_req->qtcb->header.port_handle = port->handle; - fsf_req->qtcb->bottom.support.service_class = - ZFCP_FC_SERVICE_CLASS_DEFAULT; - fsf_req->qtcb->bottom.support.timeout = ct->timeout; - fsf_req->data = (unsigned long) ct; - - zfcp_san_dbf_event_ct_request(fsf_req); + struct zfcp_fsf_req *req = NULL; - if (erp_action) { - erp_action->fsf_req = fsf_req; - fsf_req->erp_action = erp_action; - zfcp_erp_start_timer(fsf_req); - } else - zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); + spin_lock(&adapter->req_q.lock); + if (!atomic_read(&adapter->req_q.count)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, + req_flags, adapter->pool.fsf_req_abort); + if (unlikely(IS_ERR(req))) + goto out; - ret = zfcp_fsf_req_send(fsf_req); - if (ret) - goto failed_send; + if (unlikely(!(atomic_read(&unit->status) & + ZFCP_STATUS_COMMON_UNBLOCKED))) + goto out_error_free; - goto out; + sbale = zfcp_qdio_sbale_req(req); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - failed_send: - zfcp_fsf_req_free(fsf_req); - if (erp_action != NULL) { - erp_action->fsf_req = NULL; - } - failed_req: - out: - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return ret; + req->data = unit; + req->handler = zfcp_fsf_abort_fcp_command_handler; + req->qtcb->header.lun_handle = unit->handle; + req->qtcb->header.port_handle = unit->port->handle; + req->qtcb->bottom.support.req_handle = (u64) old_req_id; + + zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); + if (!zfcp_fsf_req_send(req)) + goto out; + +out_error_free: + zfcp_fsf_req_free(req); + req = NULL; +out: + spin_unlock(&adapter->req_q.lock); + return req; } -/** - * zfcp_fsf_send_ct_handler - handler for Generic Service requests - * @fsf_req: pointer to struct zfcp_fsf_req - * - * Data specific for the Generic Service request is passed using - * fsf_req->data. There we find the pointer to struct zfcp_send_ct. - * Usually a specific handler for the CT request is called which is - * found in this structure. - */ -static int -zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) { - struct zfcp_port *port; - struct zfcp_adapter *adapter; - struct zfcp_send_ct *send_ct; - struct fsf_qtcb_header *header; - struct fsf_qtcb_bottom_support *bottom; - int retval = -EINVAL; + struct zfcp_adapter *adapter = req->adapter; + struct zfcp_send_ct *send_ct = req->data; + struct zfcp_port *port = send_ct->port; + struct fsf_qtcb_header *header = &req->qtcb->header; - adapter = fsf_req->adapter; - send_ct = (struct zfcp_send_ct *) fsf_req->data; - port = send_ct->port; - header = &fsf_req->qtcb->header; - bottom = &fsf_req->qtcb->bottom.support; + send_ct->status = -EINVAL; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; - /* evaluate FSF status in QTCB */ switch (header->fsf_status) { - case FSF_GOOD: - zfcp_san_dbf_event_ct_response(fsf_req); - retval = 0; + zfcp_san_dbf_event_ct_response(req); + send_ct->status = 0; break; - case FSF_SERVICE_CLASS_NOT_SUPPORTED: - zfcp_fsf_class_not_supp(fsf_req); + zfcp_fsf_class_not_supp(req); break; - case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]){ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - /* reopening link to port */ zfcp_test_link(port); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - /* ERP strategy will escalate */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(fsf_req, port); - break; - - case FSF_GENERIC_COMMAND_REJECTED: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_fsf_access_denied_port(req, port); break; - - case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(adapter, 0, 106, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_PORT_BOXED: - zfcp_erp_port_boxed(port, 49, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR - | ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_port_boxed(port, 49, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; break; - - /* following states should never occure, all cases avoided - in zfcp_fsf_send_ct - but who knows ... */ + case FSF_PORT_HANDLE_NOT_VALID: + zfcp_erp_adapter_reopen(adapter, 0, 106, req); + case FSF_GENERIC_COMMAND_REJECTED: case FSF_PAYLOAD_SIZE_MISMATCH: case FSF_REQUEST_SIZE_TOO_LARGE: case FSF_RESPONSE_SIZE_TOO_LARGE: case FSF_SBAL_MISMATCH: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - default: + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } skip_fsfstatus: - send_ct->status = retval; - - if (send_ct->handler != NULL) + if (send_ct->handler) send_ct->handler(send_ct->handler_data); +} - return retval; +static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req, + struct scatterlist *sg_req, + struct scatterlist *sg_resp, int max_sbals) +{ + int bytes; + + bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, + sg_req, max_sbals); + if (bytes <= 0) + return -ENOMEM; + req->qtcb->bottom.support.req_buf_length = bytes; + req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; + + bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, + sg_resp, max_sbals); + if (bytes <= 0) + return -ENOMEM; + req->qtcb->bottom.support.resp_buf_length = bytes; + + return 0; } /** - * zfcp_fsf_send_els - initiate an ELS command (FC-FS) - * @els: pointer to struct zfcp_send_els which contains all needed data for - * the command. + * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) + * @ct: pointer to struct zfcp_send_ct with data for request + * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req + * @erp_action: if non-null the Generic Service request sent within ERP */ -int -zfcp_fsf_send_els(struct zfcp_send_els *els) +int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, + struct zfcp_erp_action *erp_action) { - volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; - u32 d_id; - struct zfcp_adapter *adapter; - unsigned long lock_flags; - int bytes; - int ret = 0; + struct zfcp_port *port = ct->port; + struct zfcp_adapter *adapter = port->adapter; + struct zfcp_fsf_req *req; + int ret = -EIO; - d_id = els->d_id; - adapter = els->adapter; + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; - ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, - ZFCP_REQ_AUTO_CLEANUP, - NULL, &lock_flags, &fsf_req); - if (ret < 0) - goto failed_req; - - if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, - &els->port->status))) { - ret = -EBUSY; - goto port_blocked; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, + ZFCP_REQ_AUTO_CLEANUP, pool); + if (unlikely(IS_ERR(req))) { + ret = PTR_ERR(req); + goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req); - if (zfcp_use_one_sbal(els->req, els->req_count, - els->resp, els->resp_count)){ - /* both request buffer and response buffer - fit into one sbale each */ - sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; - sbale[2].addr = zfcp_sg_to_address(&els->req[0]); - sbale[2].length = els->req[0].length; - sbale[3].addr = zfcp_sg_to_address(&els->resp[0]); - sbale[3].length = els->resp[0].length; - sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; - } else if (adapter->adapter_features & - FSF_FEATURE_ELS_CT_CHAINED_SBALS) { - /* try to use chained SBALs */ - bytes = zfcp_qdio_sbals_from_sg(fsf_req, - SBAL_FLAGS0_TYPE_WRITE_READ, - els->req, - ZFCP_MAX_SBALS_PER_ELS_REQ); - if (bytes <= 0) { - if (bytes == 0) { - ret = -ENOMEM; - } else { - ret = bytes; - } - goto failed_send; - } - fsf_req->qtcb->bottom.support.req_buf_length = bytes; - fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; - bytes = zfcp_qdio_sbals_from_sg(fsf_req, - SBAL_FLAGS0_TYPE_WRITE_READ, - els->resp, - ZFCP_MAX_SBALS_PER_ELS_REQ); - if (bytes <= 0) { - if (bytes == 0) { - ret = -ENOMEM; - } else { - ret = bytes; - } - goto failed_send; - } - fsf_req->qtcb->bottom.support.resp_buf_length = bytes; - } else { - /* reject request */ - ret = -EOPNOTSUPP; - goto failed_send; - } - - /* settings in QTCB */ - fsf_req->qtcb->bottom.support.d_id = d_id; - fsf_req->qtcb->bottom.support.service_class = - ZFCP_FC_SERVICE_CLASS_DEFAULT; - fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT; - fsf_req->data = (unsigned long) els; - - sbale = zfcp_qdio_sbale_req(fsf_req); - - zfcp_san_dbf_event_els_request(fsf_req); - - zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); - ret = zfcp_fsf_req_send(fsf_req); + ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp, + FSF_MAX_SBALS_PER_REQ); if (ret) goto failed_send; - goto out; + req->handler = zfcp_fsf_send_ct_handler; + req->qtcb->header.port_handle = port->handle; + req->qtcb->bottom.support.service_class = FSF_CLASS_3; + req->qtcb->bottom.support.timeout = ct->timeout; + req->data = ct; + + zfcp_san_dbf_event_ct_request(req); + + if (erp_action) { + erp_action->fsf_req = req; + req->erp_action = erp_action; + zfcp_erp_start_timer(req); + } else + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); - port_blocked: - failed_send: - zfcp_fsf_req_free(fsf_req); + ret = zfcp_fsf_req_send(req); + if (ret) + goto failed_send; - failed_req: - out: - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); + goto out; - return ret; +failed_send: + zfcp_fsf_req_free(req); + if (erp_action) + erp_action->fsf_req = NULL; +out: + spin_unlock(&adapter->req_q.lock); + return ret; } -/** - * zfcp_fsf_send_els_handler - handler for ELS commands - * @fsf_req: pointer to struct zfcp_fsf_req - * - * Data specific for the ELS command is passed using - * fsf_req->data. There we find the pointer to struct zfcp_send_els. - * Usually a specific handler for the ELS command is called which is - * found in this structure. - */ -static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) { - struct zfcp_adapter *adapter; - struct zfcp_port *port; - u32 d_id; - struct fsf_qtcb_header *header; - struct fsf_qtcb_bottom_support *bottom; - struct zfcp_send_els *send_els; - int retval = -EINVAL; + struct zfcp_send_els *send_els = req->data; + struct zfcp_port *port = send_els->port; + struct fsf_qtcb_header *header = &req->qtcb->header; - send_els = (struct zfcp_send_els *) fsf_req->data; - adapter = send_els->adapter; - port = send_els->port; - d_id = send_els->d_id; - header = &fsf_req->qtcb->header; - bottom = &fsf_req->qtcb->bottom.support; + send_els->status = -EINVAL; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; switch (header->fsf_status) { - case FSF_GOOD: - zfcp_san_dbf_event_els_response(fsf_req); - retval = 0; + zfcp_san_dbf_event_els_response(req); + send_els->status = 0; break; - case FSF_SERVICE_CLASS_NOT_SUPPORTED: - zfcp_fsf_class_not_supp(fsf_req); + zfcp_fsf_class_not_supp(req); break; - case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]){ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: if (port && (send_els->ls_code != ZFCP_LS_ADISC)) zfcp_test_link(port); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; + /*fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_SQ_RETRY_IF_POSSIBLE: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } break; - case FSF_ELS_COMMAND_REJECTED: case FSF_PAYLOAD_SIZE_MISMATCH: case FSF_REQUEST_SIZE_TOO_LARGE: case FSF_RESPONSE_SIZE_TOO_LARGE: break; - - case FSF_SBAL_MISMATCH: - /* should never occure, avoided in zfcp_fsf_send_els */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(fsf_req, port); + zfcp_fsf_access_denied_port(req, port); break; - + case FSF_SBAL_MISMATCH: + /* should never occure, avoided in zfcp_fsf_send_els */ + /* fall through */ default: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } - skip_fsfstatus: - send_els->status = retval; - if (send_els->handler) send_els->handler(send_els->handler_data); +} - return retval; +/** + * zfcp_fsf_send_els - initiate an ELS command (FC-FS) + * @els: pointer to struct zfcp_send_els with data for the command + */ +int zfcp_fsf_send_els(struct zfcp_send_els *els) +{ + struct zfcp_fsf_req *req; + struct zfcp_adapter *adapter = els->adapter; + struct fsf_qtcb_bottom_support *bottom; + int ret = -EIO; + + if (unlikely(!(atomic_read(&els->port->status) & + ZFCP_STATUS_COMMON_UNBLOCKED))) + return -EBUSY; + + spin_lock(&adapter->req_q.lock); + if (!atomic_read(&adapter->req_q.count)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, + ZFCP_REQ_AUTO_CLEANUP, NULL); + if (unlikely(IS_ERR(req))) { + ret = PTR_ERR(req); + goto out; + } + + ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, + FSF_MAX_SBALS_PER_ELS_REQ); + if (ret) + goto failed_send; + + bottom = &req->qtcb->bottom.support; + req->handler = zfcp_fsf_send_els_handler; + bottom->d_id = els->d_id; + bottom->service_class = FSF_CLASS_3; + bottom->timeout = 2 * R_A_TOV; + req->data = els; + + zfcp_san_dbf_event_els_request(req); + + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + ret = zfcp_fsf_req_send(req); + if (ret) + goto failed_send; + + goto out; + +failed_send: + zfcp_fsf_req_free(req); +out: + spin_unlock(&adapter->req_q.lock); + return ret; } -int -zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) +int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; + struct zfcp_fsf_req *req; struct zfcp_adapter *adapter = erp_action->adapter; - unsigned long lock_flags; - int retval; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(adapter, - FSF_QTCB_EXCHANGE_CONFIG_DATA, - ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp, - &lock_flags, &fsf_req); - if (retval) { - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return retval; + int retval = -EIO; + + spin_lock(&adapter->req_q.lock); + if (!atomic_read(&adapter->req_q.count)) + goto out; + req = zfcp_fsf_req_create(adapter, + FSF_QTCB_EXCHANGE_CONFIG_DATA, + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req); + sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - fsf_req->qtcb->bottom.config.feature_selection = + req->qtcb->bottom.config.feature_selection = FSF_FEATURE_CFDC | FSF_FEATURE_LUN_SHARING | FSF_FEATURE_NOTIFICATION_LOST | FSF_FEATURE_UPDATE_ALERT; - fsf_req->erp_action = erp_action; - erp_action->fsf_req = fsf_req; + req->erp_action = erp_action; + req->handler = zfcp_fsf_exchange_config_data_handler; + erp_action->fsf_req = req; - zfcp_erp_start_timer(fsf_req); - retval = zfcp_fsf_req_send(fsf_req); - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); + zfcp_erp_start_timer(req); + retval = zfcp_fsf_req_send(req); if (retval) { - zfcp_fsf_req_free(fsf_req); + zfcp_fsf_req_free(req); erp_action->fsf_req = NULL; } - +out: + spin_unlock(&adapter->req_q.lock); return retval; } -int -zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, - struct fsf_qtcb_bottom_config *data) +int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_config *data) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; - unsigned long lock_flags; - int retval; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, - ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags, - &fsf_req); - if (retval) { - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return retval; + struct zfcp_fsf_req *req = NULL; + int retval = -EIO; + + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, + 0, NULL); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req); + sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + req->handler = zfcp_fsf_exchange_config_data_handler; - fsf_req->qtcb->bottom.config.feature_selection = + req->qtcb->bottom.config.feature_selection = FSF_FEATURE_CFDC | FSF_FEATURE_LUN_SHARING | FSF_FEATURE_NOTIFICATION_LOST | FSF_FEATURE_UPDATE_ALERT; if (data) - fsf_req->data = (unsigned long) data; + req->data = data; - zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); - retval = zfcp_fsf_req_send(fsf_req); - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(req); +out: + spin_unlock(&adapter->req_q.lock); if (!retval) - wait_event(fsf_req->completion_wq, - fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + wait_event(req->completion_wq, + req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - zfcp_fsf_req_free(fsf_req); + zfcp_fsf_req_free(req); return retval; } -/** - * zfcp_fsf_exchange_config_evaluate - * @fsf_req: fsf_req which belongs to xchg config data request - * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1) - * - * returns: -EIO on error, 0 otherwise - */ -static int -zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) -{ - struct fsf_qtcb_bottom_config *bottom; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct Scsi_Host *shost = adapter->scsi_host; - - bottom = &fsf_req->qtcb->bottom.config; - adapter->fsf_lic_version = bottom->lic_version; - adapter->adapter_features = bottom->adapter_features; - adapter->connection_features = bottom->connection_features; - adapter->peer_wwpn = 0; - adapter->peer_wwnn = 0; - adapter->peer_d_id = 0; - - if (xchg_ok) { - - if (fsf_req->data) - memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data, - bottom, sizeof (struct fsf_qtcb_bottom_config)); - - fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; - fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; - fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; - fc_host_speed(shost) = bottom->fc_link_speed; - fc_host_supported_classes(shost) = - FC_COS_CLASS2 | FC_COS_CLASS3; - adapter->hydra_version = bottom->adapter_type; - adapter->timer_ticks = bottom->timer_interval; - if (fc_host_permanent_port_name(shost) == -1) - fc_host_permanent_port_name(shost) = - fc_host_port_name(shost); - if (bottom->fc_topology == FSF_TOPO_P2P) { - adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; - adapter->peer_wwpn = bottom->plogi_payload.wwpn; - adapter->peer_wwnn = bottom->plogi_payload.wwnn; - fc_host_port_type(shost) = FC_PORTTYPE_PTP; - } else if (bottom->fc_topology == FSF_TOPO_FABRIC) - fc_host_port_type(shost) = FC_PORTTYPE_NPORT; - else if (bottom->fc_topology == FSF_TOPO_AL) - fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; - else - fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; - } else { - fc_host_node_name(shost) = 0; - fc_host_port_name(shost) = 0; - fc_host_port_id(shost) = 0; - fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; - adapter->hydra_version = 0; - } - - if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { - adapter->hardware_version = bottom->hardware_version; - memcpy(fc_host_serial_number(shost), bottom->serial_number, - min(FC_SERIAL_NUMBER_SIZE, 17)); - EBCASC(fc_host_serial_number(shost), - min(FC_SERIAL_NUMBER_SIZE, 17)); - } - - if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { - dev_err(&adapter->ccw_device->dev, - "The adapter only supports newer control block " - "versions, try updated device driver.\n"); - zfcp_erp_adapter_shutdown(adapter, 0, 125, fsf_req); - return -EIO; - } - if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) { - dev_err(&adapter->ccw_device->dev, - "The adapter only supports older control block " - "versions, consider a microcode upgrade.\n"); - zfcp_erp_adapter_shutdown(adapter, 0, 126, fsf_req); - return -EIO; - } - return 0; -} - -/** - * function: zfcp_fsf_exchange_config_data_handler - * - * purpose: is called for finished Exchange Configuration Data command - * - * returns: - */ -static int -zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) -{ - struct fsf_qtcb_bottom_config *bottom; - struct zfcp_adapter *adapter = fsf_req->adapter; - struct fsf_qtcb *qtcb = fsf_req->qtcb; - - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) - return -EIO; - - switch (qtcb->header.fsf_status) { - - case FSF_GOOD: - if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1)) - return -EIO; - - switch (fc_host_port_type(adapter->scsi_host)) { - case FC_PORTTYPE_PTP: - if (fsf_req->erp_action) - dev_info(&adapter->ccw_device->dev, - "Point-to-Point fibrechannel " - "configuration detected.\n"); - break; - case FC_PORTTYPE_NLPORT: - dev_err(&adapter->ccw_device->dev, - "Unsupported arbitrated loop fibrechannel " - "topology detected, shutting down adapter\n"); - zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req); - return -EIO; - case FC_PORTTYPE_NPORT: - if (fsf_req->erp_action) - dev_info(&adapter->ccw_device->dev, - "Switched fabric fibrechannel " - "network detected.\n"); - break; - default: - dev_err(&adapter->ccw_device->dev, - "The fibrechannel topology reported by the " - "adapter is not known by the zfcp driver, " - "shutting down adapter.\n"); - zfcp_erp_adapter_shutdown(adapter, 0, 128, fsf_req); - return -EIO; - } - bottom = &qtcb->bottom.config; - if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { - dev_err(&adapter->ccw_device->dev, - "Maximum QTCB size (%d bytes) allowed by " - "the adapter is lower than the minimum " - "required by the driver (%ld bytes).\n", - bottom->max_qtcb_size, sizeof(struct fsf_qtcb)); - zfcp_erp_adapter_shutdown(adapter, 0, 129, fsf_req); - return -EIO; - } - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, - &adapter->status); - break; - case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: - if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0)) - return -EIO; - - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, - &adapter->status); - - zfcp_fsf_link_down_info_eval(fsf_req, 42, - &qtcb->header.fsf_status_qual.link_down_info); - break; - default: - zfcp_erp_adapter_shutdown(adapter, 0, 130, fsf_req); - return -EIO; - } - return 0; -} - /** * zfcp_fsf_exchange_port_data - request information about local port * @erp_action: ERP action for the adapter for which port data is requested + * Returns: 0 on success, error otherwise */ -int -zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) +int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; + struct zfcp_fsf_req *req; struct zfcp_adapter *adapter = erp_action->adapter; - unsigned long lock_flags; - int retval; + int retval = -EIO; if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - /* setup new FSF request */ - retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, - ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp, - &lock_flags, &fsf_req); - if (retval) { - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return retval; + spin_lock(&adapter->req_q.lock); + if (!atomic_read(&adapter->req_q.count)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; } - sbale = zfcp_qdio_sbale_req(fsf_req); + sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - erp_action->fsf_req = fsf_req; - fsf_req->erp_action = erp_action; - zfcp_erp_start_timer(fsf_req); - - retval = zfcp_fsf_req_send(fsf_req); - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); + req->handler = zfcp_fsf_exchange_port_data_handler; + req->erp_action = erp_action; + erp_action->fsf_req = req; + zfcp_erp_start_timer(req); + retval = zfcp_fsf_req_send(req); if (retval) { - zfcp_fsf_req_free(fsf_req); + zfcp_fsf_req_free(req); erp_action->fsf_req = NULL; } +out: + spin_unlock(&adapter->req_q.lock); return retval; } - /** * zfcp_fsf_exchange_port_data_sync - request information about local port - * and wait until information is ready + * @adapter: pointer to struct zfcp_adapter + * @data: pointer to struct fsf_qtcb_bottom_port + * Returns: 0 on success, error otherwise */ -int -zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, - struct fsf_qtcb_bottom_port *data) +int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_port *data) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; - unsigned long lock_flags; - int retval; + struct zfcp_fsf_req *req = NULL; + int retval = -EIO; if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - /* setup new FSF request */ - retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, - 0, NULL, &lock_flags, &fsf_req); - if (retval) { - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return retval; + spin_lock(&adapter->req_q.lock); + if (!atomic_read(&adapter->req_q.count)) + goto out; + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0, + NULL); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; } if (data) - fsf_req->data = (unsigned long) data; + req->data = data; - sbale = zfcp_qdio_sbale_req(fsf_req); + sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); - retval = zfcp_fsf_req_send(fsf_req); - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - + req->handler = zfcp_fsf_exchange_port_data_handler; + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(req); +out: + spin_unlock(&adapter->req_q.lock); if (!retval) - wait_event(fsf_req->completion_wq, - fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - - zfcp_fsf_req_free(fsf_req); - - return retval; -} - -/** - * zfcp_fsf_exchange_port_evaluate - * @fsf_req: fsf_req which belongs to xchg port data request - * @xchg_ok: specifies if xchg port data was incomplete or complete (0/1) - */ -static void -zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) -{ - struct zfcp_adapter *adapter; - struct fsf_qtcb_bottom_port *bottom; - struct Scsi_Host *shost; - - adapter = fsf_req->adapter; - bottom = &fsf_req->qtcb->bottom.port; - shost = adapter->scsi_host; - - if (fsf_req->data) - memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom, - sizeof(struct fsf_qtcb_bottom_port)); - - if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) - fc_host_permanent_port_name(shost) = bottom->wwpn; - else - fc_host_permanent_port_name(shost) = fc_host_port_name(shost); - fc_host_maxframe_size(shost) = bottom->maximum_frame_size; - fc_host_supported_speeds(shost) = bottom->supported_speed; -} - -/** - * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request - * @fsf_req: pointer to struct zfcp_fsf_req - */ -static void -zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) -{ - struct zfcp_adapter *adapter; - struct fsf_qtcb *qtcb; - - adapter = fsf_req->adapter; - qtcb = fsf_req->qtcb; + wait_event(req->completion_wq, + req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + zfcp_fsf_req_free(req); - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) - return; - - switch (qtcb->header.fsf_status) { - case FSF_GOOD: - zfcp_fsf_exchange_port_evaluate(fsf_req, 1); - atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); - break; - case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: - zfcp_fsf_exchange_port_evaluate(fsf_req, 0); - atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); - zfcp_fsf_link_down_info_eval(fsf_req, 43, - &qtcb->header.fsf_status_qual.link_down_info); - break; - } -} - - -/* - * function: zfcp_fsf_open_port - * - * purpose: - * - * returns: address of initiated FSF request - * NULL - request could not be initiated - */ -int -zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) -{ - volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; - unsigned long lock_flags; - int retval = 0; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(erp_action->adapter, - FSF_QTCB_OPEN_PORT_WITH_DID, - ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, - erp_action->adapter->pool.fsf_req_erp, - &lock_flags, &fsf_req); - if (retval < 0) - goto out; - - sbale = zfcp_qdio_sbale_req(fsf_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - - fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id; - atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); - fsf_req->data = (unsigned long) erp_action->port; - fsf_req->erp_action = erp_action; - erp_action->fsf_req = fsf_req; - - zfcp_erp_start_timer(fsf_req); - retval = zfcp_fsf_req_send(fsf_req); - if (retval) { - zfcp_fsf_req_free(fsf_req); - erp_action->fsf_req = NULL; - goto out; - } - - out: - write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); return retval; } -/* - * function: zfcp_fsf_open_port_handler - * - * purpose: is called for finished Open Port command - * - * returns: - */ -static int -zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) { - int retval = -EINVAL; - struct zfcp_port *port; + struct zfcp_port *port = req->data; + struct fsf_qtcb_header *header = &req->qtcb->header; struct fsf_plogi *plogi; - struct fsf_qtcb_header *header; - port = (struct zfcp_port *) fsf_req->data; - header = &fsf_req->qtcb->header; - - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - /* don't change port status in our bookkeeping */ + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; - } - /* evaluate FSF status in QTCB */ switch (header->fsf_status) { - case FSF_PORT_ALREADY_OPEN: - /* - * This is a bug, however operation should continue normally - * if it is simply ignored - */ break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(fsf_req, port); + zfcp_fsf_access_denied_port(req, port); break; - case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The adapter is out of resources. The remote port " "0x%016Lx could not be opened, disabling it.\n", port->wwpn); - zfcp_erp_port_failed(port, 31, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_port_failed(port, 31, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - /* ERP strategy will escalate */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - /* ERP strategy will escalate */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_NO_RETRY_POSSIBLE: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&req->adapter->ccw_device->dev, "The remote port 0x%016Lx could not be " "opened. Disabling it.\n", port->wwpn); - zfcp_erp_port_failed(port, 32, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - default: + zfcp_erp_port_failed(port, 32, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } break; - case FSF_GOOD: - /* save port handle assigned by FSF */ port->handle = header->port_handle; - /* mark port as open */ atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_COMMON_ACCESS_BOXED, &port->status); - retval = 0; /* check whether D_ID has changed during open */ /* * FIXME: This check is not airtight, as the FCP channel does @@ -2021,227 +1471,168 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) * another GID_PN straight after a port has been opened. * Alternately, an ADISC/PDISC ELS should suffice, as well. */ - plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els; - if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status)) - { - if (fsf_req->qtcb->bottom.support.els1_length < - sizeof (struct fsf_plogi)) { - /* skip sanity check and assume wwpn is ok */ - } else { - if (plogi->serv_param.wwpn != port->wwpn) { - atomic_clear_mask( - ZFCP_STATUS_PORT_DID_DID, - &port->status); - } else { - port->wwnn = plogi->serv_param.wwnn; - zfcp_fc_plogi_evaluate(port, plogi); - } + if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) + break; + + plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; + if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) { + if (plogi->serv_param.wwpn != port->wwpn) + atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID, + &port->status); + else { + port->wwnn = plogi->serv_param.wwnn; + zfcp_fc_plogi_evaluate(port, plogi); } } break; - case FSF_UNKNOWN_OP_SUBTYPE: - /* should never occure, subtype not set in zfcp_fsf_open_port */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - default: + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } - skip_fsfstatus: +skip_fsfstatus: atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status); - return retval; } -/* - * function: zfcp_fsf_close_port - * - * purpose: submit FSF command "close port" - * - * returns: address of initiated FSF request - * NULL - request could not be initiated +/** + * zfcp_fsf_open_port - create and send open port request + * @erp_action: pointer to struct zfcp_erp_action + * Returns: 0 on success, error otherwise */ -int -zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) +int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; - unsigned long lock_flags; - int retval = 0; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(erp_action->adapter, - FSF_QTCB_CLOSE_PORT, - ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, - erp_action->adapter->pool.fsf_req_erp, - &lock_flags, &fsf_req); - if (retval < 0) + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + + req = zfcp_fsf_req_create(adapter, + FSF_QTCB_OPEN_PORT_WITH_DID, + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); goto out; + } - sbale = zfcp_qdio_sbale_req(fsf_req); + sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); - fsf_req->data = (unsigned long) erp_action->port; - fsf_req->erp_action = erp_action; - fsf_req->qtcb->header.port_handle = erp_action->port->handle; - fsf_req->erp_action = erp_action; - erp_action->fsf_req = fsf_req; - - zfcp_erp_start_timer(fsf_req); - retval = zfcp_fsf_req_send(fsf_req); + req->handler = zfcp_fsf_open_port_handler; + req->qtcb->bottom.support.d_id = erp_action->port->d_id; + req->data = erp_action->port; + req->erp_action = erp_action; + erp_action->fsf_req = req; + atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); + + zfcp_erp_start_timer(req); + retval = zfcp_fsf_req_send(req); if (retval) { - zfcp_fsf_req_free(fsf_req); + zfcp_fsf_req_free(req); erp_action->fsf_req = NULL; - goto out; } - - out: - write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); +out: + spin_unlock(&adapter->req_q.lock); return retval; } -/* - * function: zfcp_fsf_close_port_handler - * - * purpose: is called for finished Close Port FSF command - * - * returns: - */ -static int -zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) { - int retval = -EINVAL; - struct zfcp_port *port; - - port = (struct zfcp_port *) fsf_req->data; + struct zfcp_port *port = req->data; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - /* don't change port status in our bookkeeping */ + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; - } - - /* evaluate FSF status in QTCB */ - switch (fsf_req->qtcb->header.fsf_status) { + switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(port->adapter, 0, 107, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_adapter_reopen(port->adapter, 0, 107, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_ADAPTER_STATUS_AVAILABLE: - /* Note: FSF has actually closed the port in this case. - * The status code is just daft. Fingers crossed for a change - */ - retval = 0; break; - case FSF_GOOD: - zfcp_erp_modify_port_status(port, 33, fsf_req, + zfcp_erp_modify_port_status(port, 33, req, ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); - retval = 0; break; } - skip_fsfstatus: +skip_fsfstatus: atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status); - return retval; } -/* - * function: zfcp_fsf_close_physical_port - * - * purpose: submit FSF command "close physical port" - * - * returns: address of initiated FSF request - * NULL - request could not be initiated +/** + * zfcp_fsf_close_port - create and send close port request + * @erp_action: pointer to struct zfcp_erp_action + * Returns: 0 on success, error otherwise */ -int -zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) +int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; - unsigned long lock_flags; - int retval = 0; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(erp_action->adapter, - FSF_QTCB_CLOSE_PHYSICAL_PORT, - ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, - erp_action->adapter->pool.fsf_req_erp, - &lock_flags, &fsf_req); - if (retval < 0) + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); goto out; + } - sbale = zfcp_qdio_sbale_req(fsf_req); + sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - /* mark port as being closed */ - atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, - &erp_action->port->status); - /* save a pointer to this port */ - fsf_req->data = (unsigned long) erp_action->port; - fsf_req->qtcb->header.port_handle = erp_action->port->handle; - fsf_req->erp_action = erp_action; - erp_action->fsf_req = fsf_req; - - zfcp_erp_start_timer(fsf_req); - retval = zfcp_fsf_req_send(fsf_req); + req->handler = zfcp_fsf_close_port_handler; + req->data = erp_action->port; + req->erp_action = erp_action; + req->qtcb->header.port_handle = erp_action->port->handle; + erp_action->fsf_req = req; + atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); + + zfcp_erp_start_timer(req); + retval = zfcp_fsf_req_send(req); if (retval) { - zfcp_fsf_req_free(fsf_req); + zfcp_fsf_req_free(req); erp_action->fsf_req = NULL; - goto out; } - - out: - write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); +out: + spin_unlock(&adapter->req_q.lock); return retval; } -/* - * function: zfcp_fsf_close_physical_port_handler - * - * purpose: is called for finished Close Physical Port FSF command - * - * returns: - */ -static int -zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) { - int retval = -EINVAL; - struct zfcp_port *port; + struct zfcp_port *port = req->data; + struct fsf_qtcb_header *header = &req->qtcb->header; struct zfcp_unit *unit; - struct fsf_qtcb_header *header; - - port = (struct zfcp_port *) fsf_req->data; - header = &fsf_req->qtcb->header; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - /* don't change port status in our bookkeeping */ + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; - } - /* evaluate FSF status in QTCB */ switch (header->fsf_status) { - case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(port->adapter, 0, 108, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_adapter_reopen(port->adapter, 0, 108, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(fsf_req, port); + zfcp_fsf_access_denied_port(req, port); break; - case FSF_PORT_BOXED: - zfcp_erp_port_boxed(port, 50, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; - + zfcp_erp_port_boxed(port, 50, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); @@ -2249,120 +1640,88 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); break; - case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - /* This will now be escalated by ERP */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; + /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - /* ERP strategy will escalate */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } break; - case FSF_GOOD: /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); list_for_each_entry(unit, &port->unit_list_head, list) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); - retval = 0; + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + &unit->status); break; } - - skip_fsfstatus: +skip_fsfstatus: atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status); - return retval; } -/* - * function: zfcp_fsf_open_unit - * - * purpose: - * - * returns: - * - * assumptions: This routine does not check whether the associated - * remote port has already been opened. This should be - * done by calling routines. Otherwise some status - * may be presented by FSF +/** + * zfcp_fsf_close_physical_port - close physical port + * @erp_action: pointer to struct zfcp_erp_action + * Returns: 0 on success */ -int -zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) +int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; - unsigned long lock_flags; - int retval = 0; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(erp_action->adapter, - FSF_QTCB_OPEN_LUN, - ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, - erp_action->adapter->pool.fsf_req_erp, - &lock_flags, &fsf_req); - if (retval < 0) + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) goto out; - sbale = zfcp_qdio_sbale_req(fsf_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT, + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; + } - fsf_req->qtcb->header.port_handle = erp_action->port->handle; - fsf_req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; - if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE)) - fsf_req->qtcb->bottom.support.option = - FSF_OPEN_LUN_SUPPRESS_BOXING; - atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); - fsf_req->data = (unsigned long) erp_action->unit; - fsf_req->erp_action = erp_action; - erp_action->fsf_req = fsf_req; + sbale = zfcp_qdio_sbale_req(req); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - zfcp_erp_start_timer(fsf_req); - retval = zfcp_fsf_req_send(erp_action->fsf_req); + req->data = erp_action->port; + req->qtcb->header.port_handle = erp_action->port->handle; + req->erp_action = erp_action; + req->handler = zfcp_fsf_close_physical_port_handler; + erp_action->fsf_req = req; + atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, + &erp_action->port->status); + + zfcp_erp_start_timer(req); + retval = zfcp_fsf_req_send(req); if (retval) { - zfcp_fsf_req_free(fsf_req); + zfcp_fsf_req_free(req); erp_action->fsf_req = NULL; - goto out; } - out: - write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); +out: + spin_unlock(&adapter->req_q.lock); return retval; } -/* - * function: zfcp_fsf_open_unit_handler - * - * purpose: is called for finished Open LUN command - * - * returns: - */ -static int -zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) { - int retval = -EINVAL; - struct zfcp_adapter *adapter; - struct zfcp_unit *unit; - struct fsf_qtcb_header *header; - struct fsf_qtcb_bottom_support *bottom; - struct fsf_queue_designator *queue_designator; + struct zfcp_adapter *adapter = req->adapter; + struct zfcp_unit *unit = req->data; + struct fsf_qtcb_header *header = &req->qtcb->header; + struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; + struct fsf_queue_designator *queue_designator = + &header->fsf_status_qual.fsf_queue_designator; int exclusive, readwrite; - unit = (struct zfcp_unit *) fsf_req->data; - - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - /* don't change unit status in our bookkeeping */ + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; - } - - adapter = fsf_req->adapter; - header = &fsf_req->qtcb->header; - bottom = &fsf_req->qtcb->bottom.support; - queue_designator = &header->fsf_status_qual.fsf_queue_designator; atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_COMMON_ACCESS_BOXED | @@ -2370,32 +1729,25 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) ZFCP_STATUS_UNIT_READONLY, &unit->status); - /* evaluate FSF status in QTCB */ switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - + zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, req); + /* fall through */ case FSF_LUN_ALREADY_OPEN: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_unit(fsf_req, unit); + zfcp_fsf_access_denied_unit(req, unit); atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); break; - case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, 51, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_port_boxed(unit->port, 51, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; break; - case FSF_LUN_SHARING_VIOLATION: - if (header->fsf_status_qual.word[0] != 0) { + if (header->fsf_status_qual.word[0]) dev_warn(&adapter->ccw_device->dev, "FCP-LUN 0x%Lx at the remote port " "with WWPN 0x%Lx " @@ -2405,47 +1757,37 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) unit->port->wwpn, queue_designator->hla, queue_designator->cssid); - } else + else zfcp_act_eval_err(adapter, header->fsf_status_qual.word[2]); - zfcp_erp_unit_access_denied(unit, 60, fsf_req); + zfcp_erp_unit_access_denied(unit, 60, req); atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: - dev_warn(&fsf_req->adapter->ccw_device->dev, + dev_warn(&adapter->ccw_device->dev, "The adapter ran out of resources. There is no " "handle available for unit 0x%016Lx on port 0x%016Lx.", unit->fcp_lun, unit->port->wwpn); - zfcp_erp_unit_failed(unit, 34, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_unit_failed(unit, 34, req); + /* fall through */ + case FSF_INVALID_COMMAND_OPTION: + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - /* Re-establish link to port */ zfcp_test_link(unit->port); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; + /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - /* ERP strategy will escalate */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } break; - case FSF_INVALID_COMMAND_OPTION: - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - retval = -EINVAL; - break; - case FSF_GOOD: - /* save LUN handle assigned by FSF */ unit->handle = header->lun_handle; - /* mark unit as open */ atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && @@ -2463,412 +1805,192 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) if (!readwrite) { atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); - dev_info(&fsf_req->adapter->ccw_device->dev, + dev_info(&adapter->ccw_device->dev, "Read-only access for unit 0x%016Lx " "on port 0x%016Lx.\n", unit->fcp_lun, unit->port->wwpn); } if (exclusive && !readwrite) { - dev_err(&fsf_req->adapter->ccw_device->dev, + dev_err(&adapter->ccw_device->dev, "Exclusive access of read-only unit " "0x%016Lx on port 0x%016Lx not " "supported, disabling unit.\n", unit->fcp_lun, unit->port->wwpn); - zfcp_erp_unit_failed(unit, 35, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_unit_shutdown(unit, 0, 80, fsf_req); + zfcp_erp_unit_failed(unit, 35, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_unit_shutdown(unit, 0, 80, req); } else if (!exclusive && readwrite) { - dev_err(&fsf_req->adapter->ccw_device->dev, + dev_err(&adapter->ccw_device->dev, "Shared access of read-write unit " "0x%016Lx on port 0x%016Lx not " "supported, disabling unit.\n", unit->fcp_lun, unit->port->wwpn); - zfcp_erp_unit_failed(unit, 36, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_unit_shutdown(unit, 0, 81, fsf_req); + zfcp_erp_unit_failed(unit, 36, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_unit_shutdown(unit, 0, 81, req); } } - - retval = 0; break; } - skip_fsfstatus: +skip_fsfstatus: atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status); - return retval; } -/* - * function: zfcp_fsf_close_unit - * - * purpose: - * - * returns: address of fsf_req - request successfully initiated - * NULL - - * - * assumptions: This routine does not check whether the associated - * remote port/lun has already been opened. This should be - * done by calling routines. Otherwise some status - * may be presented by FSF +/** + * zfcp_fsf_open_unit - open unit + * @erp_action: pointer to struct zfcp_erp_action + * Returns: 0 on success, error otherwise */ -int -zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) +int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; - unsigned long lock_flags; - int retval = 0; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(erp_action->adapter, - FSF_QTCB_CLOSE_LUN, - ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, - erp_action->adapter->pool.fsf_req_erp, - &lock_flags, &fsf_req); - if (retval < 0) + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) goto out; - sbale = zfcp_qdio_sbale_req(fsf_req); + req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN, + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; + } + + sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - fsf_req->qtcb->header.port_handle = erp_action->port->handle; - fsf_req->qtcb->header.lun_handle = erp_action->unit->handle; - atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); - fsf_req->data = (unsigned long) erp_action->unit; - fsf_req->erp_action = erp_action; - erp_action->fsf_req = fsf_req; + req->qtcb->header.port_handle = erp_action->port->handle; + req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; + req->handler = zfcp_fsf_open_unit_handler; + req->data = erp_action->unit; + req->erp_action = erp_action; + erp_action->fsf_req = req; + + if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) + req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING; + + atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); - zfcp_erp_start_timer(fsf_req); - retval = zfcp_fsf_req_send(erp_action->fsf_req); + zfcp_erp_start_timer(req); + retval = zfcp_fsf_req_send(req); if (retval) { - zfcp_fsf_req_free(fsf_req); + zfcp_fsf_req_free(req); erp_action->fsf_req = NULL; - goto out; } - - out: - write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags); +out: + spin_unlock(&adapter->req_q.lock); return retval; } -/* - * function: zfcp_fsf_close_unit_handler - * - * purpose: is called for finished Close LUN FSF command - * - * returns: - */ -static int -zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) { - int retval = -EINVAL; - struct zfcp_unit *unit; - - unit = (struct zfcp_unit *) fsf_req->data; + struct zfcp_unit *unit = req->data; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - /* don't change unit status in our bookkeeping */ + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; - } - - /* evaluate FSF status in QTCB */ - switch (fsf_req->qtcb->header.fsf_status) { + switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(unit->port, 0, 111, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_port_reopen(unit->port, 0, 111, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, 52, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_port_boxed(unit->port, 52, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; break; - case FSF_ADAPTER_STATUS_AVAILABLE: - switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { + switch (req->qtcb->header.fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - /* re-establish link to port */ zfcp_test_link(unit->port); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; + /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - /* ERP strategy will escalate */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - default: + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } break; - case FSF_GOOD: - /* mark unit as closed */ atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); - retval = 0; break; } - - skip_fsfstatus: +skip_fsfstatus: atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status); - return retval; } /** - * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) - * @adapter: adapter where scsi command is issued - * @unit: unit where command is sent to - * @scsi_cmnd: scsi command to be sent - * @timer: timer to be started when request is initiated - * @req_flags: flags for fsf_request + * zfcp_fsf_close_unit - close zfcp unit + * @erp_action: pointer to struct zfcp_unit + * Returns: 0 on success, error otherwise */ -int -zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, - struct zfcp_unit *unit, - struct scsi_cmnd * scsi_cmnd, - int use_timer, int req_flags) -{ - struct zfcp_fsf_req *fsf_req = NULL; - struct fcp_cmnd_iu *fcp_cmnd_iu; - unsigned int sbtype; - unsigned long lock_flags; - int real_bytes = 0; - int retval = 0; - int mask; - - /* setup new FSF request */ - retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, - adapter->pool.fsf_req_scsi, - &lock_flags, &fsf_req); - if (unlikely(retval < 0)) - goto failed_req_create; - - if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, - &unit->status))) { - retval = -EBUSY; - goto unit_blocked; - } - - zfcp_unit_get(unit); - fsf_req->unit = unit; - - /* associate FSF request with SCSI request (for look up on abort) */ - scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id; - - /* associate SCSI command with FSF request */ - fsf_req->data = (unsigned long) scsi_cmnd; - - /* set handles of unit and its parent port in QTCB */ - fsf_req->qtcb->header.lun_handle = unit->handle; - fsf_req->qtcb->header.port_handle = unit->port->handle; - - /* FSF does not define the structure of the FCP_CMND IU */ - fcp_cmnd_iu = (struct fcp_cmnd_iu *) - &(fsf_req->qtcb->bottom.io.fcp_cmnd); - - /* - * set depending on data direction: - * data direction bits in SBALE (SB Type) - * data direction bits in QTCB - * data direction bits in FCP_CMND IU - */ - switch (scsi_cmnd->sc_data_direction) { - case DMA_NONE: - fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; - /* - * FIXME(qdio): - * what is the correct type for commands - * without 'real' data buffers? - */ - sbtype = SBAL_FLAGS0_TYPE_READ; - break; - case DMA_FROM_DEVICE: - fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; - sbtype = SBAL_FLAGS0_TYPE_READ; - fcp_cmnd_iu->rddata = 1; - break; - case DMA_TO_DEVICE: - fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; - sbtype = SBAL_FLAGS0_TYPE_WRITE; - fcp_cmnd_iu->wddata = 1; - break; - case DMA_BIDIRECTIONAL: - default: - /* - * dummy, catch this condition earlier - * in zfcp_scsi_queuecommand - */ - goto failed_scsi_cmnd; - } - - /* set FC service class in QTCB (3 per default) */ - fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; - - /* set FCP_LUN in FCP_CMND IU in QTCB */ - fcp_cmnd_iu->fcp_lun = unit->fcp_lun; - - mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED; - - /* set task attributes in FCP_CMND IU in QTCB */ - if (likely((scsi_cmnd->device->simple_tags) || - (atomic_test_mask(mask, &unit->status)))) - fcp_cmnd_iu->task_attribute = SIMPLE_Q; - else - fcp_cmnd_iu->task_attribute = UNTAGGED; - - /* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */ - if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) - fcp_cmnd_iu->add_fcp_cdb_length - = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; - /* - * copy SCSI CDB (including additional length, if any) to - * FCP_CDB in FCP_CMND IU in QTCB - */ - memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); - - /* FCP CMND IU length in QTCB */ - fsf_req->qtcb->bottom.io.fcp_cmnd_length = - sizeof (struct fcp_cmnd_iu) + - fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t); - - /* generate SBALEs from data buffer */ - real_bytes = zfcp_qdio_sbals_from_sg(fsf_req, sbtype, - scsi_sglist(scsi_cmnd), - ZFCP_MAX_SBALS_PER_REQ); - if (unlikely(real_bytes < 0)) { - if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) - retval = -EIO; - else { - dev_err(&adapter->ccw_device->dev, - "SCSI request too large. " - "Shutting down unit 0x%016Lx on port " - "0x%016Lx.\n", unit->fcp_lun, - unit->port->wwpn); - zfcp_erp_unit_shutdown(unit, 0, 131, fsf_req); - retval = -EINVAL; - } - goto no_fit; - } - - /* set length of FCP data length in FCP_CMND IU in QTCB */ - zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); - - if (use_timer) - zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); - - retval = zfcp_fsf_req_send(fsf_req); - if (unlikely(retval < 0)) - goto send_failed; - - goto success; - - send_failed: - no_fit: - failed_scsi_cmnd: - zfcp_unit_put(unit); - unit_blocked: - zfcp_fsf_req_free(fsf_req); - fsf_req = NULL; - scsi_cmnd->host_scribble = NULL; - success: - failed_req_create: - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return retval; -} - -struct zfcp_fsf_req * -zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, - struct zfcp_unit *unit, - u8 tm_flags, int req_flags) +int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) { - struct zfcp_fsf_req *fsf_req = NULL; - int retval = 0; - struct fcp_cmnd_iu *fcp_cmnd_iu; - unsigned long lock_flags; volatile struct qdio_buffer_element *sbale; + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; - /* setup new FSF request */ - retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, - adapter->pool.fsf_req_scsi, - &lock_flags, &fsf_req); - if (retval < 0) + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN, + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; + } - if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, - &unit->status))) - goto unit_blocked; - - /* - * Used to decide on proper handler in the return path, - * could be either zfcp_fsf_send_fcp_command_task_handler or - * zfcp_fsf_send_fcp_command_task_management_handler */ - - fsf_req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; - - /* - * hold a pointer to the unit being target of this - * task management request - */ - fsf_req->data = (unsigned long) unit; - - /* set FSF related fields in QTCB */ - fsf_req->qtcb->header.lun_handle = unit->handle; - fsf_req->qtcb->header.port_handle = unit->port->handle; - fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; - fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; - fsf_req->qtcb->bottom.io.fcp_cmnd_length = - sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t); - - sbale = zfcp_qdio_sbale_req(fsf_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; + sbale = zfcp_qdio_sbale_req(req); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - /* set FCP related fields in FCP_CMND IU in QTCB */ - fcp_cmnd_iu = (struct fcp_cmnd_iu *) - &(fsf_req->qtcb->bottom.io.fcp_cmnd); - fcp_cmnd_iu->fcp_lun = unit->fcp_lun; - fcp_cmnd_iu->task_management_flags = tm_flags; - - zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); - retval = zfcp_fsf_req_send(fsf_req); - if (!retval) - goto out; - - unit_blocked: - zfcp_fsf_req_free(fsf_req); - fsf_req = NULL; + req->qtcb->header.port_handle = erp_action->port->handle; + req->qtcb->header.lun_handle = erp_action->unit->handle; + req->handler = zfcp_fsf_close_unit_handler; + req->data = erp_action->unit; + req->erp_action = erp_action; + erp_action->fsf_req = req; + atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); - out: - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return fsf_req; + zfcp_erp_start_timer(req); + retval = zfcp_fsf_req_send(req); + if (retval) { + zfcp_fsf_req_free(req); + erp_action->fsf_req = NULL; + } +out: + spin_unlock(&adapter->req_q.lock); + return retval; } static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat) { lat_rec->sum += lat; - if (lat_rec->min > lat) - lat_rec->min = lat; - if (lat_rec->max < lat) - lat_rec->max = lat; + lat_rec->min = min(lat_rec->min, lat); + lat_rec->max = max(lat_rec->max, lat); } -static void zfcp_fsf_req_latency(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req) { struct fsf_qual_latency_info *lat_inf; struct latency_cont *lat; - struct zfcp_unit *unit; + struct zfcp_unit *unit = req->unit; unsigned long flags; - lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info; - unit = fsf_req->unit; + lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info; - switch (fsf_req->qtcb->bottom.io.data_direction) { + switch (req->qtcb->bottom.io.data_direction) { case FSF_DATADIR_READ: lat = &unit->latencies.read; break; @@ -2886,212 +2008,53 @@ static void zfcp_fsf_req_latency(struct zfcp_fsf_req *fsf_req) zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat); zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat); lat->counter++; - spin_unlock_irqrestore(&unit->latencies.lock, flags); -} - -/* - * function: zfcp_fsf_send_fcp_command_handler - * - * purpose: is called for finished Send FCP Command - * - * returns: - */ -static int -zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) -{ - int retval = -EINVAL; - struct zfcp_unit *unit; - struct fsf_qtcb_header *header; - - header = &fsf_req->qtcb->header; - - if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) - unit = (struct zfcp_unit *) fsf_req->data; - else - unit = fsf_req->unit; - - if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { - /* go directly to calls of special handlers */ - goto skip_fsfstatus; - } - - /* evaluate FSF status in QTCB */ - switch (header->fsf_status) { - - case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(unit->port, 0, 113, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_HANDLE_MISMATCH: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, 114, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_SERVICE_CLASS_NOT_SUPPORTED: - zfcp_fsf_class_not_supp(fsf_req); - break; - - case FSF_FCPLUN_NOT_VALID: - zfcp_erp_port_reopen(unit->port, 0, 115, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_unit(fsf_req, unit); - break; - - case FSF_DIRECTION_INDICATOR_NOT_VALID: - dev_err(&fsf_req->adapter->ccw_device->dev, - "Invalid data direction (%d) given for unit 0x%016Lx " - "on port 0x%016Lx, shutting down adapter.\n", - fsf_req->qtcb->bottom.io.data_direction, - unit->fcp_lun, unit->port->wwpn); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_CMND_LENGTH_NOT_VALID: - dev_err(&fsf_req->adapter->ccw_device->dev, - "An invalid control-data-block length field (%d) " - "was found in a command for unit 0x%016Lx on port " - "0x%016Lx. Shutting down adapter.\n", - fsf_req->qtcb->bottom.io.fcp_cmnd_length, - unit->fcp_lun, unit->port->wwpn); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, 53, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; - break; - - case FSF_LUN_BOXED: - zfcp_erp_unit_boxed(unit, 54, fsf_req); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR - | ZFCP_STATUS_FSFREQ_RETRY; - break; - - case FSF_ADAPTER_STATUS_AVAILABLE: - switch (header->fsf_status_qual.word[0]) { - case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - /* re-establish link to port */ - zfcp_test_link(unit->port); - break; - case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - /* FIXME(hw) need proper specs for proper action */ - /* let scsi stack deal with retries and escalation */ - break; - } - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - - case FSF_GOOD: - break; - - case FSF_FCP_RSP_AVAILABLE: - break; - } - - skip_fsfstatus: - if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) { - retval = - zfcp_fsf_send_fcp_command_task_management_handler(fsf_req); - } else { - retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req); - fsf_req->unit = NULL; - zfcp_unit_put(unit); - } - return retval; + spin_unlock_irqrestore(&unit->latencies.lock, flags); } -/* - * function: zfcp_fsf_send_fcp_command_task_handler - * - * purpose: evaluates FCP_RSP IU - * - * returns: - */ -static int -zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) { - int retval = 0; - struct scsi_cmnd *scpnt; + struct scsi_cmnd *scpnt = req->data; struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) - &(fsf_req->qtcb->bottom.io.fcp_rsp); + &(req->qtcb->bottom.io.fcp_rsp); u32 sns_len; char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; unsigned long flags; - read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); - scpnt = (struct scsi_cmnd *) fsf_req->data; if (unlikely(!scpnt)) - goto out; + return; - if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { - /* FIXME: (design) mid-layer should handle DID_ABORT like - * DID_SOFT_ERROR by retrying the request for devices - * that allow retries. - */ + read_lock_irqsave(&req->adapter->abort_lock, flags); + + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { set_host_byte(scpnt, DID_SOFT_ERROR); set_driver_byte(scpnt, SUGGEST_RETRY); goto skip_fsfstatus; } - if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { set_host_byte(scpnt, DID_ERROR); goto skip_fsfstatus; } - /* set message byte of result in SCSI command */ set_msg_byte(scpnt, COMMAND_COMPLETE); - /* - * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte - * of result in SCSI command - */ scpnt->result |= fcp_rsp_iu->scsi_status; - if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) - zfcp_fsf_req_latency(fsf_req); + if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) + zfcp_fsf_req_latency(req); - /* check FCP_RSP_INFO */ if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { - switch (fcp_rsp_info[3]) { - case RSP_CODE_GOOD: - /* ok, continue */ + if (fcp_rsp_info[3] == RSP_CODE_GOOD) set_host_byte(scpnt, DID_OK); - break; - case RSP_CODE_LENGTH_MISMATCH: - /* hardware bug */ - set_host_byte(scpnt, DID_ERROR); - goto skip_fsfstatus; - case RSP_CODE_FIELD_INVALID: - /* driver or hardware bug */ - set_host_byte(scpnt, DID_ERROR); - goto skip_fsfstatus; - case RSP_CODE_RO_MISMATCH: - /* hardware bug */ - set_host_byte(scpnt, DID_ERROR); - goto skip_fsfstatus; - default: - /* invalid FCP response code */ + else { set_host_byte(scpnt, DID_ERROR); goto skip_fsfstatus; } } - /* check for sense data */ if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { - sns_len = FSF_FCP_RSP_SIZE - - sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len; + sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) + + fcp_rsp_iu->fcp_rsp_len; sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); @@ -3099,382 +2062,372 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); } - /* check for underrun */ if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < scpnt->underflow) set_host_byte(scpnt, DID_ERROR); } - - skip_fsfstatus: +skip_fsfstatus: if (scpnt->result != 0) - zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt, fsf_req); + zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req); else if (scpnt->retries > 0) - zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt, fsf_req); + zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req); else - zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt, fsf_req); + zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req); - /* cleanup pointer (need this especially for abort) */ scpnt->host_scribble = NULL; - - /* always call back */ (scpnt->scsi_done) (scpnt); - /* * We must hold this lock until scsi_done has been called. * Otherwise we may call scsi_done after abort regarding this * command has completed. * Note: scsi_done must not block! */ - out: - read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags); - return retval; + read_unlock_irqrestore(&req->adapter->abort_lock, flags); } -/* - * function: zfcp_fsf_send_fcp_command_task_management_handler - * - * purpose: evaluates FCP_RSP IU - * - * returns: - */ -static int -zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) +static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req) { - int retval = 0; struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) - &(fsf_req->qtcb->bottom.io.fcp_rsp); + &(req->qtcb->bottom.io.fcp_rsp); char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; + if ((fcp_rsp_info[3] != RSP_CODE_GOOD) || + (req->status & ZFCP_STATUS_FSFREQ_ERROR)) + req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; +} + + +static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req) +{ + struct zfcp_unit *unit; + struct fsf_qtcb_header *header = &req->qtcb->header; + + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) + unit = req->data; + else + unit = req->unit; + + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) goto skip_fsfstatus; - } - /* check FCP_RSP_INFO */ - switch (fcp_rsp_info[3]) { - case RSP_CODE_GOOD: - /* ok, continue */ + switch (header->fsf_status) { + case FSF_HANDLE_MISMATCH: + case FSF_PORT_HANDLE_NOT_VALID: + zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_FCPLUN_NOT_VALID: + case FSF_LUN_HANDLE_NOT_VALID: + zfcp_erp_port_reopen(unit->port, 0, 113, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case RSP_CODE_TASKMAN_UNSUPP: - fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP; + case FSF_SERVICE_CLASS_NOT_SUPPORTED: + zfcp_fsf_class_not_supp(req); break; - case RSP_CODE_TASKMAN_FAILED: - fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; + case FSF_ACCESS_DENIED: + zfcp_fsf_access_denied_unit(req, unit); + break; + case FSF_DIRECTION_INDICATOR_NOT_VALID: + dev_err(&req->adapter->ccw_device->dev, + "Invalid data direction (%d) given for unit " + "0x%016Lx on port 0x%016Lx, shutting down " + "adapter.\n", + req->qtcb->bottom.io.data_direction, + unit->fcp_lun, unit->port->wwpn); + zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_CMND_LENGTH_NOT_VALID: + dev_err(&req->adapter->ccw_device->dev, + "An invalid control-data-block length field (%d) " + "was found in a command for unit 0x%016Lx on port " + "0x%016Lx. Shutting down adapter.\n", + req->qtcb->bottom.io.fcp_cmnd_length, + unit->fcp_lun, unit->port->wwpn); + zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_PORT_BOXED: + zfcp_erp_port_boxed(unit->port, 53, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; + break; + case FSF_LUN_BOXED: + zfcp_erp_unit_boxed(unit, 54, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; + break; + case FSF_ADAPTER_STATUS_AVAILABLE: + if (header->fsf_status_qual.word[0] == + FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) + zfcp_test_link(unit->port); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - default: - /* invalid FCP response code */ - fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; } - - skip_fsfstatus: - return retval; +skip_fsfstatus: + if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) + zfcp_fsf_send_fcp_ctm_handler(req); + else { + zfcp_fsf_send_fcp_command_task_handler(req); + req->unit = NULL; + zfcp_unit_put(unit); + } } - -/* - * function: zfcp_fsf_control_file - * - * purpose: Initiator of the control file upload/download FSF requests - * - * returns: 0 - FSF request is successfuly created and queued - * -EOPNOTSUPP - The FCP adapter does not have Control File support - * -EINVAL - Invalid direction specified - * -ENOMEM - Insufficient memory - * -EPERM - Cannot create FSF request or place it in QDIO queue +/** + * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) + * @adapter: adapter where scsi command is issued + * @unit: unit where command is sent to + * @scsi_cmnd: scsi command to be sent + * @timer: timer to be started when request is initiated + * @req_flags: flags for fsf_request */ -struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, - struct zfcp_fsf_cfdc *fsf_cfdc) +int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, + struct zfcp_unit *unit, + struct scsi_cmnd *scsi_cmnd, + int use_timer, int req_flags) { - struct zfcp_fsf_req *fsf_req; - struct fsf_qtcb_bottom_support *bottom; - volatile struct qdio_buffer_element *sbale; - unsigned long lock_flags; - int direction; - int retval; - int bytes; + struct zfcp_fsf_req *req; + struct fcp_cmnd_iu *fcp_cmnd_iu; + unsigned int sbtype; + int real_bytes, retval = -EIO; - if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) - return ERR_PTR(-EOPNOTSUPP); + if (unlikely(!(atomic_read(&unit->status) & + ZFCP_STATUS_COMMON_UNBLOCKED))) + return -EBUSY; - switch (fsf_cfdc->command) { - case FSF_QTCB_DOWNLOAD_CONTROL_FILE: - direction = SBAL_FLAGS0_TYPE_WRITE; + spin_lock(&adapter->req_q.lock); + if (!atomic_read(&adapter->req_q.count)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, + adapter->pool.fsf_req_scsi); + if (unlikely(IS_ERR(req))) { + retval = PTR_ERR(req); + goto out; + } + + zfcp_unit_get(unit); + req->unit = unit; + req->data = scsi_cmnd; + req->handler = zfcp_fsf_send_fcp_command_handler; + req->qtcb->header.lun_handle = unit->handle; + req->qtcb->header.port_handle = unit->port->handle; + req->qtcb->bottom.io.service_class = FSF_CLASS_3; + + scsi_cmnd->host_scribble = (unsigned char *) req->req_id; + + fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd); + fcp_cmnd_iu->fcp_lun = unit->fcp_lun; + /* + * set depending on data direction: + * data direction bits in SBALE (SB Type) + * data direction bits in QTCB + * data direction bits in FCP_CMND IU + */ + switch (scsi_cmnd->sc_data_direction) { + case DMA_NONE: + req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; + sbtype = SBAL_FLAGS0_TYPE_READ; break; - case FSF_QTCB_UPLOAD_CONTROL_FILE: - direction = SBAL_FLAGS0_TYPE_READ; + case DMA_FROM_DEVICE: + req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; + sbtype = SBAL_FLAGS0_TYPE_READ; + fcp_cmnd_iu->rddata = 1; + break; + case DMA_TO_DEVICE: + req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; + sbtype = SBAL_FLAGS0_TYPE_WRITE; + fcp_cmnd_iu->wddata = 1; break; + case DMA_BIDIRECTIONAL: default: - return ERR_PTR(-EINVAL); + retval = -EIO; + goto failed_scsi_cmnd; } - retval = zfcp_fsf_req_create(adapter, fsf_cfdc->command, - ZFCP_WAIT_FOR_SBAL, - NULL, &lock_flags, &fsf_req); - if (retval < 0) { - retval = -EPERM; - goto unlock_queue_lock; - } + if (likely((scsi_cmnd->device->simple_tags) || + ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) && + (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED)))) + fcp_cmnd_iu->task_attribute = SIMPLE_Q; + else + fcp_cmnd_iu->task_attribute = UNTAGGED; - sbale = zfcp_qdio_sbale_req(fsf_req); - sbale[0].flags |= direction; + if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) + fcp_cmnd_iu->add_fcp_cdb_length = + (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; - bottom = &fsf_req->qtcb->bottom.support; - bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; - bottom->option = fsf_cfdc->option; + memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); - bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, - fsf_cfdc->sg, - ZFCP_MAX_SBALS_PER_REQ); - if (bytes != ZFCP_CFDC_MAX_SIZE) { - retval = -ENOMEM; - goto free_fsf_req; - } + req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + + fcp_cmnd_iu->add_fcp_cdb_length + sizeof(fcp_dl_t); - zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); - retval = zfcp_fsf_req_send(fsf_req); - if (retval < 0) { - retval = -EPERM; - goto free_fsf_req; + real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype, + scsi_sglist(scsi_cmnd), + FSF_MAX_SBALS_PER_REQ); + if (unlikely(real_bytes < 0)) { + if (req->sbal_number < FSF_MAX_SBALS_PER_REQ) + retval = -EIO; + else { + dev_err(&adapter->ccw_device->dev, + "SCSI request too large. " + "Shutting down unit 0x%016Lx on port " + "0x%016Lx.\n", unit->fcp_lun, + unit->port->wwpn); + zfcp_erp_unit_shutdown(unit, 0, 131, req); + retval = -EINVAL; + } + goto failed_scsi_cmnd; } - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - - wait_event(fsf_req->completion_wq, - fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - return fsf_req; + zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); - free_fsf_req: - zfcp_fsf_req_free(fsf_req); - unlock_queue_lock: - write_unlock_irqrestore(&adapter->req_q.lock, lock_flags); - return ERR_PTR(retval); -} + if (use_timer) + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); -static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) -{ - if (fsf_req->qtcb->header.fsf_status != FSF_GOOD) - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; -} + retval = zfcp_fsf_req_send(req); + if (unlikely(retval)) + goto failed_scsi_cmnd; -static inline int -zfcp_fsf_req_sbal_check(unsigned long *flags, - struct zfcp_qdio_queue *queue, int needed) -{ - write_lock_irqsave(&queue->lock, *flags); - if (likely(atomic_read(&queue->count) >= needed)) - return 1; - write_unlock_irqrestore(&queue->lock, *flags); - return 0; -} + goto out; -/* - * set qtcb pointer in fsf_req and initialize QTCB - */ -static void -zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) -{ - if (likely(fsf_req->qtcb != NULL)) { - fsf_req->qtcb->prefix.req_seq_no = - fsf_req->adapter->fsf_req_seq_no; - fsf_req->qtcb->prefix.req_id = fsf_req->req_id; - fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION; - fsf_req->qtcb->prefix.qtcb_type = - fsf_qtcb_type[fsf_req->fsf_command]; - fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION; - fsf_req->qtcb->header.req_handle = fsf_req->req_id; - fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command; - } +failed_scsi_cmnd: + zfcp_unit_put(unit); + zfcp_fsf_req_free(req); + scsi_cmnd->host_scribble = NULL; +out: + spin_unlock(&adapter->req_q.lock); + return retval; } /** - * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue - * @adapter: adapter for which request queue is examined - * @req_flags: flags indicating whether to wait for needed SBAL or not - * @lock_flags: lock_flags if queue_lock is taken - * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS - * Locks: lock adapter->req_q->lock on success - */ -static int -zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags, - unsigned long *lock_flags) -{ - long ret; - struct zfcp_qdio_queue *req_q = &adapter->req_q; - - if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) { - ret = wait_event_interruptible_timeout(adapter->request_wq, - zfcp_fsf_req_sbal_check(lock_flags, req_q, 1), - ZFCP_SBAL_TIMEOUT); - if (ret < 0) - return ret; - if (!ret) - return -EIO; - } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_q, 1)) - return -EIO; - - return 0; -} - -/* - * function: zfcp_fsf_req_create - * - * purpose: create an FSF request at the specified adapter and - * setup common fields - * - * returns: -ENOMEM if there was insufficient memory for a request - * -EIO if no qdio buffers could be allocate to the request - * -EINVAL/-EPERM on bug conditions in req_dequeue - * 0 in success - * - * note: The created request is returned by reference. - * - * locks: lock of concerned request queue must not be held, - * but is held on completion (write, irqsave) + * zfcp_fsf_send_fcp_ctm - send SCSI task management command + * @adapter: pointer to struct zfcp-adapter + * @unit: pointer to struct zfcp_unit + * @tm_flags: unsigned byte for task management flags + * @req_flags: int request flags + * Returns: on success pointer to struct fsf_req, NULL otherwise */ -int -zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, - mempool_t *pool, unsigned long *lock_flags, - struct zfcp_fsf_req **fsf_req_p) +struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter, + struct zfcp_unit *unit, + u8 tm_flags, int req_flags) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req = NULL; - int ret = 0; - struct zfcp_qdio_queue *req_q = &adapter->req_q; - - /* allocate new FSF request */ - fsf_req = zfcp_fsf_req_alloc(pool, req_flags); - if (unlikely(!fsf_req)) { - ret = -ENOMEM; - goto failed_fsf_req; - } - - fsf_req->adapter = adapter; - fsf_req->fsf_command = fsf_cmd; - INIT_LIST_HEAD(&fsf_req->list); - init_timer(&fsf_req->timer); - - /* initialize waitqueue which may be used to wait on - this request completion */ - init_waitqueue_head(&fsf_req->completion_wq); - - ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags); - if (ret < 0) - goto failed_sbals; - - /* this is serialized (we are holding req_queue-lock of adapter) */ - if (adapter->req_no == 0) - adapter->req_no++; - fsf_req->req_id = adapter->req_no++; - - zfcp_fsf_req_qtcb_init(fsf_req); - - /* - * We hold queue_lock here. Check if QDIOUP is set and let request fail - * if it is not set (see also *_open_qdio and *_close_qdio). - */ - - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { - write_unlock_irqrestore(&req_q->lock, *lock_flags); - ret = -EIO; - goto failed_sbals; - } + struct zfcp_fsf_req *req = NULL; + struct fcp_cmnd_iu *fcp_cmnd_iu; - if (fsf_req->qtcb) { - fsf_req->seq_no = adapter->fsf_req_seq_no; - fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; - } - fsf_req->sbal_number = 1; - fsf_req->sbal_first = req_q->first; - fsf_req->sbal_last = req_q->first; - fsf_req->sbale_curr = 1; + if (unlikely(!(atomic_read(&unit->status) & + ZFCP_STATUS_COMMON_UNBLOCKED))) + return NULL; - if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) { - fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - } + spin_lock(&adapter->req_q.lock); + if (!atomic_read(&adapter->req_q.count)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, + adapter->pool.fsf_req_scsi); + if (unlikely(IS_ERR(req))) + goto out; - sbale = zfcp_qdio_sbale_req(fsf_req); + req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; + req->data = unit; + req->handler = zfcp_fsf_send_fcp_command_handler; + req->qtcb->header.lun_handle = unit->handle; + req->qtcb->header.port_handle = unit->port->handle; + req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; + req->qtcb->bottom.io.service_class = FSF_CLASS_3; + req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + + sizeof(fcp_dl_t); + + sbale = zfcp_qdio_sbale_req(req); + sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - /* setup common SBALE fields */ - sbale[0].addr = (void *) fsf_req->req_id; - sbale[0].flags |= SBAL_FLAGS0_COMMAND; - if (likely(fsf_req->qtcb != NULL)) { - sbale[1].addr = (void *) fsf_req->qtcb; - sbale[1].length = sizeof(struct fsf_qtcb); - } + fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd; + fcp_cmnd_iu->fcp_lun = unit->fcp_lun; + fcp_cmnd_iu->task_management_flags = tm_flags; - goto success; + zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); + if (!zfcp_fsf_req_send(req)) + goto out; - failed_sbals: -/* dequeue new FSF request previously enqueued */ - zfcp_fsf_req_free(fsf_req); - fsf_req = NULL; + zfcp_fsf_req_free(req); + req = NULL; +out: + spin_unlock(&adapter->req_q.lock); + return req; +} - failed_fsf_req: - write_lock_irqsave(&req_q->lock, *lock_flags); - success: - *fsf_req_p = fsf_req; - return ret; +static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req) +{ + if (req->qtcb->header.fsf_status != FSF_GOOD) + req->status |= ZFCP_STATUS_FSFREQ_ERROR; } -/* - * function: zfcp_fsf_req_send - * - * purpose: start transfer of FSF request via QDIO - * - * returns: 0 - request transfer succesfully started - * !0 - start of request transfer failed +/** + * zfcp_fsf_control_file - control file upload/download + * @adapter: pointer to struct zfcp_adapter + * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc + * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise */ -static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) +struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, + struct zfcp_fsf_cfdc *fsf_cfdc) { - struct zfcp_adapter *adapter; - struct zfcp_qdio_queue *req_q; volatile struct qdio_buffer_element *sbale; - int inc_seq_no; - int retval = 0; + struct zfcp_fsf_req *req = NULL; + struct fsf_qtcb_bottom_support *bottom; + int direction, retval = -EIO, bytes; + + if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) + return ERR_PTR(-EOPNOTSUPP); + + switch (fsf_cfdc->command) { + case FSF_QTCB_DOWNLOAD_CONTROL_FILE: + direction = SBAL_FLAGS0_TYPE_WRITE; + break; + case FSF_QTCB_UPLOAD_CONTROL_FILE: + direction = SBAL_FLAGS0_TYPE_READ; + break; + default: + return ERR_PTR(-EINVAL); + } - adapter = fsf_req->adapter; - req_q = &adapter->req_q; + spin_lock(&adapter->req_q.lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; - sbale = zfcp_qdio_sbale_req(fsf_req); + req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL); + if (unlikely(IS_ERR(req))) { + retval = -EPERM; + goto out; + } - /* put allocated FSF request into hash table */ - spin_lock(&adapter->req_list_lock); - zfcp_reqlist_add(adapter, fsf_req); - spin_unlock(&adapter->req_list_lock); + req->handler = zfcp_fsf_control_file_handler; - inc_seq_no = (fsf_req->qtcb != NULL); + sbale = zfcp_qdio_sbale_req(req); + sbale[0].flags |= direction; - fsf_req->issued = get_clock(); + bottom = &req->qtcb->bottom.support; + bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; + bottom->option = fsf_cfdc->option; - retval = zfcp_qdio_send(fsf_req); + bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg, + FSF_MAX_SBALS_PER_REQ); + if (bytes != ZFCP_CFDC_MAX_SIZE) { + retval = -ENOMEM; + zfcp_fsf_req_free(req); + goto out; + } - if (unlikely(retval)) { - /* Queues are down..... */ - del_timer(&fsf_req->timer); - spin_lock(&adapter->req_list_lock); - zfcp_reqlist_remove(adapter, fsf_req); - spin_unlock(&adapter->req_list_lock); - /* undo changes in request queue made for this request */ - atomic_add(fsf_req->sbal_number, &req_q->count); - req_q->first -= fsf_req->sbal_number; - req_q->first += QDIO_MAX_BUFFERS_PER_Q; - req_q->first %= QDIO_MAX_BUFFERS_PER_Q; - zfcp_erp_adapter_reopen(adapter, 0, 116, fsf_req); - retval = -EIO; - } else { - /* - * increase FSF sequence counter - - * this must only be done for request successfully enqueued to - * QDIO this rejected requests may be cleaned up by calling - * routines resulting in missing sequence counter values - * otherwise, - */ + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(req); +out: + spin_unlock(&adapter->req_q.lock); - /* Don't increase for unsolicited status */ - if (inc_seq_no) - adapter->fsf_req_seq_no++; + if (!retval) { + wait_event(req->completion_wq, + req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + return req; } - return retval; + return ERR_PTR(retval); } diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 6ce2f1e4b00e..bf94b4da0763 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -287,6 +287,18 @@ struct fsf_bit_error_payload { u32 current_transmit_b2b_credit; } __attribute__ ((packed)); +struct fsf_link_down_info { + u32 error_code; + u32 res1; + u8 res2[2]; + u8 primary_status; + u8 ioerr_code; + u8 action_code; + u8 reason_code; + u8 explanation_code; + u8 vendor_specific_code; +} __attribute__ ((packed)); + struct fsf_status_read_buffer { u32 status_type; u32 status_subtype; @@ -297,7 +309,12 @@ struct fsf_status_read_buffer { u32 class; u64 fcp_lun; u8 res3[24]; - u8 payload[FSF_STATUS_READ_PAYLOAD_SIZE]; + union { + u8 data[FSF_STATUS_READ_PAYLOAD_SIZE]; + u32 word[FSF_STATUS_READ_PAYLOAD_SIZE/sizeof(u32)]; + struct fsf_link_down_info link_down_info; + struct fsf_bit_error_payload bit_error; + } payload; } __attribute__ ((packed)); struct fsf_qual_version_error { @@ -310,18 +327,6 @@ struct fsf_qual_sequence_error { u32 res1[3]; } __attribute__ ((packed)); -struct fsf_link_down_info { - u32 error_code; - u32 res1; - u8 res2[2]; - u8 primary_status; - u8 ioerr_code; - u8 action_code; - u8 reason_code; - u8 explanation_code; - u8 vendor_specific_code; -} __attribute__ ((packed)); - struct fsf_qual_latency_info { u32 channel_lat; u32 fabric_lat; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index b8ed42bb5c9e..72e3094796d4 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -10,7 +10,7 @@ /* FIXME(tune): free space should be one max. SBAL chain plus what? */ #define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ - - (ZFCP_MAX_SBALS_PER_REQ + 4)) + - (FSF_MAX_SBALS_PER_REQ + 4)) #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) @@ -432,9 +432,9 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter) /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ req_q = &adapter->req_q; - write_lock_irq(&req_q->lock); + spin_lock(&req_q->lock); atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); - write_unlock_irq(&req_q->lock); + spin_unlock(&req_q->lock); while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index e6d8ea8051af..aeae56b00b45 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -182,7 +182,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); return retval; } - fsf_req->data = 0; + fsf_req->data = NULL; fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; /* don't access old fsf_req after releasing the abort_lock */ @@ -220,8 +220,7 @@ static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, int retval = SUCCESS; /* issue task management function */ - fsf_req = zfcp_fsf_send_fcp_command_task_management - (adapter, unit, tm_flags, 0); + fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0); if (!fsf_req) { zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); return FAILED; -- cgit v1.2.3 From 287ac01acf22ab6aaaf9f5a4919ce2449c8b391c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 2 Jul 2008 10:56:40 +0200 Subject: [SCSI] zfcp: Cleanup code in zfcp_erp.c Cleanup the code in zfcp_erp.c, move erp internal definititions to this file and move FSF timeout handling to the FSF layer. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 45 - drivers/s390/scsi/zfcp_erp.c | 3500 ++++++++++++++++-------------------------- drivers/s390/scsi/zfcp_ext.h | 25 +- drivers/s390/scsi/zfcp_fsf.c | 43 +- 4 files changed, 1345 insertions(+), 2268 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 206b6e7a8bfd..67f45fc62f53 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -91,17 +91,11 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) /* max. number of (data buffer) SBALEs in largest SBAL chain multiplied with number of sectors per 4k block */ -#define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */ - /********************* FSF SPECIFIC DEFINES *********************************/ /* ATTENTION: value must not be used by hardware */ #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 -/* Do 1st retry in 1 second, then double the timeout for each following retry */ -#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 1 -#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7 - /* timeout value for "default timer" for fsf requests */ #define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ) @@ -349,45 +343,6 @@ struct zfcp_rc_entry { #define ZFCP_STATUS_FSFREQ_RETRY 0x00000800 #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 -/*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/ - -#define ZFCP_MAX_ERPS 3 - -#define ZFCP_ERP_FSFREQ_TIMEOUT (30 * HZ) -#define ZFCP_ERP_MEMWAIT_TIMEOUT HZ - -#define ZFCP_STATUS_ERP_TIMEDOUT 0x10000000 -#define ZFCP_STATUS_ERP_CLOSE_ONLY 0x01000000 -#define ZFCP_STATUS_ERP_DISMISSING 0x00100000 -#define ZFCP_STATUS_ERP_DISMISSED 0x00200000 -#define ZFCP_STATUS_ERP_LOWMEM 0x00400000 - -#define ZFCP_ERP_STEP_UNINITIALIZED 0x00000000 -#define ZFCP_ERP_STEP_FSF_XCONFIG 0x00000001 -#define ZFCP_ERP_STEP_PHYS_PORT_CLOSING 0x00000010 -#define ZFCP_ERP_STEP_PORT_CLOSING 0x00000100 -#define ZFCP_ERP_STEP_NAMESERVER_OPEN 0x00000200 -#define ZFCP_ERP_STEP_NAMESERVER_LOOKUP 0x00000400 -#define ZFCP_ERP_STEP_PORT_OPENING 0x00000800 -#define ZFCP_ERP_STEP_UNIT_CLOSING 0x00001000 -#define ZFCP_ERP_STEP_UNIT_OPENING 0x00002000 - -/* Ordered by escalation level (necessary for proper erp-code operation) */ -#define ZFCP_ERP_ACTION_REOPEN_ADAPTER 0x4 -#define ZFCP_ERP_ACTION_REOPEN_PORT_FORCED 0x3 -#define ZFCP_ERP_ACTION_REOPEN_PORT 0x2 -#define ZFCP_ERP_ACTION_REOPEN_UNIT 0x1 - -#define ZFCP_ERP_ACTION_RUNNING 0x1 -#define ZFCP_ERP_ACTION_READY 0x2 - -#define ZFCP_ERP_SUCCEEDED 0x0 -#define ZFCP_ERP_FAILED 0x1 -#define ZFCP_ERP_CONTINUES 0x2 -#define ZFCP_ERP_EXIT 0x3 -#define ZFCP_ERP_DISMISSED 0x4 -#define ZFCP_ERP_NOMEM 0x5 - /************************* STRUCTURE DEFINITIONS *****************************/ struct zfcp_fsf_req; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 4d797e5264d9..643ac4bba5b5 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -8,373 +8,399 @@ #include "zfcp_ext.h" -static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int, u8, - void *); -static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int, u8, - void *); -static int zfcp_erp_port_reopen_internal(struct zfcp_port *, int, u8, void *); -static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *, int, u8, void *); - -static int zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *, int, u8, - void *); -static int zfcp_erp_unit_reopen_all_internal(struct zfcp_port *, int, u8, - void *); - -static void zfcp_erp_adapter_block(struct zfcp_adapter *, int); -static void zfcp_erp_adapter_unblock(struct zfcp_adapter *); -static void zfcp_erp_port_block(struct zfcp_port *, int); -static void zfcp_erp_port_unblock(struct zfcp_port *); -static void zfcp_erp_unit_block(struct zfcp_unit *, int); -static void zfcp_erp_unit_unblock(struct zfcp_unit *); - -static int zfcp_erp_thread(void *); - -static int zfcp_erp_strategy(struct zfcp_erp_action *); - -static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *); -static int zfcp_erp_strategy_memwait(struct zfcp_erp_action *); -static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *, int); -static int zfcp_erp_strategy_check_unit(struct zfcp_unit *, int); -static int zfcp_erp_strategy_check_port(struct zfcp_port *, int); -static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int); -static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *, - struct zfcp_port *, - struct zfcp_unit *, int); -static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); -static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *, - struct zfcp_port *, - struct zfcp_unit *, int); -static int zfcp_erp_strategy_check_queues(struct zfcp_adapter *); -static int zfcp_erp_strategy_check_action(struct zfcp_erp_action *, int); - -static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int); -static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_open_fsf_statusread( - struct zfcp_erp_action *); - -static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *); -static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *); - -static int zfcp_erp_port_strategy(struct zfcp_erp_action *); -static int zfcp_erp_port_strategy_clearstati(struct zfcp_port *); -static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *); -static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *); -static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *); -static int zfcp_erp_port_strategy_open_nameserver_wakeup( - struct zfcp_erp_action *); -static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *); -static int zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *); -static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *); - -static int zfcp_erp_unit_strategy(struct zfcp_erp_action *); -static int zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *); -static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *); -static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *); - -static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *); -static void zfcp_erp_action_dismiss_port(struct zfcp_port *); -static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *); -static void zfcp_erp_action_dismiss(struct zfcp_erp_action *); - -static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *, - struct zfcp_port *, struct zfcp_unit *, - u8 id, void *ref); -static int zfcp_erp_action_dequeue(struct zfcp_erp_action *); -static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, - struct zfcp_port *, struct zfcp_unit *, - int); - -static void zfcp_erp_action_ready(struct zfcp_erp_action *); -static int zfcp_erp_action_exists(struct zfcp_erp_action *); - -static void zfcp_erp_action_to_ready(struct zfcp_erp_action *); -static void zfcp_erp_action_to_running(struct zfcp_erp_action *); - -static void zfcp_erp_memwait_handler(unsigned long); +#define ZFCP_MAX_ERPS 3 + +enum zfcp_erp_act_flags { + ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000, + ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000, + ZFCP_STATUS_ERP_DISMISSING = 0x00100000, + ZFCP_STATUS_ERP_DISMISSED = 0x00200000, + ZFCP_STATUS_ERP_LOWMEM = 0x00400000, +}; -/** - * zfcp_close_fsf - stop FSF operations for an adapter - * - * Dismiss and cleanup all pending fsf_reqs (this wakes up all initiators of - * requests waiting for completion; especially this returns SCSI commands - * with error state). - */ -static void zfcp_close_fsf(struct zfcp_adapter *adapter) +enum zfcp_erp_steps { + ZFCP_ERP_STEP_UNINITIALIZED = 0x0000, + ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, + ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, + ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, + ZFCP_ERP_STEP_NAMESERVER_OPEN = 0x0200, + ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400, + ZFCP_ERP_STEP_PORT_OPENING = 0x0800, + ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, + ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, +}; + +enum zfcp_erp_act_type { + ZFCP_ERP_ACTION_REOPEN_UNIT = 1, + ZFCP_ERP_ACTION_REOPEN_PORT = 2, + ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, + ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, +}; + +enum zfcp_erp_act_state { + ZFCP_ERP_ACTION_RUNNING = 1, + ZFCP_ERP_ACTION_READY = 2, +}; + +enum zfcp_erp_act_result { + ZFCP_ERP_SUCCEEDED = 0, + ZFCP_ERP_FAILED = 1, + ZFCP_ERP_CONTINUES = 2, + ZFCP_ERP_EXIT = 3, + ZFCP_ERP_DISMISSED = 4, + ZFCP_ERP_NOMEM = 5, +}; + +static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) { - /* close queues to ensure that buffers are not accessed by adapter */ - zfcp_qdio_close(adapter); - zfcp_fsf_req_dismiss_all(adapter); - /* reset FSF request sequence number */ - adapter->fsf_req_seq_no = 0; - /* all ports and units are closed */ - zfcp_erp_modify_adapter_status(adapter, 24, NULL, - ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); + zfcp_erp_modify_adapter_status(adapter, 15, NULL, + ZFCP_STATUS_COMMON_UNBLOCKED | mask, + ZFCP_CLEAR); } -/** - * zfcp_fsf_request_timeout_handler - called if a request timed out - * @data: pointer to adapter for handler function - * - * This function needs to be called if requests (ELS, Generic Service, - * or SCSI commands) exceed a certain time limit. The assumption is - * that after the time limit the adapter get stuck. So we trigger a reopen of - * the adapter. - */ -static void zfcp_fsf_request_timeout_handler(unsigned long data) +static int zfcp_erp_action_exists(struct zfcp_erp_action *act) { - struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; - zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62, - NULL); + struct zfcp_erp_action *curr_act; + + list_for_each_entry(curr_act, &act->adapter->erp_running_head, list) + if (act == curr_act) + return ZFCP_ERP_ACTION_RUNNING; + return 0; } -void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout) +static void zfcp_erp_action_ready(struct zfcp_erp_action *act) { - fsf_req->timer.function = zfcp_fsf_request_timeout_handler; - fsf_req->timer.data = (unsigned long) fsf_req->adapter; - fsf_req->timer.expires = jiffies + timeout; - add_timer(&fsf_req->timer); + struct zfcp_adapter *adapter = act->adapter; + + list_move(&act->list, &act->adapter->erp_ready_head); + zfcp_rec_dbf_event_action(146, act); + up(&adapter->erp_ready_sem); + zfcp_rec_dbf_event_thread(2, adapter); } -/* - * function: - * - * purpose: called if an adapter failed, - * initiates adapter recovery which is done - * asynchronously - * - * returns: 0 - initiated action successfully - * <0 - failed to initiate action - */ -static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, - int clear_mask, u8 id, void *ref) +static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) { - int retval; + act->status |= ZFCP_STATUS_ERP_DISMISSED; + if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING) + zfcp_erp_action_ready(act); +} - zfcp_erp_adapter_block(adapter, clear_mask); +static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) +{ + if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) + zfcp_erp_action_dismiss(&unit->erp_action); +} - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { - /* ensure propagation of failed status to new devices */ - zfcp_erp_adapter_failed(adapter, 13, NULL); - retval = -EIO; - goto out; - } - retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, - adapter, NULL, NULL, id, ref); +static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) +{ + struct zfcp_unit *unit; - out: - return retval; + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) + zfcp_erp_action_dismiss(&port->erp_action); + else + list_for_each_entry(unit, &port->unit_list_head, list) + zfcp_erp_action_dismiss_unit(unit); } -/* - * function: - * - * purpose: Wrappper for zfcp_erp_adapter_reopen_internal - * used to ensure the correct locking - * - * returns: 0 - initiated action successfully - * <0 - failed to initiate action - */ -int zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear_mask, - u8 id, void *ref) +static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) { - int retval; - unsigned long flags; - - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); - retval = zfcp_erp_adapter_reopen_internal(adapter, clear_mask, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + struct zfcp_port *port; - return retval; + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) + zfcp_erp_action_dismiss(&adapter->erp_action); + else + list_for_each_entry(port, &adapter->port_list_head, list) + zfcp_erp_action_dismiss_port(port); } -int zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear_mask, - u8 id, void *ref) +static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct zfcp_unit *unit) { - int retval; + int need = want; + int u_status, p_status, a_status; - retval = zfcp_erp_adapter_reopen(adapter, - ZFCP_STATUS_COMMON_RUNNING | - ZFCP_STATUS_COMMON_ERP_FAILED | - clear_mask, id, ref); + switch (want) { + case ZFCP_ERP_ACTION_REOPEN_UNIT: + u_status = atomic_read(&unit->status); + if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) + return 0; + p_status = atomic_read(&port->status); + if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || + p_status & ZFCP_STATUS_COMMON_ERP_FAILED) + return 0; + if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) + need = ZFCP_ERP_ACTION_REOPEN_PORT; + /* fall through */ + case ZFCP_ERP_ACTION_REOPEN_PORT: + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + p_status = atomic_read(&port->status); + if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) + return 0; + a_status = atomic_read(&adapter->status); + if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || + a_status & ZFCP_STATUS_COMMON_ERP_FAILED) + return 0; + if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) + need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; + /* fall through */ + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + a_status = atomic_read(&adapter->status); + if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) + return 0; + } - return retval; + return need; } -int zfcp_erp_port_shutdown(struct zfcp_port *port, int clear_mask, u8 id, - void *ref) +static struct zfcp_erp_action *zfcp_erp_setup_act(int need, + struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct zfcp_unit *unit) { - int retval; + struct zfcp_erp_action *erp_action; + u32 status = 0; - retval = zfcp_erp_port_reopen(port, - ZFCP_STATUS_COMMON_RUNNING | - ZFCP_STATUS_COMMON_ERP_FAILED | - clear_mask, id, ref); + switch (need) { + case ZFCP_ERP_ACTION_REOPEN_UNIT: + zfcp_unit_get(unit); + atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); + erp_action = &unit->erp_action; + if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) + status = ZFCP_STATUS_ERP_CLOSE_ONLY; + break; - return retval; -} + case ZFCP_ERP_ACTION_REOPEN_PORT: + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + zfcp_port_get(port); + zfcp_erp_action_dismiss_port(port); + atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); + erp_action = &port->erp_action; + if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) + status = ZFCP_STATUS_ERP_CLOSE_ONLY; + break; -int zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask, u8 id, - void *ref) -{ - int retval; + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + zfcp_adapter_get(adapter); + zfcp_erp_action_dismiss_adapter(adapter); + atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); + erp_action = &adapter->erp_action; + if (!(atomic_read(&adapter->status) & + ZFCP_STATUS_COMMON_RUNNING)) + status = ZFCP_STATUS_ERP_CLOSE_ONLY; + break; + + default: + return NULL; + } - retval = zfcp_erp_unit_reopen(unit, - ZFCP_STATUS_COMMON_RUNNING | - ZFCP_STATUS_COMMON_ERP_FAILED | - clear_mask, id, ref); + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); + erp_action->adapter = adapter; + erp_action->port = port; + erp_action->unit = unit; + erp_action->action = need; + erp_action->status = status; - return retval; + return erp_action; } -/* - * function: - * - * purpose: called if a port failed to be opened normally - * initiates Forced Reopen recovery which is done - * asynchronously - * - * returns: 0 - initiated action successfully - * <0 - failed to initiate action - */ -static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, - int clear_mask, u8 id, - void *ref) +static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct zfcp_unit *unit, u8 id, void *ref) { - int retval; + int retval = 1, need; + struct zfcp_erp_action *act = NULL; - zfcp_erp_port_block(port, clear_mask); + if (!(atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)) + return -EIO; - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { - retval = -EIO; + need = zfcp_erp_required_act(want, adapter, port, unit); + if (!need) goto out; - } - - retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, - port->adapter, port, NULL, id, ref); + atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); + act = zfcp_erp_setup_act(need, adapter, port, unit); + if (!act) + goto out; + ++adapter->erp_total_count; + list_add_tail(&act->list, &adapter->erp_ready_head); + up(&adapter->erp_ready_sem); + zfcp_rec_dbf_event_thread(1, adapter); + retval = 0; out: + zfcp_rec_dbf_event_trigger(id, ref, want, need, act, + adapter, port, unit); return retval; } -/* - * function: - * - * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal - * used to ensure the correct locking - * - * returns: 0 - initiated action successfully - * <0 - failed to initiate action +static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, + int clear_mask, u8 id, void *ref) +{ + zfcp_erp_adapter_block(adapter, clear_mask); + + /* ensure propagation of failed status to new devices */ + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + zfcp_erp_adapter_failed(adapter, 13, NULL); + return -EIO; + } + return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, + adapter, NULL, NULL, id, ref); +} + +/** + * zfcp_erp_adapter_reopen - Reopen adapter. + * @adapter: Adapter to reopen. + * @clear: Status flags to clear. + * @id: Id for debug trace event. + * @ref: Reference for debug trace event. */ -int zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask, u8 id, - void *ref) +void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, + u8 id, void *ref) { - int retval; unsigned long flags; - struct zfcp_adapter *adapter; - adapter = port->adapter; read_lock_irqsave(&zfcp_data.config_lock, flags); write_lock(&adapter->erp_lock); - retval = zfcp_erp_port_forced_reopen_internal(port, clear_mask, id, - ref); + _zfcp_erp_adapter_reopen(adapter, clear, id, ref); write_unlock(&adapter->erp_lock); read_unlock_irqrestore(&zfcp_data.config_lock, flags); +} - return retval; +/** + * zfcp_erp_adapter_shutdown - Shutdown adapter. + * @adapter: Adapter to shut down. + * @clear: Status flags to clear. + * @id: Id for debug trace event. + * @ref: Reference for debug trace event. + */ +void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, + u8 id, void *ref) +{ + int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); } -/* - * function: - * - * purpose: called if a port is to be opened - * initiates Reopen recovery which is done - * asynchronously - * - * returns: 0 - initiated action successfully - * <0 - failed to initiate action +/** + * zfcp_erp_port_shutdown - Shutdown port + * @port: Port to shut down. + * @clear: Status flags to clear. + * @id: Id for debug trace event. + * @ref: Reference for debug trace event. */ -static int zfcp_erp_port_reopen_internal(struct zfcp_port *port, int clear_mask, - u8 id, void *ref) +void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, u8 id, void *ref) { - int retval; + int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + zfcp_erp_port_reopen(port, clear | flags, id, ref); +} + +/** + * zfcp_erp_unit_shutdown - Shutdown unit + * @unit: Unit to shut down. + * @clear: Status flags to clear. + * @id: Id for debug trace event. + * @ref: Reference for debug trace event. + */ +void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, u8 id, void *ref) +{ + int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + zfcp_erp_unit_reopen(unit, clear | flags, id, ref); +} + +static void zfcp_erp_port_block(struct zfcp_port *port, int clear) +{ + zfcp_erp_modify_port_status(port, 17, NULL, + ZFCP_STATUS_COMMON_UNBLOCKED | clear, + ZFCP_CLEAR); +} + +static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, + int clear, u8 id, void *ref) +{ + zfcp_erp_port_block(port, clear); + + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + return; - zfcp_erp_port_block(port, clear_mask); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, + port->adapter, port, NULL, id, ref); +} + +/** + * zfcp_erp_port_forced_reopen - Forced close of port and open again + * @port: Port to force close and to reopen. + * @id: Id for debug trace event. + * @ref: Reference for debug trace event. + */ +void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, u8 id, + void *ref) +{ + unsigned long flags; + struct zfcp_adapter *adapter = port->adapter; + + read_lock_irqsave(&zfcp_data.config_lock, flags); + write_lock(&adapter->erp_lock); + _zfcp_erp_port_forced_reopen(port, clear, id, ref); + write_unlock(&adapter->erp_lock); + read_unlock_irqrestore(&zfcp_data.config_lock, flags); +} + +static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, + void *ref) +{ + zfcp_erp_port_block(port, clear); - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { /* ensure propagation of failed status to new devices */ zfcp_erp_port_failed(port, 14, NULL); - retval = -EIO; - goto out; + return -EIO; } - retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, - port->adapter, port, NULL, id, ref); - - out: - return retval; + return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, + port->adapter, port, NULL, id, ref); } /** - * zfcp_erp_port_reopen - initiate reopen of a remote port - * @port: port to be reopened - * @clear_mask: specifies flags in port status to be cleared - * Return: 0 on success, < 0 on error + * zfcp_erp_port_reopen - trigger remote port recovery + * @port: port to recover + * @clear_mask: flags in port status to be cleared * - * This is a wrappper function for zfcp_erp_port_reopen_internal. It ensures - * correct locking. An error recovery task is initiated to do the reopen. - * To wait for the completion of the reopen zfcp_erp_wait should be used. + * Returns 0 if recovery has been triggered, < 0 if not. */ -int zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask, u8 id, - void *ref) +int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, void *ref) { - int retval; unsigned long flags; + int retval; struct zfcp_adapter *adapter = port->adapter; read_lock_irqsave(&zfcp_data.config_lock, flags); write_lock(&adapter->erp_lock); - retval = zfcp_erp_port_reopen_internal(port, clear_mask, id, ref); + retval = _zfcp_erp_port_reopen(port, clear, id, ref); write_unlock(&adapter->erp_lock); read_unlock_irqrestore(&zfcp_data.config_lock, flags); return retval; } -/* - * function: - * - * purpose: called if a unit is to be opened - * initiates Reopen recovery which is done - * asynchronously - * - * returns: 0 - initiated action successfully - * <0 - failed to initiate action - */ -static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask, - u8 id, void *ref) +static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) +{ + zfcp_erp_modify_unit_status(unit, 19, NULL, + ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, + ZFCP_CLEAR); +} + +static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, + void *ref) { - int retval; struct zfcp_adapter *adapter = unit->port->adapter; - zfcp_erp_unit_block(unit, clear_mask); + zfcp_erp_unit_block(unit, clear); - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { - retval = -EIO; - goto out; - } + if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + return; - retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, - adapter, unit->port, unit, id, ref); - out: - return retval; + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, + adapter, unit->port, unit, id, ref); } /** @@ -382,790 +408,655 @@ static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask, * @unit: unit to be reopened * @clear_mask: specifies flags in unit status to be cleared * Return: 0 on success, < 0 on error - * - * This is a wrappper for zfcp_erp_unit_reopen_internal. It ensures correct - * locking. An error recovery task is initiated to do the reopen. - * To wait for the completion of the reopen zfcp_erp_wait should be used. */ -int zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask, u8 id, - void *ref) +void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, void *ref) { - int retval; unsigned long flags; - struct zfcp_adapter *adapter; - struct zfcp_port *port; - - port = unit->port; - adapter = port->adapter; + struct zfcp_port *port = unit->port; + struct zfcp_adapter *adapter = port->adapter; read_lock_irqsave(&zfcp_data.config_lock, flags); write_lock(&adapter->erp_lock); - retval = zfcp_erp_unit_reopen_internal(unit, clear_mask, id, ref); + _zfcp_erp_unit_reopen(unit, clear, id, ref); write_unlock(&adapter->erp_lock); read_unlock_irqrestore(&zfcp_data.config_lock, flags); - - return retval; } -/** - * zfcp_erp_adapter_block - mark adapter as blocked, block scsi requests - */ -static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask) +static int status_change_set(unsigned long mask, atomic_t *status) { - zfcp_erp_modify_adapter_status(adapter, 15, NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | - clear_mask, ZFCP_CLEAR); + return (atomic_read(status) ^ mask) & mask; } -/* FIXME: isn't really atomic */ -/* - * returns the mask which has not been set so far, i.e. - * 0 if no bit has been changed, !0 if some bit has been changed - */ -static int atomic_test_and_set_mask(unsigned long mask, atomic_t *v) +static int status_change_clear(unsigned long mask, atomic_t *status) { - int changed_bits = (atomic_read(v) /*XOR*/^ mask) & mask; - atomic_set_mask(mask, v); - return changed_bits; + return atomic_read(status) & mask; } -/* FIXME: isn't really atomic */ -/* - * returns the mask which has not been cleared so far, i.e. - * 0 if no bit has been changed, !0 if some bit has been changed - */ -static int atomic_test_and_clear_mask(unsigned long mask, atomic_t *v) +static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) { - int changed_bits = atomic_read(v) & mask; - atomic_clear_mask(mask, v); - return changed_bits; + if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) + zfcp_rec_dbf_event_adapter(16, NULL, adapter); + atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); } -/** - * zfcp_erp_adapter_unblock - mark adapter as unblocked, allow scsi requests - */ -static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) +static void zfcp_erp_port_unblock(struct zfcp_port *port) { - if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, - &adapter->status)) - zfcp_rec_dbf_event_adapter(16, NULL, adapter); + if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) + zfcp_rec_dbf_event_port(18, NULL, port); + atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } -/* - * function: - * - * purpose: disable I/O, - * return any open requests and clean them up, - * aim: no pending and incoming I/O - * - * returns: - */ -static void -zfcp_erp_port_block(struct zfcp_port *port, int clear_mask) +static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) { - zfcp_erp_modify_port_status(port, 17, NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, - ZFCP_CLEAR); + if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) + zfcp_rec_dbf_event_unit(20, NULL, unit); + atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); } -/* - * function: - * - * purpose: enable I/O - * - * returns: - */ -static void -zfcp_erp_port_unblock(struct zfcp_port *port) +static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) { - if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, - &port->status)) - zfcp_rec_dbf_event_port(18, NULL, port); + list_move(&erp_action->list, &erp_action->adapter->erp_running_head); + zfcp_rec_dbf_event_action(145, erp_action); } -/* - * function: - * - * purpose: disable I/O, - * return any open requests and clean them up, - * aim: no pending and incoming I/O - * - * returns: - */ -static void -zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) +static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) { - zfcp_erp_modify_unit_status(unit, 19, NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, - ZFCP_CLEAR); -} - -/* - * function: - * - * purpose: enable I/O - * - * returns: - */ -static void -zfcp_erp_unit_unblock(struct zfcp_unit *unit) -{ - if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, - &unit->status)) - zfcp_rec_dbf_event_unit(20, NULL, unit); -} - -static void -zfcp_erp_action_ready(struct zfcp_erp_action *erp_action) -{ - struct zfcp_adapter *adapter = erp_action->adapter; - - zfcp_erp_action_to_ready(erp_action); - up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread(2, adapter); -} + struct zfcp_adapter *adapter = act->adapter; -/* - * function: - * - * purpose: - * - * returns: <0 erp_action not found in any list - * ZFCP_ERP_ACTION_READY erp_action is in ready list - * ZFCP_ERP_ACTION_RUNNING erp_action is in running list - * - * locks: erp_lock must be held - */ -static int -zfcp_erp_action_exists(struct zfcp_erp_action *erp_action) -{ - int retval = -EINVAL; - struct list_head *entry; - struct zfcp_erp_action *entry_erp_action; - struct zfcp_adapter *adapter = erp_action->adapter; + if (!act->fsf_req) + return; - /* search in running list */ - list_for_each(entry, &adapter->erp_running_head) { - entry_erp_action = - list_entry(entry, struct zfcp_erp_action, list); - if (entry_erp_action == erp_action) { - retval = ZFCP_ERP_ACTION_RUNNING; - goto out; - } - } - /* search in ready list */ - list_for_each(entry, &adapter->erp_ready_head) { - entry_erp_action = - list_entry(entry, struct zfcp_erp_action, list); - if (entry_erp_action == erp_action) { - retval = ZFCP_ERP_ACTION_READY; - goto out; + spin_lock(&adapter->req_list_lock); + if (zfcp_reqlist_find_safe(adapter, act->fsf_req) && + act->fsf_req->erp_action == act) { + if (act->status & (ZFCP_STATUS_ERP_DISMISSED | + ZFCP_STATUS_ERP_TIMEDOUT)) { + act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; + zfcp_rec_dbf_event_action(142, act); } - } - - out: - return retval; + if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) + zfcp_rec_dbf_event_action(143, act); + if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | + ZFCP_STATUS_FSFREQ_DISMISSED)) + act->fsf_req = NULL; + } else + act->fsf_req = NULL; + spin_unlock(&adapter->req_list_lock); } -/* - * purpose: checks current status of action (timed out, dismissed, ...) - * and does appropriate preparations (dismiss fsf request, ...) - * - * locks: called under erp_lock (disabled interrupts) +/** + * zfcp_erp_notify - Trigger ERP action. + * @erp_action: ERP action to continue. + * @set_mask: ERP action status flags to set. */ -static void -zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) +void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) { struct zfcp_adapter *adapter = erp_action->adapter; + unsigned long flags; - if (erp_action->fsf_req) { - /* take lock to ensure that request is not deleted meanwhile */ - spin_lock(&adapter->req_list_lock); - if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) && - erp_action->fsf_req->erp_action == erp_action) { - /* fsf_req still exists */ - /* dismiss fsf_req of timed out/dismissed erp_action */ - if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED | - ZFCP_STATUS_ERP_TIMEDOUT)) { - erp_action->fsf_req->status |= - ZFCP_STATUS_FSFREQ_DISMISSED; - zfcp_rec_dbf_event_action(142, erp_action); - } - if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) - zfcp_rec_dbf_event_action(143, erp_action); - /* - * If fsf_req is neither dismissed nor completed - * then keep it running asynchronously and don't mess - * with the association of erp_action and fsf_req. - */ - if (erp_action->fsf_req->status & - (ZFCP_STATUS_FSFREQ_COMPLETED | - ZFCP_STATUS_FSFREQ_DISMISSED)) { - /* forget about association between fsf_req - and erp_action */ - erp_action->fsf_req = NULL; - } - } else { - /* - * even if this fsf_req has gone, forget about - * association between erp_action and fsf_req - */ - erp_action->fsf_req = NULL; - } - spin_unlock(&adapter->req_list_lock); - } -} - -/** - * zfcp_erp_async_handler_nolock - complete erp_action - * - * Used for normal completion, time-out, dismissal and failure after - * low memory condition. - */ -static void zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action, - unsigned long set_mask) -{ + write_lock_irqsave(&adapter->erp_lock, flags); if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { erp_action->status |= set_mask; zfcp_erp_action_ready(erp_action); - } else { - /* action is ready or gone - nothing to do */ } -} - -/** - * zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w/ locking - */ -void zfcp_erp_async_handler(struct zfcp_erp_action *erp_action, - unsigned long set_mask) -{ - struct zfcp_adapter *adapter = erp_action->adapter; - unsigned long flags; - - write_lock_irqsave(&adapter->erp_lock, flags); - zfcp_erp_async_handler_nolock(erp_action, set_mask); write_unlock_irqrestore(&adapter->erp_lock, flags); } -/* - * purpose: is called for erp_action which was slept waiting for - * memory becoming avaliable, - * will trigger that this action will be continued +/** + * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request + * @data: ERP action (from timer data) */ -static void -zfcp_erp_memwait_handler(unsigned long data) +void zfcp_erp_timeout_handler(unsigned long data) { - struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; - - zfcp_erp_async_handler(erp_action, 0); + struct zfcp_erp_action *act = (struct zfcp_erp_action *) data; + zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT); } -/* - * purpose: is called if an asynchronous erp step timed out, - * action gets an appropriate flag and will be processed - * accordingly - */ -static void zfcp_erp_timeout_handler(unsigned long data) +static void zfcp_erp_memwait_handler(unsigned long data) { - struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; - - zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT); + zfcp_erp_notify((struct zfcp_erp_action *)data, 0); } -/** - * zfcp_erp_action_dismiss - dismiss an erp_action - * - * adapter->erp_lock must be held - * - * Dismissal of an erp_action is usually required if an erp_action of - * higher priority is generated. - */ -static void zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action) +static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) { - erp_action->status |= ZFCP_STATUS_ERP_DISMISSED; - if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) - zfcp_erp_action_ready(erp_action); + init_timer(&erp_action->timer); + erp_action->timer.function = zfcp_erp_memwait_handler; + erp_action->timer.data = (unsigned long) erp_action; + erp_action->timer.expires = jiffies + HZ; + add_timer(&erp_action->timer); } -int -zfcp_erp_thread_setup(struct zfcp_adapter *adapter) +static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, + int clear, u8 id, void *ref) { - int retval = 0; - - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - - retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); - if (retval < 0) - dev_err(&adapter->ccw_device->dev, - "Creation of ERP thread failed.\n"); - else { - wait_event(adapter->erp_thread_wqh, - atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, - &adapter->status)); - } + struct zfcp_port *port; - return (retval < 0); + list_for_each_entry(port, &adapter->port_list_head, list) + if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)) + _zfcp_erp_port_reopen(port, clear, id, ref); } -/* - * function: - * - * purpose: - * - * returns: - * - * context: process (i.e. proc-fs or rmmod/insmod) - * - * note: The caller of this routine ensures that the specified - * adapter has been shut down and that this operation - * has been completed. Thus, there are no pending erp_actions - * which would need to be handled here. - */ -int -zfcp_erp_thread_kill(struct zfcp_adapter *adapter) +static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id, + void *ref) { - int retval = 0; - - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); - up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock(2, adapter); - - wait_event(adapter->erp_thread_wqh, - !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, - &adapter->status)); - - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, - &adapter->status); + struct zfcp_unit *unit; - return retval; + list_for_each_entry(unit, &port->unit_list_head, list) + _zfcp_erp_unit_reopen(unit, clear, id, ref); } -/* - * purpose: is run as a kernel thread, - * goes through list of error recovery actions of associated adapter - * and delegates single action to execution - * - * returns: 0 - */ -static int -zfcp_erp_thread(void *data) +static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) { - struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; - struct list_head *next; - struct zfcp_erp_action *erp_action; - unsigned long flags; + struct zfcp_adapter *adapter = act->adapter; + struct zfcp_port *port = act->port; + struct zfcp_unit *unit = act->unit; + u32 status = act->status; - daemonize("zfcperp%s", zfcp_get_busid_by_adapter(adapter)); - /* Block all signals */ - siginitsetinv(¤t->blocked, 0); - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - wake_up(&adapter->erp_thread_wqh); + /* initiate follow-up actions depending on success of finished action */ + switch (act->action) { - while (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, - &adapter->status)) { + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + if (status == ZFCP_ERP_SUCCEEDED) + _zfcp_erp_port_reopen_all(adapter, 0, 70, NULL); + else + _zfcp_erp_adapter_reopen(adapter, 0, 71, NULL); + break; - write_lock_irqsave(&adapter->erp_lock, flags); - next = adapter->erp_ready_head.next; - write_unlock_irqrestore(&adapter->erp_lock, flags); + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + if (status == ZFCP_ERP_SUCCEEDED) + _zfcp_erp_port_reopen(port, 0, 72, NULL); + else + _zfcp_erp_adapter_reopen(adapter, 0, 73, NULL); + break; - if (next != &adapter->erp_ready_head) { - erp_action = - list_entry(next, struct zfcp_erp_action, list); - /* - * process action (incl. [re]moving it - * from 'ready' queue) - */ - zfcp_erp_strategy(erp_action); - } + case ZFCP_ERP_ACTION_REOPEN_PORT: + if (status == ZFCP_ERP_SUCCEEDED) + _zfcp_erp_unit_reopen_all(port, 0, 74, NULL); + else + _zfcp_erp_port_forced_reopen(port, 0, 75, NULL); + break; - /* - * sleep as long as there is nothing to do, i.e. - * no action in 'ready' queue to be processed and - * thread is not to be killed - */ - zfcp_rec_dbf_event_thread_lock(4, adapter); - down_interruptible(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock(5, adapter); + case ZFCP_ERP_ACTION_REOPEN_UNIT: + if (status != ZFCP_ERP_SUCCEEDED) + _zfcp_erp_port_reopen(unit->port, 0, 76, NULL); + break; } - - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - wake_up(&adapter->erp_thread_wqh); - - return 0; } -/* - * function: - * - * purpose: drives single error recovery action and schedules higher and - * subordinate actions, if necessary - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_SUCCEEDED - action finished successfully (deqd) - * ZFCP_ERP_FAILED - action finished unsuccessfully (deqd) - * ZFCP_ERP_EXIT - action finished (dequeued), offline - * ZFCP_ERP_DISMISSED - action canceled (dequeued) - */ -static int -zfcp_erp_strategy(struct zfcp_erp_action *erp_action) +static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) { - int retval = 0; - struct zfcp_adapter *adapter = erp_action->adapter; - struct zfcp_port *port = erp_action->port; - struct zfcp_unit *unit = erp_action->unit; - int action = erp_action->action; - u32 status = erp_action->status; unsigned long flags; - /* serialise dismissing, timing out, moving, enqueueing */ read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); - - /* dequeue dismissed action and leave, if required */ - retval = zfcp_erp_strategy_check_action(erp_action, retval); - if (retval == ZFCP_ERP_DISMISSED) { - goto unlock; + read_lock(&adapter->erp_lock); + if (list_empty(&adapter->erp_ready_head) && + list_empty(&adapter->erp_running_head)) { + atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, + &adapter->status); + wake_up(&adapter->erp_done_wqh); } + read_unlock(&adapter->erp_lock); + read_unlock_irqrestore(&zfcp_data.config_lock, flags); +} - /* - * move action to 'running' queue before processing it - * (to avoid a race condition regarding moving the - * action to the 'running' queue and back) - */ - zfcp_erp_action_to_running(erp_action); +static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) +{ + if (zfcp_qdio_open(act->adapter)) + return ZFCP_ERP_FAILED; + init_waitqueue_head(&act->adapter->request_wq); + atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); + return ZFCP_ERP_SUCCEEDED; +} - /* - * try to process action as far as possible, - * no lock to allow for blocking operations (kmalloc, qdio, ...), - * afterwards the lock is required again for the following reasons: - * - dequeueing of finished action and enqueueing of - * follow-up actions must be atomic so that any other - * reopen-routine does not believe there is nothing to do - * and that it is safe to enqueue something else, - * - we want to force any control thread which is dismissing - * actions to finish this before we decide about - * necessary steps to be taken here further - */ - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - retval = zfcp_erp_strategy_do_action(erp_action); - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); +static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) +{ + struct zfcp_port *port; + port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, + adapter->peer_d_id); + if (IS_ERR(port)) /* error or port already attached */ + return; + _zfcp_erp_port_reopen(port, 0, 150, NULL); +} - /* - * check for dismissed status again to avoid follow-up actions, - * failing of targets and so on for dismissed actions, - * we go through down() here because there has been an up() - */ - if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) - retval = ZFCP_ERP_CONTINUES; +static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) +{ + int retries; + int sleep = 1; + struct zfcp_adapter *adapter = erp_action->adapter; - switch (retval) { - case ZFCP_ERP_NOMEM: - /* no memory to continue immediately, let it sleep */ - if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { - ++adapter->erp_low_mem_count; - erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; - } - /* This condition is true if there is no memory available - for any erp_action on this adapter. This implies that there - are no elements in the memory pool(s) left for erp_actions. - This might happen if an erp_action that used a memory pool - element was timed out. - */ - if (adapter->erp_total_count == adapter->erp_low_mem_count) - zfcp_erp_adapter_reopen_internal(adapter, 0, 66, NULL); - else - retval = zfcp_erp_strategy_memwait(erp_action); - goto unlock; - case ZFCP_ERP_CONTINUES: - /* leave since this action runs asynchronously */ - if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { - --adapter->erp_low_mem_count; - erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; + atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); + + for (retries = 7; retries; retries--) { + atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + &adapter->status); + write_lock_irq(&adapter->erp_lock); + zfcp_erp_action_to_running(erp_action); + write_unlock_irq(&adapter->erp_lock); + if (zfcp_fsf_exchange_config_data(erp_action)) { + atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + &adapter->status); + return ZFCP_ERP_FAILED; } - goto unlock; - } - /* ok, finished action (whatever its result is) */ - /* check for unrecoverable targets */ - retval = zfcp_erp_strategy_check_target(erp_action, retval); + zfcp_rec_dbf_event_thread_lock(6, adapter); + down(&adapter->erp_ready_sem); + zfcp_rec_dbf_event_thread_lock(7, adapter); + if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) + break; - /* action must be dequeued (here to allow for further ones) */ - zfcp_erp_action_dequeue(erp_action); + if (!(atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_HOST_CON_INIT)) + break; - /* - * put this target through the erp mill again if someone has - * requested to change the status of a target being online - * to offline or the other way around - * (old retval is preserved if nothing has to be done here) - */ - retval = zfcp_erp_strategy_statechange(action, status, adapter, - port, unit, retval); - - /* - * leave if target is in permanent error state or if - * action is repeated in order to process state change - */ - if (retval == ZFCP_ERP_EXIT) { - goto unlock; + ssleep(sleep); + sleep *= 2; } - /* trigger follow up actions */ - zfcp_erp_strategy_followup_actions(action, adapter, port, unit, retval); + atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + &adapter->status); - unlock: - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) + return ZFCP_ERP_FAILED; - if (retval != ZFCP_ERP_CONTINUES) - zfcp_erp_action_cleanup(action, adapter, port, unit, retval); - - /* - * a few tasks remain when the erp queues are empty - * (don't do that if the last action evaluated was dismissed - * since this clearly indicates that there is more to come) : - * - close the name server port if it is open yet - * (enqueues another [probably] final action) - * - otherwise, wake up whoever wants to be woken when we are - * done with erp - */ - if (retval != ZFCP_ERP_DISMISSED) - zfcp_erp_strategy_check_queues(adapter); + if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) + zfcp_erp_enqueue_ptp_port(adapter); - return retval; + return ZFCP_ERP_SUCCEEDED; } -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_DISMISSED - if action has been dismissed - * retval - otherwise - */ -static int -zfcp_erp_strategy_check_action(struct zfcp_erp_action *erp_action, int retval) +static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) { - zfcp_erp_strategy_check_fsfreq(erp_action); + int ret; + struct zfcp_adapter *adapter = act->adapter; - if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { - zfcp_erp_action_dequeue(erp_action); - retval = ZFCP_ERP_DISMISSED; - } + atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); - return retval; + write_lock_irq(&adapter->erp_lock); + zfcp_erp_action_to_running(act); + write_unlock_irq(&adapter->erp_lock); + + ret = zfcp_fsf_exchange_port_data(act); + if (ret == -EOPNOTSUPP) + return ZFCP_ERP_SUCCEEDED; + if (ret) + return ZFCP_ERP_FAILED; + + zfcp_rec_dbf_event_thread_lock(8, adapter); + down(&adapter->erp_ready_sem); + zfcp_rec_dbf_event_thread_lock(9, adapter); + if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) + return ZFCP_ERP_FAILED; + + return ZFCP_ERP_SUCCEEDED; } -static int -zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) +static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) { - int retval = ZFCP_ERP_FAILED; + if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED) + return ZFCP_ERP_FAILED; - /* - * try to execute/continue action as far as possible, - * note: no lock in subsequent strategy routines - * (this allows these routine to call schedule, e.g. - * kmalloc with such flags or qdio_initialize & friends) - * Note: in case of timeout, the separate strategies will fail - * anyhow. No need for a special action. Even worse, a nameserver - * failure would not wake up waiting ports without the call. - */ - switch (erp_action->action) { + if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) + return ZFCP_ERP_FAILED; - case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - retval = zfcp_erp_adapter_strategy(erp_action); - break; + atomic_set(&act->adapter->stat_miss, 16); + if (zfcp_status_read_refill(act->adapter)) + return ZFCP_ERP_FAILED; - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - retval = zfcp_erp_port_forced_strategy(erp_action); - break; + return ZFCP_ERP_SUCCEEDED; +} - case ZFCP_ERP_ACTION_REOPEN_PORT: - retval = zfcp_erp_port_strategy(erp_action); - break; +static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *act, + int close) +{ + int retval = ZFCP_ERP_SUCCEEDED; + struct zfcp_adapter *adapter = act->adapter; - case ZFCP_ERP_ACTION_REOPEN_UNIT: - retval = zfcp_erp_unit_strategy(erp_action); - break; - } + if (close) + goto close_only; + + retval = zfcp_erp_adapter_strategy_open_qdio(act); + if (retval != ZFCP_ERP_SUCCEEDED) + goto failed_qdio; + retval = zfcp_erp_adapter_strategy_open_fsf(act); + if (retval != ZFCP_ERP_SUCCEEDED) + goto failed_openfcp; + + atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &act->adapter->status); + schedule_work(&act->adapter->scan_work); + + return ZFCP_ERP_SUCCEEDED; + + close_only: + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + &act->adapter->status); + + failed_openfcp: + /* close queues to ensure that buffers are not accessed by adapter */ + zfcp_qdio_close(adapter); + zfcp_fsf_req_dismiss_all(adapter); + adapter->fsf_req_seq_no = 0; + /* all ports and units are closed */ + zfcp_erp_modify_adapter_status(adapter, 24, NULL, + ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); + failed_qdio: + atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | + ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | + ZFCP_STATUS_ADAPTER_XPORT_OK, + &act->adapter->status); return retval; } -/* - * function: - * - * purpose: triggers retry of this action after a certain amount of time - * by means of timer provided by erp_action - * - * returns: ZFCP_ERP_CONTINUES - erp_action sleeps in erp running queue - */ -static int -zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) +static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act) { - int retval = ZFCP_ERP_CONTINUES; + int retval; - init_timer(&erp_action->timer); - erp_action->timer.function = zfcp_erp_memwait_handler; - erp_action->timer.data = (unsigned long) erp_action; - erp_action->timer.expires = jiffies + ZFCP_ERP_MEMWAIT_TIMEOUT; - add_timer(&erp_action->timer); + atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status); + zfcp_erp_adapter_strategy_generic(act, 1); /* close */ + atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status); + if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY) + return ZFCP_ERP_EXIT; + + atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status); + retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */ + atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status); + + if (retval == ZFCP_ERP_FAILED) + ssleep(8); return retval; } -/* - * function: zfcp_erp_adapter_failed - * - * purpose: sets the adapter and all underlying devices to ERP_FAILED - * - */ -void -zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref) +static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act) { - zfcp_erp_modify_adapter_status(adapter, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); - dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n"); + int retval; + + retval = zfcp_fsf_close_physical_port(act); + if (retval == -ENOMEM) + return ZFCP_ERP_NOMEM; + act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; + if (retval) + return ZFCP_ERP_FAILED; + + return ZFCP_ERP_CONTINUES; } -/* - * function: zfcp_erp_port_failed - * - * purpose: sets the port and all underlying devices to ERP_FAILED - * - */ -void -zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref) +static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) { - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); + atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | + ZFCP_STATUS_COMMON_CLOSING | + ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_PORT_DID_DID | + ZFCP_STATUS_PORT_PHYS_CLOSING | + ZFCP_STATUS_PORT_INVALID_WWPN, + &port->status); +} - if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) - dev_err(&port->adapter->ccw_device->dev, - "Port ERP failed for WKA port d_id=0x%06x.\n", - port->d_id); - else - dev_err(&port->adapter->ccw_device->dev, - "Port ERP failed for port wwpn=0x%016Lx.\n", - port->wwpn); +static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) +{ + struct zfcp_port *port = erp_action->port; + int status = atomic_read(&port->status); + + switch (erp_action->step) { + case ZFCP_ERP_STEP_UNINITIALIZED: + zfcp_erp_port_strategy_clearstati(port); + if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) && + (status & ZFCP_STATUS_COMMON_OPEN)) + return zfcp_erp_port_forced_strategy_close(erp_action); + else + return ZFCP_ERP_FAILED; + + case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: + if (status & ZFCP_STATUS_PORT_PHYS_OPEN) + return ZFCP_ERP_SUCCEEDED; + } + return ZFCP_ERP_FAILED; } -/* - * function: zfcp_erp_unit_failed - * - * purpose: sets the unit to ERP_FAILED - * - */ -void -zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref) +static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) { - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); + int retval; - dev_err(&unit->port->adapter->ccw_device->dev, - "Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n", - unit->fcp_lun, unit->port->wwpn); + retval = zfcp_fsf_close_port(erp_action); + if (retval == -ENOMEM) + return ZFCP_ERP_NOMEM; + erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; + if (retval) + return ZFCP_ERP_FAILED; + return ZFCP_ERP_CONTINUES; } -/* - * function: zfcp_erp_strategy_check_target - * - * purpose: increments the erp action count on the device currently in - * recovery if the action failed or resets the count in case of - * success. If a maximum count is exceeded the device is marked - * as ERP_FAILED. - * The 'blocked' state of a target which has been recovered - * successfully is reset. - * - * returns: ZFCP_ERP_CONTINUES - action continues (not considered) - * ZFCP_ERP_SUCCEEDED - action finished successfully - * ZFCP_ERP_EXIT - action failed and will not continue - */ -static int -zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, int result) +static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) { - struct zfcp_adapter *adapter = erp_action->adapter; - struct zfcp_port *port = erp_action->port; - struct zfcp_unit *unit = erp_action->unit; + int retval; - switch (erp_action->action) { + retval = zfcp_fsf_open_port(erp_action); + if (retval == -ENOMEM) + return ZFCP_ERP_NOMEM; + erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; + if (retval) + return ZFCP_ERP_FAILED; + return ZFCP_ERP_CONTINUES; +} - case ZFCP_ERP_ACTION_REOPEN_UNIT: - result = zfcp_erp_strategy_check_unit(unit, result); - break; +static void zfcp_erp_port_strategy_open_ns_wake(struct zfcp_erp_action *ns_act) +{ + unsigned long flags; + struct zfcp_adapter *adapter = ns_act->adapter; + struct zfcp_erp_action *act, *tmp; + int status; - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - case ZFCP_ERP_ACTION_REOPEN_PORT: - result = zfcp_erp_strategy_check_port(port, result); - break; + read_lock_irqsave(&adapter->erp_lock, flags); + list_for_each_entry_safe(act, tmp, &adapter->erp_running_head, list) { + if (act->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) { + status = atomic_read(&adapter->nameserver_port->status); + if (status & ZFCP_STATUS_COMMON_ERP_FAILED) + zfcp_erp_port_failed(act->port, 27, NULL); + zfcp_erp_action_ready(act); + } + } + read_unlock_irqrestore(&adapter->erp_lock, flags); +} - case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - result = zfcp_erp_strategy_check_adapter(adapter, result); - break; +static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *act) +{ + int retval; + + switch (act->step) { + case ZFCP_ERP_STEP_UNINITIALIZED: + case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: + case ZFCP_ERP_STEP_PORT_CLOSING: + return zfcp_erp_port_strategy_open_port(act); + + case ZFCP_ERP_STEP_PORT_OPENING: + if (atomic_read(&act->port->status) & ZFCP_STATUS_COMMON_OPEN) + retval = ZFCP_ERP_SUCCEEDED; + else + retval = ZFCP_ERP_FAILED; + /* this is needed anyway */ + zfcp_erp_port_strategy_open_ns_wake(act); + return retval; + + default: + return ZFCP_ERP_FAILED; } +} - return result; +static int zfcp_erp_port_strategy_open_lookup(struct zfcp_erp_action *act) +{ + int retval; + + retval = zfcp_fc_ns_gid_pn_request(act); + if (retval == -ENOMEM) + return ZFCP_ERP_NOMEM; + act->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; + if (retval) + return ZFCP_ERP_FAILED; + return ZFCP_ERP_CONTINUES; } -static int -zfcp_erp_strategy_statechange(int action, - u32 status, - struct zfcp_adapter *adapter, - struct zfcp_port *port, - struct zfcp_unit *unit, int retval) +static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) { - switch (action) { + struct zfcp_adapter *adapter = act->adapter; + struct zfcp_port *port = act->port; - case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - if (zfcp_erp_strategy_statechange_detected(&adapter->status, - status)) { - zfcp_erp_adapter_reopen_internal(adapter, - ZFCP_STATUS_COMMON_ERP_FAILED, - 67, NULL); - retval = ZFCP_ERP_EXIT; + if (port->wwpn != adapter->peer_wwpn) { + dev_err(&adapter->ccw_device->dev, + "Failed to open port 0x%016Lx, " + "Peer WWPN 0x%016Lx does not " + "match.\n", port->wwpn, + adapter->peer_wwpn); + zfcp_erp_port_failed(port, 25, NULL); + return ZFCP_ERP_FAILED; + } + port->d_id = adapter->peer_d_id; + atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); + return zfcp_erp_port_strategy_open_port(act); +} + +static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) +{ + struct zfcp_adapter *adapter = act->adapter; + struct zfcp_port *port = act->port; + struct zfcp_port *ns_port = adapter->nameserver_port; + int p_status = atomic_read(&port->status); + + switch (act->step) { + case ZFCP_ERP_STEP_UNINITIALIZED: + case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: + case ZFCP_ERP_STEP_PORT_CLOSING: + if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) + return zfcp_erp_open_ptp_port(act); + if (!ns_port) { + dev_err(&adapter->ccw_device->dev, + "Nameserver port unavailable.\n"); + return ZFCP_ERP_FAILED; } - break; + if (!(atomic_read(&ns_port->status) & + ZFCP_STATUS_COMMON_UNBLOCKED)) { + /* nameserver port may live again */ + atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, + &ns_port->status); + if (zfcp_erp_port_reopen(ns_port, 0, 77, act) >= 0) { + act->step = ZFCP_ERP_STEP_NAMESERVER_OPEN; + return ZFCP_ERP_CONTINUES; + } + return ZFCP_ERP_FAILED; + } + /* else nameserver port is already open, fall through */ + case ZFCP_ERP_STEP_NAMESERVER_OPEN: + if (!(atomic_read(&ns_port->status) & ZFCP_STATUS_COMMON_OPEN)) + return ZFCP_ERP_FAILED; + return zfcp_erp_port_strategy_open_lookup(act); - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - case ZFCP_ERP_ACTION_REOPEN_PORT: - if (zfcp_erp_strategy_statechange_detected(&port->status, - status)) { - zfcp_erp_port_reopen_internal(port, - ZFCP_STATUS_COMMON_ERP_FAILED, - 68, NULL); - retval = ZFCP_ERP_EXIT; + case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: + if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { + if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) { + zfcp_erp_port_failed(port, 26, NULL); + return ZFCP_ERP_EXIT; + } + return ZFCP_ERP_FAILED; } + return zfcp_erp_port_strategy_open_port(act); + + case ZFCP_ERP_STEP_PORT_OPENING: + /* D_ID might have changed during open */ + if ((p_status & ZFCP_STATUS_COMMON_OPEN) && + (p_status & ZFCP_STATUS_PORT_DID_DID)) + return ZFCP_ERP_SUCCEEDED; + /* fall through otherwise */ + } + return ZFCP_ERP_FAILED; +} + +static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *act) +{ + if (atomic_read(&act->port->status) & (ZFCP_STATUS_PORT_WKA)) + return zfcp_erp_port_strategy_open_nameserver(act); + return zfcp_erp_port_strategy_open_common(act); +} + +static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) +{ + struct zfcp_port *port = erp_action->port; + + switch (erp_action->step) { + case ZFCP_ERP_STEP_UNINITIALIZED: + zfcp_erp_port_strategy_clearstati(port); + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) + return zfcp_erp_port_strategy_close(erp_action); break; - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (zfcp_erp_strategy_statechange_detected(&unit->status, - status)) { - zfcp_erp_unit_reopen_internal(unit, - ZFCP_STATUS_COMMON_ERP_FAILED, - 69, NULL); - retval = ZFCP_ERP_EXIT; - } + case ZFCP_ERP_STEP_PORT_CLOSING: + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) + return ZFCP_ERP_FAILED; break; } + if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) + return ZFCP_ERP_EXIT; + else + return zfcp_erp_port_strategy_open(erp_action); - return retval; + return ZFCP_ERP_FAILED; +} + +static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) +{ + atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | + ZFCP_STATUS_COMMON_CLOSING | + ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_UNIT_SHARED | + ZFCP_STATUS_UNIT_READONLY, + &unit->status); +} + +static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) +{ + int retval = zfcp_fsf_close_unit(erp_action); + if (retval == -ENOMEM) + return ZFCP_ERP_NOMEM; + erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; + if (retval) + return ZFCP_ERP_FAILED; + return ZFCP_ERP_CONTINUES; +} + +static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) +{ + int retval = zfcp_fsf_open_unit(erp_action); + if (retval == -ENOMEM) + return ZFCP_ERP_NOMEM; + erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; + if (retval) + return ZFCP_ERP_FAILED; + return ZFCP_ERP_CONTINUES; } -static int -zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) +static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) { - return - /* take it online */ - (atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, target_status) && - (ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)) || - /* take it offline */ - (!atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, target_status) && - !(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)); + struct zfcp_unit *unit = erp_action->unit; + + switch (erp_action->step) { + case ZFCP_ERP_STEP_UNINITIALIZED: + zfcp_erp_unit_strategy_clearstati(unit); + if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + return zfcp_erp_unit_strategy_close(erp_action); + /* already closed, fall through */ + case ZFCP_ERP_STEP_UNIT_CLOSING: + if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + return ZFCP_ERP_FAILED; + if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) + return ZFCP_ERP_EXIT; + return zfcp_erp_unit_strategy_open(erp_action); + + case ZFCP_ERP_STEP_UNIT_OPENING: + if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + return ZFCP_ERP_SUCCEEDED; + } + return ZFCP_ERP_FAILED; } -static int -zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) +static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) { switch (result) { case ZFCP_ERP_SUCCEEDED : @@ -1177,29 +1068,25 @@ zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) zfcp_erp_unit_failed(unit, 21, NULL); break; - case ZFCP_ERP_EXIT : - /* nothing */ - break; } - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { - zfcp_erp_unit_block(unit, 0); /* for ZFCP_ERP_SUCCEEDED */ + if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + zfcp_erp_unit_block(unit, 0); result = ZFCP_ERP_EXIT; } - return result; } -static int -zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) +static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) { switch (result) { case ZFCP_ERP_SUCCEEDED : atomic_set(&port->erp_counter, 0); zfcp_erp_port_unblock(port); break; + case ZFCP_ERP_FAILED : - if (atomic_test_mask(ZFCP_STATUS_COMMON_NOESC, &port->status)) { + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { zfcp_erp_port_block(port, 0); result = ZFCP_ERP_EXIT; } @@ -1207,1402 +1094,588 @@ zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) zfcp_erp_port_failed(port, 22, NULL); break; - case ZFCP_ERP_EXIT : - /* nothing */ - break; } - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { - zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */ + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + zfcp_erp_port_block(port, 0); result = ZFCP_ERP_EXIT; } - return result; } -static int -zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result) +static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, + int result) { switch (result) { case ZFCP_ERP_SUCCEEDED : atomic_set(&adapter->erp_counter, 0); zfcp_erp_adapter_unblock(adapter); break; + case ZFCP_ERP_FAILED : atomic_inc(&adapter->erp_counter); if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) zfcp_erp_adapter_failed(adapter, 23, NULL); break; - case ZFCP_ERP_EXIT : - /* nothing */ - break; } - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { - zfcp_erp_adapter_block(adapter, 0); /* for ZFCP_ERP_SUCCEEDED */ + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + zfcp_erp_adapter_block(adapter, 0); result = ZFCP_ERP_EXIT; } - return result; } -struct zfcp_erp_add_work { - struct zfcp_unit *unit; - struct work_struct work; -}; - -/** - * zfcp_erp_scsi_scan - * @data: pointer to a struct zfcp_erp_add_work - * - * Registers a logical unit with the SCSI stack. - */ -static void zfcp_erp_scsi_scan(struct work_struct *work) +static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, + int result) { - struct zfcp_erp_add_work *p = - container_of(work, struct zfcp_erp_add_work, work); - struct zfcp_unit *unit = p->unit; - struct fc_rport *rport = unit->port->rport; - scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, - unit->scsi_lun, 0); - atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); - zfcp_unit_put(unit); - kfree(p); + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_port *port = erp_action->port; + struct zfcp_unit *unit = erp_action->unit; + + switch (erp_action->action) { + + case ZFCP_ERP_ACTION_REOPEN_UNIT: + result = zfcp_erp_strategy_check_unit(unit, result); + break; + + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + case ZFCP_ERP_ACTION_REOPEN_PORT: + result = zfcp_erp_strategy_check_port(port, result); + break; + + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + result = zfcp_erp_strategy_check_adapter(adapter, result); + break; + } + return result; } -/** - * zfcp_erp_schedule_work - * @unit: pointer to unit which should be registered with SCSI stack - * - * Schedules work which registers a unit with the SCSI stack - */ -static void -zfcp_erp_schedule_work(struct zfcp_unit *unit) +static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) { - struct zfcp_erp_add_work *p; + int status = atomic_read(target_status); - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) { - dev_err(&unit->port->adapter->ccw_device->dev, - "Out of resources. Could not register unit 0x%016Lx " - "on port 0x%016Lx with SCSI stack.\n", - unit->fcp_lun, unit->port->wwpn); - return; - } + if ((status & ZFCP_STATUS_COMMON_RUNNING) && + (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) + return 1; /* take it online */ - zfcp_unit_get(unit); - atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); - INIT_WORK(&p->work, zfcp_erp_scsi_scan); - p->unit = unit; - schedule_work(&p->work); + if (!(status & ZFCP_STATUS_COMMON_RUNNING) && + !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) + return 1; /* take it offline */ + + return 0; } -/* - * function: - * - * purpose: remaining things in good cases, - * escalation in bad cases - * - * returns: - */ -static int -zfcp_erp_strategy_followup_actions(int action, - struct zfcp_adapter *adapter, - struct zfcp_port *port, - struct zfcp_unit *unit, int status) +static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) { - /* initiate follow-up actions depending on success of finished action */ - switch (action) { + int action = act->action; + struct zfcp_adapter *adapter = act->adapter; + struct zfcp_port *port = act->port; + struct zfcp_unit *unit = act->unit; + u32 erp_status = act->status; + switch (action) { case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - if (status == ZFCP_ERP_SUCCEEDED) - zfcp_erp_port_reopen_all_internal(adapter, 0, 70, NULL); - else - zfcp_erp_adapter_reopen_internal(adapter, 0, 71, NULL); + if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { + _zfcp_erp_adapter_reopen(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED, + 67, NULL); + return ZFCP_ERP_EXIT; + } break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - if (status == ZFCP_ERP_SUCCEEDED) - zfcp_erp_port_reopen_internal(port, 0, 72, NULL); - else - zfcp_erp_adapter_reopen_internal(adapter, 0, 73, NULL); - break; - case ZFCP_ERP_ACTION_REOPEN_PORT: - if (status == ZFCP_ERP_SUCCEEDED) - zfcp_erp_unit_reopen_all_internal(port, 0, 74, NULL); - else - zfcp_erp_port_forced_reopen_internal(port, 0, 75, NULL); + if (zfcp_erp_strat_change_det(&port->status, erp_status)) { + _zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED, + 68, NULL); + return ZFCP_ERP_EXIT; + } break; case ZFCP_ERP_ACTION_REOPEN_UNIT: - /* Nothing to do if status == ZFCP_ERP_SUCCEEDED */ - if (status != ZFCP_ERP_SUCCEEDED) - zfcp_erp_port_reopen_internal(unit->port, 0, 76, NULL); + if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { + _zfcp_erp_unit_reopen(unit, + ZFCP_STATUS_COMMON_ERP_FAILED, + 69, NULL); + return ZFCP_ERP_EXIT; + } break; } - - return 0; + return ret; } -static int -zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter) +static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) { - unsigned long flags; + struct zfcp_adapter *adapter = erp_action->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - read_lock(&adapter->erp_lock); - if (list_empty(&adapter->erp_ready_head) && - list_empty(&adapter->erp_running_head)) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, - &adapter->status); - wake_up(&adapter->erp_done_wqh); + adapter->erp_total_count--; + if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { + adapter->erp_low_mem_count--; + erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; } - read_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - return 0; -} + list_del(&erp_action->list); + zfcp_rec_dbf_event_action(144, erp_action); -/** - * zfcp_erp_wait - wait for completion of error recovery on an adapter - * @adapter: adapter for which to wait for completion of its error recovery - * Return: 0 - */ -int -zfcp_erp_wait(struct zfcp_adapter *adapter) -{ - int retval = 0; + switch (erp_action->action) { + case ZFCP_ERP_ACTION_REOPEN_UNIT: + atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + &erp_action->unit->status); + break; - wait_event(adapter->erp_done_wqh, - !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, - &adapter->status)); + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + case ZFCP_ERP_ACTION_REOPEN_PORT: + atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + &erp_action->port->status); + break; - return retval; + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + &erp_action->adapter->status); + break; + } } -void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id, - void *ref, u32 mask, int set_or_clear) -{ - struct zfcp_port *port; - u32 changed, common_mask = mask & ZFCP_COMMON_FLAGS; - - if (set_or_clear == ZFCP_SET) { - changed = atomic_test_and_set_mask(mask, &adapter->status); - } else { - changed = atomic_test_and_clear_mask(mask, &adapter->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) - atomic_set(&adapter->erp_counter, 0); - } - if (changed) - zfcp_rec_dbf_event_adapter(id, ref, adapter); +struct zfcp_erp_add_work { + struct zfcp_unit *unit; + struct work_struct work; +}; - /* Deal with all underlying devices, only pass common_mask */ - if (common_mask) - list_for_each_entry(port, &adapter->port_list_head, list) - zfcp_erp_modify_port_status(port, id, ref, common_mask, - set_or_clear); +static void zfcp_erp_scsi_scan(struct work_struct *work) +{ + struct zfcp_erp_add_work *p = + container_of(work, struct zfcp_erp_add_work, work); + struct zfcp_unit *unit = p->unit; + struct fc_rport *rport = unit->port->rport; + scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, + unit->scsi_lun, 0); + atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); + zfcp_unit_put(unit); + kfree(p); } -/* - * function: zfcp_erp_modify_port_status - * - * purpose: sets the port and all underlying devices to ERP_FAILED - * - */ -void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref, - u32 mask, int set_or_clear) +static void zfcp_erp_schedule_work(struct zfcp_unit *unit) { - struct zfcp_unit *unit; - u32 changed, common_mask = mask & ZFCP_COMMON_FLAGS; + struct zfcp_erp_add_work *p; - if (set_or_clear == ZFCP_SET) { - changed = atomic_test_and_set_mask(mask, &port->status); - } else { - changed = atomic_test_and_clear_mask(mask, &port->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) - atomic_set(&port->erp_counter, 0); + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) { + dev_err(&unit->port->adapter->ccw_device->dev, + "Out of resources. Could not register unit " + "0x%016Lx on port 0x%016Lx with SCSI stack.\n", + unit->fcp_lun, unit->port->wwpn); + return; } - if (changed) - zfcp_rec_dbf_event_port(id, ref, port); - /* Modify status of all underlying devices, only pass common mask */ - if (common_mask) - list_for_each_entry(unit, &port->unit_list_head, list) - zfcp_erp_modify_unit_status(unit, id, ref, common_mask, - set_or_clear); + zfcp_unit_get(unit); + atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); + INIT_WORK(&p->work, zfcp_erp_scsi_scan); + p->unit = unit; + schedule_work(&p->work); } -/* - * function: zfcp_erp_modify_unit_status - * - * purpose: sets the unit to ERP_FAILED - * - */ -void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref, - u32 mask, int set_or_clear) +static void zfcp_erp_rport_register(struct zfcp_port *port) { - u32 changed; - - if (set_or_clear == ZFCP_SET) { - changed = atomic_test_and_set_mask(mask, &unit->status); - } else { - changed = atomic_test_and_clear_mask(mask, &unit->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { - atomic_set(&unit->erp_counter, 0); - } + struct fc_rport_identifiers ids; + ids.node_name = port->wwnn; + ids.port_name = port->wwpn; + ids.port_id = port->d_id; + ids.roles = FC_RPORT_ROLE_FCP_TARGET; + port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); + if (!port->rport) { + dev_err(&port->adapter->ccw_device->dev, + "Failed registration of rport " + "0x%016Lx.\n", port->wwpn); + return; } - if (changed) - zfcp_rec_dbf_event_unit(id, ref, unit); -} - -/* - * function: - * - * purpose: Wrappper for zfcp_erp_port_reopen_all_internal - * used to ensure the correct locking - * - * returns: 0 - initiated action successfully - * <0 - failed to initiate action - */ -int zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, int clear_mask, - u8 id, void *ref) -{ - int retval; - unsigned long flags; - - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); - retval = zfcp_erp_port_reopen_all_internal(adapter, clear_mask, id, - ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - return retval; + scsi_target_unblock(&port->rport->dev); + port->rport->maxframe_size = port->maxframe_size; + port->rport->supported_classes = port->supported_classes; } -static int zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, - int clear_mask, u8 id, void *ref) +static void zfcp_erp_rports_del(struct zfcp_adapter *adapter) { - int retval = 0; struct zfcp_port *port; - list_for_each_entry(port, &adapter->port_list_head, list) - if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) - zfcp_erp_port_reopen_internal(port, clear_mask, id, - ref); - - return retval; + if (port->rport && !(atomic_read(&port->status) & + ZFCP_STATUS_PORT_WKA)) { + fc_remote_port_delete(port->rport); + port->rport = NULL; + } } -/* - * function: - * - * purpose: - * - * returns: FIXME - */ -static int zfcp_erp_unit_reopen_all_internal(struct zfcp_port *port, - int clear_mask, u8 id, void *ref) +static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) { - int retval = 0; - struct zfcp_unit *unit; + struct zfcp_adapter *adapter = act->adapter; + struct zfcp_port *port = act->port; + struct zfcp_unit *unit = act->unit; - list_for_each_entry(unit, &port->unit_list_head, list) - zfcp_erp_unit_reopen_internal(unit, clear_mask, id, ref); + switch (act->action) { + case ZFCP_ERP_ACTION_REOPEN_UNIT: + if ((result == ZFCP_ERP_SUCCEEDED) && + !unit->device && port->rport) { + atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, + &unit->status); + if (!(atomic_read(&unit->status) & + ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) + zfcp_erp_schedule_work(unit); + } + zfcp_unit_put(unit); + break; - return retval; + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + case ZFCP_ERP_ACTION_REOPEN_PORT: + if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) { + zfcp_port_put(port); + return; + } + if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport) + zfcp_erp_rport_register(port); + if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { + fc_remote_port_delete(port->rport); + port->rport = NULL; + } + zfcp_port_put(port); + break; + + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + if (result != ZFCP_ERP_SUCCEEDED) + zfcp_erp_rports_del(adapter); + zfcp_adapter_put(adapter); + break; + } } -/* - * function: - * - * purpose: this routine executes the 'Reopen Adapter' action - * (the entire action is processed synchronously, since - * there are no actions which might be run concurrently - * per definition) - * - * returns: ZFCP_ERP_SUCCEEDED - action finished successfully - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) +static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) { - int retval; - - retval = zfcp_erp_adapter_strategy_close(erp_action); - if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) - retval = ZFCP_ERP_EXIT; - else - retval = zfcp_erp_adapter_strategy_open(erp_action); - - if (retval == ZFCP_ERP_FAILED) - ssleep(ZFCP_TYPE2_RECOVERY_TIME); - - return retval; + switch (erp_action->action) { + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + return zfcp_erp_adapter_strategy(erp_action); + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + return zfcp_erp_port_forced_strategy(erp_action); + case ZFCP_ERP_ACTION_REOPEN_PORT: + return zfcp_erp_port_strategy(erp_action); + case ZFCP_ERP_ACTION_REOPEN_UNIT: + return zfcp_erp_unit_strategy(erp_action); + } + return ZFCP_ERP_FAILED; } -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_SUCCEEDED - action finished successfully - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *erp_action) +static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) { int retval; + struct zfcp_adapter *adapter = erp_action->adapter; + unsigned long flags; - atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, - &erp_action->adapter->status); - retval = zfcp_erp_adapter_strategy_generic(erp_action, 1); - atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, - &erp_action->adapter->status); + read_lock_irqsave(&zfcp_data.config_lock, flags); + write_lock(&adapter->erp_lock); - return retval; -} + zfcp_erp_strategy_check_fsfreq(erp_action); -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_SUCCEEDED - action finished successfully - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *erp_action) -{ - int retval; - - atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, - &erp_action->adapter->status); - retval = zfcp_erp_adapter_strategy_generic(erp_action, 0); - atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, - &erp_action->adapter->status); - - return retval; -} - -/* - * function: zfcp_register_adapter - * - * purpose: allocate the irq associated with this devno and register - * the FSF adapter with the SCSI stack - * - * returns: - */ -static int -zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) -{ - int retval = ZFCP_ERP_SUCCEEDED; - - if (close) - goto close_only; - - retval = zfcp_erp_adapter_strategy_open_qdio(erp_action); - if (retval != ZFCP_ERP_SUCCEEDED) - goto failed_qdio; - - retval = zfcp_erp_adapter_strategy_open_fsf(erp_action); - if (retval != ZFCP_ERP_SUCCEEDED) - goto failed_openfcp; - - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &erp_action->adapter->status); - schedule_work(&erp_action->adapter->scan_work); - goto out; - - close_only: - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, - &erp_action->adapter->status); - - failed_openfcp: - zfcp_close_fsf(erp_action->adapter); - failed_qdio: - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | - ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | - ZFCP_STATUS_ADAPTER_XPORT_OK, - &erp_action->adapter->status); - out: - return retval; -} - -/* - * function: zfcp_qdio_init - * - * purpose: setup QDIO operation for specified adapter - * - * returns: 0 - successful setup - * !0 - failed setup - */ -static int -zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) -{ - struct zfcp_adapter *adapter = erp_action->adapter; - - if (zfcp_qdio_open(adapter)) - return ZFCP_ERP_FAILED; - - /* initialize waitqueue used to wait for free SBALs in requests queue */ - init_waitqueue_head(&adapter->request_wq); - - /* ok, we did it - skip all cleanups for different failures */ - atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); - return ZFCP_ERP_SUCCEEDED; -} - - -static int -zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) -{ - int retval; - - retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); - if (retval == ZFCP_ERP_FAILED) - return ZFCP_ERP_FAILED; - - retval = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); - if (retval == ZFCP_ERP_FAILED) - return ZFCP_ERP_FAILED; - - return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); -} - -static void zfcp_erp_open_ptp_port(struct zfcp_adapter *adapter) -{ - struct zfcp_port *port; - port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, - adapter->peer_d_id); - if (IS_ERR(port)) /* error or port already attached */ - return; - zfcp_erp_port_reopen_internal(port, 0, 150, NULL); -} - -static int -zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) -{ - int retries; - int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP; - struct zfcp_adapter *adapter = erp_action->adapter; - - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); - - for (retries = ZFCP_EXCHANGE_CONFIG_DATA_RETRIES; retries; retries--) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, - &adapter->status); - write_lock_irq(&adapter->erp_lock); - zfcp_erp_action_to_running(erp_action); - write_unlock_irq(&adapter->erp_lock); - if (zfcp_fsf_exchange_config_data(erp_action)) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, - &adapter->status); - return ZFCP_ERP_FAILED; - } - - /* - * Why this works: - * Both the normal completion handler as well as the timeout - * handler will do an 'up' when the 'exchange config data' - * request completes or times out. Thus, the signal to go on - * won't be lost utilizing this semaphore. - * Furthermore, this 'adapter_reopen' action is - * guaranteed to be the only action being there (highest action - * which prevents other actions from being created). - * Resulting from that, the wake signal recognized here - * _must_ be the one belonging to the 'exchange config - * data' request. - */ - zfcp_rec_dbf_event_thread_lock(6, adapter); - down(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock(7, adapter); - if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) - break; - - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, - &adapter->status)) - break; - - /* sleep a little bit before retry */ - ssleep(sleep); - sleep *= 2; + if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { + zfcp_erp_action_dequeue(erp_action); + retval = ZFCP_ERP_DISMISSED; + goto unlock; } - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, - &adapter->status); - - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, - &adapter->status)) - return ZFCP_ERP_FAILED; - - if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) - zfcp_erp_open_ptp_port(adapter); - - return ZFCP_ERP_SUCCEEDED; -} - -static int -zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) -{ - int ret; - struct zfcp_adapter *adapter; - - adapter = erp_action->adapter; - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); - - write_lock_irq(&adapter->erp_lock); zfcp_erp_action_to_running(erp_action); - write_unlock_irq(&adapter->erp_lock); - - ret = zfcp_fsf_exchange_port_data(erp_action); - if (ret == -EOPNOTSUPP) { - return ZFCP_ERP_SUCCEEDED; - } else if (ret) { - return ZFCP_ERP_FAILED; - } - - ret = ZFCP_ERP_SUCCEEDED; - zfcp_rec_dbf_event_thread_lock(8, adapter); - down(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock(9, adapter); - if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) - ret = ZFCP_ERP_FAILED; - - return ret; -} - -static int -zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action - *erp_action) -{ - struct zfcp_adapter *adapter = erp_action->adapter; - - atomic_set(&adapter->stat_miss, 16); - return zfcp_status_read_refill(adapter); -} - -/* - * function: - * - * purpose: this routine executes the 'Reopen Physical Port' action - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_SUCCEEDED - action finished successfully - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) -{ - int retval = ZFCP_ERP_FAILED; - struct zfcp_port *port = erp_action->port; - - switch (erp_action->step) { - - /* - * FIXME: - * the ULP spec. begs for waiting for oustanding commands - */ - case ZFCP_ERP_STEP_UNINITIALIZED: - zfcp_erp_port_strategy_clearstati(port); - /* - * it would be sufficient to test only the normal open flag - * since the phys. open flag cannot be set if the normal - * open flag is unset - however, this is for readabilty ... - */ - if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN | - ZFCP_STATUS_COMMON_OPEN), - &port->status)) { - retval = - zfcp_erp_port_forced_strategy_close(erp_action); - } else - retval = ZFCP_ERP_FAILED; - break; - - case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: - if (atomic_test_mask(ZFCP_STATUS_PORT_PHYS_OPEN, - &port->status)) { - retval = ZFCP_ERP_FAILED; - } else - retval = ZFCP_ERP_SUCCEEDED; - break; - } - - return retval; -} - -/* - * function: - * - * purpose: this routine executes the 'Reopen Port' action - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_SUCCEEDED - action finished successfully - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) -{ - int retval = ZFCP_ERP_FAILED; - struct zfcp_port *port = erp_action->port; - - switch (erp_action->step) { - - /* - * FIXME: - * the ULP spec. begs for waiting for oustanding commands - */ - case ZFCP_ERP_STEP_UNINITIALIZED: - zfcp_erp_port_strategy_clearstati(port); - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { - retval = zfcp_erp_port_strategy_close(erp_action); - goto out; - } /* else it's already closed, open it */ - break; - - case ZFCP_ERP_STEP_PORT_CLOSING: - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { - retval = ZFCP_ERP_FAILED; - goto out; - } /* else it's closed now, open it */ - break; - } - if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) - retval = ZFCP_ERP_EXIT; - else - retval = zfcp_erp_port_strategy_open(erp_action); - out: - return retval; -} - -static int -zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action) -{ - int retval; - - if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, - &erp_action->port->status)) - retval = zfcp_erp_port_strategy_open_nameserver(erp_action); - else - retval = zfcp_erp_port_strategy_open_common(erp_action); - - return retval; -} - -static int -zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) -{ - int retval = 0; - struct zfcp_adapter *adapter = erp_action->adapter; - struct zfcp_port *port = erp_action->port; - - switch (erp_action->step) { + /* no lock to allow for blocking operations */ + write_unlock(&adapter->erp_lock); + read_unlock_irqrestore(&zfcp_data.config_lock, flags); + retval = zfcp_erp_strategy_do_action(erp_action); + read_lock_irqsave(&zfcp_data.config_lock, flags); + write_lock(&adapter->erp_lock); - case ZFCP_ERP_STEP_UNINITIALIZED: - case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: - case ZFCP_ERP_STEP_PORT_CLOSING: - if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) { - if (port->wwpn != adapter->peer_wwpn) { - dev_err(&adapter->ccw_device->dev, - "Failed to open port 0x%016Lx, " - "Peer WWPN 0x%016Lx does not match.\n", - port->wwpn, adapter->peer_wwpn); - zfcp_erp_port_failed(port, 25, NULL); - retval = ZFCP_ERP_FAILED; - break; - } - port->d_id = adapter->peer_d_id; - atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); - retval = zfcp_erp_port_strategy_open_port(erp_action); - break; - } + if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) + retval = ZFCP_ERP_CONTINUES; - if (!adapter->nameserver_port) { - dev_err(&adapter->ccw_device->dev, - "Nameserver port unavailable.\n"); - retval = ZFCP_ERP_FAILED; - break; - } - if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, - &adapter->nameserver_port->status)) { - /* nameserver port may live again */ - atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, - &adapter->nameserver_port->status); - if (zfcp_erp_port_reopen(adapter->nameserver_port, 0, - 77, erp_action) >= 0) { - erp_action->step = - ZFCP_ERP_STEP_NAMESERVER_OPEN; - retval = ZFCP_ERP_CONTINUES; - } else - retval = ZFCP_ERP_FAILED; - break; + switch (retval) { + case ZFCP_ERP_NOMEM: + if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { + ++adapter->erp_low_mem_count; + erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; } - /* else nameserver port is already open, fall through */ - case ZFCP_ERP_STEP_NAMESERVER_OPEN: - if (!atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, - &adapter->nameserver_port->status)) - retval = ZFCP_ERP_FAILED; - else - retval = zfcp_erp_port_strategy_open_common_lookup - (erp_action); - break; - - case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: - if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) { - if (atomic_test_mask - (ZFCP_STATUS_PORT_INVALID_WWPN, &port->status)) { - zfcp_erp_port_failed(port, 26, NULL); - retval = ZFCP_ERP_EXIT; - } else - retval = ZFCP_ERP_FAILED; - } else - retval = zfcp_erp_port_strategy_open_port(erp_action); - break; - - case ZFCP_ERP_STEP_PORT_OPENING: - /* D_ID might have changed during open */ - if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN | - ZFCP_STATUS_PORT_DID_DID), - &port->status)) - retval = ZFCP_ERP_SUCCEEDED; - else - retval = ZFCP_ERP_FAILED; - break; - - default: - /* unknown erp step */ - retval = ZFCP_ERP_FAILED; - } - - return retval; -} - -static int -zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action) -{ - int retval; - struct zfcp_port *port = erp_action->port; - - switch (erp_action->step) { - - case ZFCP_ERP_STEP_UNINITIALIZED: - case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: - case ZFCP_ERP_STEP_PORT_CLOSING: - retval = zfcp_erp_port_strategy_open_port(erp_action); - break; - - case ZFCP_ERP_STEP_PORT_OPENING: - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) - retval = ZFCP_ERP_SUCCEEDED; - else - retval = ZFCP_ERP_FAILED; - /* this is needed anyway (dont care for retval of wakeup) */ - zfcp_erp_port_strategy_open_nameserver_wakeup(erp_action); - break; - - default: - /* unknown erp step */ - retval = ZFCP_ERP_FAILED; - } - - return retval; -} - -/* - * function: - * - * purpose: makes the erp thread continue with reopen (physical) port - * actions which have been paused until the name server port - * is opened (or failed) - * - * returns: 0 (a kind of void retval, its not used) - */ -static int -zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action - *ns_erp_action) -{ - int retval = 0; - unsigned long flags; - struct zfcp_adapter *adapter = ns_erp_action->adapter; - struct zfcp_erp_action *erp_action, *tmp; - - read_lock_irqsave(&adapter->erp_lock, flags); - list_for_each_entry_safe(erp_action, tmp, &adapter->erp_running_head, - list) { - if (erp_action->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) { - if (atomic_test_mask( - ZFCP_STATUS_COMMON_ERP_FAILED, - &adapter->nameserver_port->status)) - zfcp_erp_port_failed(erp_action->port, 27, - NULL); - zfcp_erp_action_ready(erp_action); + if (adapter->erp_total_count == adapter->erp_low_mem_count) + _zfcp_erp_adapter_reopen(adapter, 0, 66, NULL); + else { + zfcp_erp_strategy_memwait(erp_action); + retval = ZFCP_ERP_CONTINUES; } - } - read_unlock_irqrestore(&adapter->erp_lock, flags); - - return retval; -} - -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *erp_action) -{ - int retval; - - retval = zfcp_fsf_close_physical_port(erp_action); - if (retval == -ENOMEM) { - retval = ZFCP_ERP_NOMEM; - goto out; - } - erp_action->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; - if (retval != 0) { - /* could not send 'open', fail */ - retval = ZFCP_ERP_FAILED; - goto out; - } - retval = ZFCP_ERP_CONTINUES; - out: - return retval; -} - -static int -zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) -{ - int retval = 0; - - atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | - ZFCP_STATUS_COMMON_CLOSING | - ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_PORT_DID_DID | - ZFCP_STATUS_PORT_PHYS_CLOSING | - ZFCP_STATUS_PORT_INVALID_WWPN, - &port->status); - return retval; -} - -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) -{ - int retval; - - retval = zfcp_fsf_close_port(erp_action); - if (retval == -ENOMEM) { - retval = ZFCP_ERP_NOMEM; - goto out; - } - erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; - if (retval != 0) { - /* could not send 'close', fail */ - retval = ZFCP_ERP_FAILED; - goto out; - } - retval = ZFCP_ERP_CONTINUES; - out: - return retval; -} - -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) -{ - int retval; - - retval = zfcp_fsf_open_port(erp_action); - if (retval == -ENOMEM) { - retval = ZFCP_ERP_NOMEM; - goto out; - } - erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; - if (retval != 0) { - /* could not send 'open', fail */ - retval = ZFCP_ERP_FAILED; - goto out; - } - retval = ZFCP_ERP_CONTINUES; - out: - return retval; -} - -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action) -{ - int retval; - - retval = zfcp_fc_ns_gid_pn_request(erp_action); - if (retval == -ENOMEM) { - retval = ZFCP_ERP_NOMEM; - goto out; - } - erp_action->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; - if (retval != 0) { - /* could not send nameserver request, fail */ - retval = ZFCP_ERP_FAILED; - goto out; - } - retval = ZFCP_ERP_CONTINUES; - out: - return retval; -} - -/* - * function: - * - * purpose: this routine executes the 'Reopen Unit' action - * currently no retries - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_SUCCEEDED - action finished successfully - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) -{ - int retval = ZFCP_ERP_FAILED; - struct zfcp_unit *unit = erp_action->unit; - - switch (erp_action->step) { + goto unlock; - /* - * FIXME: - * the ULP spec. begs for waiting for oustanding commands - */ - case ZFCP_ERP_STEP_UNINITIALIZED: - zfcp_erp_unit_strategy_clearstati(unit); - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { - retval = zfcp_erp_unit_strategy_close(erp_action); - break; + case ZFCP_ERP_CONTINUES: + if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { + --adapter->erp_low_mem_count; + erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; } - /* else it's already closed, fall through */ - case ZFCP_ERP_STEP_UNIT_CLOSING: - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) - retval = ZFCP_ERP_FAILED; - else - if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) - retval = ZFCP_ERP_EXIT; - else - retval = - zfcp_erp_unit_strategy_open(erp_action); - break; - - case ZFCP_ERP_STEP_UNIT_OPENING: - if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) - retval = ZFCP_ERP_SUCCEEDED; - else - retval = ZFCP_ERP_FAILED; - break; + goto unlock; } - return retval; -} - -static int -zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) -{ - int retval = 0; - - atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | - ZFCP_STATUS_COMMON_CLOSING | - ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_UNIT_SHARED | - ZFCP_STATUS_UNIT_READONLY, - &unit->status); - - return retval; -} - -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) -{ - int retval; - - retval = zfcp_fsf_close_unit(erp_action); - if (retval == -ENOMEM) { - retval = ZFCP_ERP_NOMEM; - goto out; - } - erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; - if (retval != 0) { - /* could not send 'close', fail */ - retval = ZFCP_ERP_FAILED; - goto out; - } - retval = ZFCP_ERP_CONTINUES; + retval = zfcp_erp_strategy_check_target(erp_action, retval); + zfcp_erp_action_dequeue(erp_action); + retval = zfcp_erp_strategy_statechange(erp_action, retval); + if (retval == ZFCP_ERP_EXIT) + goto unlock; + zfcp_erp_strategy_followup_actions(erp_action); - out: - return retval; -} + unlock: + write_unlock(&adapter->erp_lock); + read_unlock_irqrestore(&zfcp_data.config_lock, flags); -/* - * function: - * - * purpose: - * - * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) - * ZFCP_ERP_FAILED - action finished unsuccessfully - */ -static int -zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) -{ - int retval; + if (retval != ZFCP_ERP_CONTINUES) + zfcp_erp_action_cleanup(erp_action, retval); - retval = zfcp_fsf_open_unit(erp_action); - if (retval == -ENOMEM) { - retval = ZFCP_ERP_NOMEM; - goto out; - } - erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; - if (retval != 0) { - /* could not send 'open', fail */ - retval = ZFCP_ERP_FAILED; - goto out; - } - retval = ZFCP_ERP_CONTINUES; - out: return retval; } -void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req) -{ - BUG_ON(!fsf_req->erp_action); - fsf_req->timer.function = zfcp_erp_timeout_handler; - fsf_req->timer.data = (unsigned long) fsf_req->erp_action; - fsf_req->timer.expires = jiffies + ZFCP_ERP_FSFREQ_TIMEOUT; - add_timer(&fsf_req->timer); -} - -/* - * function: - * - * purpose: enqueue the specified error recovery action, if needed - * - * returns: - */ -static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, - struct zfcp_port *port, - struct zfcp_unit *unit, u8 id, void *ref) +static int zfcp_erp_thread(void *data) { - int retval = 1, need = want; - struct zfcp_erp_action *erp_action = NULL; - u32 status = 0; - - /* - * We need some rules here which check whether we really need - * this action or whether we should just drop it. - * E.g. if there is a unfinished 'Reopen Port' request then we drop a - * 'Reopen Unit' request for an associated unit since we can't - * satisfy this request now. A 'Reopen Port' action will trigger - * 'Reopen Unit' actions when it completes. - * Thus, there are only actions in the queue which can immediately be - * executed. This makes the processing of the action queue more - * efficient. - */ - - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, - &adapter->status)) - return -EIO; + struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; + struct list_head *next; + struct zfcp_erp_action *act; + unsigned long flags; - /* check whether we really need this */ - switch (want) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) { - goto out; - } - if (!atomic_test_mask - (ZFCP_STATUS_COMMON_RUNNING, &port->status) || - atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { - goto out; - } - if (!atomic_test_mask - (ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) - need = ZFCP_ERP_ACTION_REOPEN_PORT; - /* fall through !!! */ + daemonize("zfcperp%s", adapter->ccw_device->dev.bus_id); + /* Block all signals */ + siginitsetinv(¤t->blocked, 0); + atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); + wake_up(&adapter->erp_thread_wqh); - case ZFCP_ERP_ACTION_REOPEN_PORT: - if (atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) { - goto out; - } - /* fall through !!! */ + while (!(atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { + write_lock_irqsave(&adapter->erp_lock, flags); + next = adapter->erp_ready_head.next; + write_unlock_irqrestore(&adapter->erp_lock, flags); - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, - &port->status)) - goto out; - if (!atomic_test_mask - (ZFCP_STATUS_COMMON_RUNNING, &adapter->status) || - atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { - goto out; - } - if (!atomic_test_mask - (ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) - need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; - /* fall through !!! */ + if (next != &adapter->erp_ready_head) { + act = list_entry(next, struct zfcp_erp_action, list); - case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - if (atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) { - goto out; + /* there is more to come after dismission, no notify */ + if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) + zfcp_erp_wakeup(adapter); } - break; - default: - /* unknown erp action */ - goto out; + zfcp_rec_dbf_event_thread(4, adapter); + down_interruptible(&adapter->erp_ready_sem); + zfcp_rec_dbf_event_thread(5, adapter); } - /* mark adapter to have some error recovery pending */ - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); - - /* setup error recovery action */ - switch (need) { + atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); + wake_up(&adapter->erp_thread_wqh); - case ZFCP_ERP_ACTION_REOPEN_UNIT: - zfcp_unit_get(unit); - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); - erp_action = &unit->erp_action; - if (!atomic_test_mask - (ZFCP_STATUS_COMMON_RUNNING, &unit->status)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; - break; + return 0; +} - case ZFCP_ERP_ACTION_REOPEN_PORT: - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - zfcp_port_get(port); - zfcp_erp_action_dismiss_port(port); - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); - erp_action = &port->erp_action; - if (!atomic_test_mask - (ZFCP_STATUS_COMMON_RUNNING, &port->status)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; - break; +/** + * zfcp_erp_thread_setup - Start ERP thread for adapter + * @adapter: Adapter to start the ERP thread for + * + * Returns 0 on success or error code from kernel_thread() + */ +int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) +{ + int retval; - case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - zfcp_adapter_get(adapter); - zfcp_erp_action_dismiss_adapter(adapter); - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); - erp_action = &adapter->erp_action; - if (!atomic_test_mask - (ZFCP_STATUS_COMMON_RUNNING, &adapter->status)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; - break; + atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); + retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); + if (retval < 0) { + dev_err(&adapter->ccw_device->dev, + "Creation of ERP thread failed.\n"); + return retval; } + wait_event(adapter->erp_thread_wqh, + atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); + return 0; +} - memset(erp_action, 0, sizeof (struct zfcp_erp_action)); - erp_action->adapter = adapter; - erp_action->port = port; - erp_action->unit = unit; - erp_action->action = need; - erp_action->status = status; +/** + * zfcp_erp_thread_kill - Stop ERP thread. + * @adapter: Adapter where the ERP thread should be stopped. + * + * The caller of this routine ensures that the specified adapter has + * been shut down and that this operation has been completed. Thus, + * there are no pending erp_actions which would need to be handled + * here. + */ +void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) +{ + atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); + up(&adapter->erp_ready_sem); + zfcp_rec_dbf_event_thread_lock(2, adapter); - ++adapter->erp_total_count; + wait_event(adapter->erp_thread_wqh, + !(atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); - /* finally put it into 'ready' queue and kick erp thread */ - list_add_tail(&erp_action->list, &adapter->erp_ready_head); - up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread(1, adapter); - retval = 0; - out: - zfcp_rec_dbf_event_trigger(id, ref, want, need, erp_action, - adapter, port, unit); - return retval; + atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, + &adapter->status); } -static int -zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) +/** + * zfcp_erp_adapter_failed - Set adapter status to failed. + * @adapter: Failed adapter. + * @id: Event id for debug trace. + * @ref: Reference for debug trace. + */ +void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref) { - int retval = 0; - struct zfcp_adapter *adapter = erp_action->adapter; - - --adapter->erp_total_count; - if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { - --adapter->erp_low_mem_count; - erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; - } + zfcp_erp_modify_adapter_status(adapter, id, ref, + ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); + dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n"); +} - list_del(&erp_action->list); - zfcp_rec_dbf_event_action(144, erp_action); +/** + * zfcp_erp_port_failed - Set port status to failed. + * @port: Failed port. + * @id: Event id for debug trace. + * @ref: Reference for debug trace. + */ +void zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref) +{ + zfcp_erp_modify_port_status(port, id, ref, + ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); - switch (erp_action->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, - &erp_action->unit->status); - break; - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - case ZFCP_ERP_ACTION_REOPEN_PORT: - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, - &erp_action->port->status); - break; - case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, - &erp_action->adapter->status); - break; - default: - /* bug */ - break; - } - return retval; + if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) + dev_err(&port->adapter->ccw_device->dev, + "Port ERP failed for WKA port d_id=0x%06x.\n", + port->d_id); + else + dev_err(&port->adapter->ccw_device->dev, + "Port ERP failed for port wwpn=0x%016Lx.\n", + port->wwpn); } /** - * zfcp_erp_action_cleanup - * - * Register unit with scsi stack if appropriate and fix reference counts. - * Note: Temporary units are not registered with scsi stack. + * zfcp_erp_unit_failed - Set unit status to failed. + * @unit: Failed unit. + * @id: Event id for debug trace. + * @ref: Reference for debug trace. */ -static void -zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, - struct zfcp_port *port, struct zfcp_unit *unit, - int result) +void zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref) { - switch (action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if ((result == ZFCP_ERP_SUCCEEDED) - && (!atomic_test_mask(ZFCP_STATUS_UNIT_TEMPORARY, - &unit->status)) - && !unit->device - && port->rport) { - atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, - &unit->status); - if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, - &unit->status) == 0) - zfcp_erp_schedule_work(unit); - } - zfcp_unit_put(unit); - break; - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - case ZFCP_ERP_ACTION_REOPEN_PORT: - if (atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, - &port->status)) { - zfcp_port_put(port); - break; - } + zfcp_erp_modify_unit_status(unit, id, ref, + ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); - if ((result == ZFCP_ERP_SUCCEEDED) - && !port->rport) { - struct fc_rport_identifiers ids; - ids.node_name = port->wwnn; - ids.port_name = port->wwpn; - ids.port_id = port->d_id; - ids.roles = FC_RPORT_ROLE_FCP_TARGET; - port->rport = - fc_remote_port_add(adapter->scsi_host, 0, &ids); - if (!port->rport) - dev_err(&adapter->ccw_device->dev, - "Failed registration of rport " - "0x%016Lx.\n", port->wwpn); - else { - scsi_target_unblock(&port->rport->dev); - port->rport->maxframe_size = port->maxframe_size; - port->rport->supported_classes = - port->supported_classes; - } - } - if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { - fc_remote_port_delete(port->rport); - port->rport = NULL; - } - zfcp_port_put(port); - break; - case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - if (result != ZFCP_ERP_SUCCEEDED) { - list_for_each_entry(port, &adapter->port_list_head, list) - if (port->rport && - !atomic_test_mask(ZFCP_STATUS_PORT_WKA, - &port->status)) { - fc_remote_port_delete(port->rport); - port->rport = NULL; - } - } - zfcp_adapter_put(adapter); - break; - default: - break; - } + dev_err(&unit->port->adapter->ccw_device->dev, + "Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n", + unit->fcp_lun, unit->port->wwpn); } +/** + * zfcp_erp_wait - wait for completion of error recovery on an adapter + * @adapter: adapter for which to wait for completion of its error recovery + */ +void zfcp_erp_wait(struct zfcp_adapter *adapter) +{ + wait_event(adapter->erp_done_wqh, + !(atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_ERP_PENDING)); +} -static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) +/** + * zfcp_erp_modify_adapter_status - change adapter status bits + * @adapter: adapter to change the status + * @id: id for the debug trace + * @ref: reference for the debug trace + * @mask: status bits to change + * @set_or_clear: ZFCP_SET or ZFCP_CLEAR + * + * Changes in common status bits are propagated to attached ports and units. + */ +void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id, + void *ref, u32 mask, int set_or_clear) { struct zfcp_port *port; + u32 common_mask = mask & ZFCP_COMMON_FLAGS; - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) - zfcp_erp_action_dismiss(&adapter->erp_action); - else + if (set_or_clear == ZFCP_SET) { + if (status_change_set(mask, &adapter->status)) + zfcp_rec_dbf_event_adapter(id, ref, adapter); + atomic_set_mask(mask, &adapter->status); + } else { + if (status_change_clear(mask, &adapter->status)) + zfcp_rec_dbf_event_adapter(id, ref, adapter); + atomic_clear_mask(mask, &adapter->status); + if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) + atomic_set(&adapter->erp_counter, 0); + } + + if (common_mask) list_for_each_entry(port, &adapter->port_list_head, list) - zfcp_erp_action_dismiss_port(port); + zfcp_erp_modify_port_status(port, id, ref, common_mask, + set_or_clear); } -static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) +/** + * zfcp_erp_modify_port_status - change port status bits + * @port: port to change the status bits + * @id: id for the debug trace + * @ref: reference for the debug trace + * @mask: status bits to change + * @set_or_clear: ZFCP_SET or ZFCP_CLEAR + * + * Changes in common status bits are propagated to attached units. + */ +void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref, + u32 mask, int set_or_clear) { struct zfcp_unit *unit; + u32 common_mask = mask & ZFCP_COMMON_FLAGS; - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) - zfcp_erp_action_dismiss(&port->erp_action); - else - list_for_each_entry(unit, &port->unit_list_head, list) - zfcp_erp_action_dismiss_unit(unit); -} - -static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) -{ - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) - zfcp_erp_action_dismiss(&unit->erp_action); -} + if (set_or_clear == ZFCP_SET) { + if (status_change_set(mask, &port->status)) + zfcp_rec_dbf_event_port(id, ref, port); + atomic_set_mask(mask, &port->status); + } else { + if (status_change_clear(mask, &port->status)) + zfcp_rec_dbf_event_port(id, ref, port); + atomic_clear_mask(mask, &port->status); + if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) + atomic_set(&port->erp_counter, 0); + } -static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) -{ - list_move(&erp_action->list, &erp_action->adapter->erp_running_head); - zfcp_rec_dbf_event_action(145, erp_action); + if (common_mask) + list_for_each_entry(unit, &port->unit_list_head, list) + zfcp_erp_modify_unit_status(unit, id, ref, common_mask, + set_or_clear); } -static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) +/** + * zfcp_erp_modify_unit_status - change unit status bits + * @unit: unit to change the status bits + * @id: id for the debug trace + * @ref: reference for the debug trace + * @mask: status bits to change + * @set_or_clear: ZFCP_SET or ZFCP_CLEAR + */ +void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref, + u32 mask, int set_or_clear) { - list_move(&erp_action->list, &erp_action->adapter->erp_ready_head); - zfcp_rec_dbf_event_action(146, erp_action); + if (set_or_clear == ZFCP_SET) { + if (status_change_set(mask, &unit->status)) + zfcp_rec_dbf_event_unit(id, ref, unit); + atomic_set_mask(mask, &unit->status); + } else { + if (status_change_clear(mask, &unit->status)) + zfcp_rec_dbf_event_unit(id, ref, unit); + atomic_clear_mask(mask, &unit->status); + if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { + atomic_set(&unit->erp_counter, 0); + } + } } +/** + * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP + * @port: The "boxed" port. + * @id: The debug trace id. + * @id: Reference for the debug trace. + */ void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) { unsigned long flags; @@ -2614,6 +1687,12 @@ void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); } +/** + * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP + * @port: The "boxed" unit. + * @id: The debug trace id. + * @id: Reference for the debug trace. + */ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) { zfcp_erp_modify_unit_status(unit, id, ref, @@ -2621,6 +1700,15 @@ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); } +/** + * zfcp_erp_port_access_denied - Adapter denied access to port. + * @port: port where access has been denied + * @id: id for debug trace + * @ref: reference for debug trace + * + * Since the adapter has denied access, stop using the port and the + * attached units. + */ void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) { unsigned long flags; @@ -2632,6 +1720,14 @@ void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) read_unlock_irqrestore(&zfcp_data.config_lock, flags); } +/** + * zfcp_erp_unit_access_denied - Adapter denied access to unit. + * @unit: unit where access has been denied + * @id: id for debug trace + * @ref: reference for debug trace + * + * Since the adapter has denied access, stop using the unit. + */ void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) { zfcp_erp_modify_unit_status(unit, id, ref, @@ -2639,33 +1735,26 @@ void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); } -void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id, - void *ref) +static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id, + void *ref) { - struct zfcp_port *port; - unsigned long flags; - - if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) + int status = atomic_read(&unit->status); + if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_COMMON_ACCESS_BOXED))) return; - read_lock_irqsave(&zfcp_data.config_lock, flags); - if (adapter->nameserver_port) - zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref); - list_for_each_entry(port, &adapter->port_list_head, list) - if (port != adapter->nameserver_port) - zfcp_erp_port_access_changed(port, id, ref); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); } -void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, void *ref) +static void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, + void *ref) { struct zfcp_unit *unit; + int status = atomic_read(&port->status); - if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, - &port->status) && - !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, - &port->status)) { - if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) + if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_COMMON_ACCESS_BOXED))) { + if (!(status & ZFCP_STATUS_PORT_WKA)) list_for_each_entry(unit, &port->unit_list_head, list) zfcp_erp_unit_access_changed(unit, id, ref); return; @@ -2674,13 +1763,26 @@ void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, void *ref) zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); } -void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id, void *ref) +/** + * zfcp_erp_adapter_access_changed - Process change in adapter ACT + * @adapter: Adapter where the Access Control Table (ACT) changed + * @id: Id for debug trace + * @ref: Reference for debug trace + */ +void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id, + void *ref) { - if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, - &unit->status) && - !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, - &unit->status)) + struct zfcp_port *port; + unsigned long flags; + + if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) return; - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); + read_lock_irqsave(&zfcp_data.config_lock, flags); + if (adapter->nameserver_port) + zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref); + list_for_each_entry(port, &adapter->port_list_head, list) + if (port != adapter->nameserver_port) + zfcp_erp_port_access_changed(port, id, ref); + read_unlock_irqrestore(&zfcp_data.config_lock, flags); } diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 2845693413fb..13eb0a67da66 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -67,8 +67,6 @@ extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, struct fsf_qtcb_bottom_port *); extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, struct zfcp_fsf_cfdc *fsf_cfdc); -extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); -extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_adapter *); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); @@ -103,37 +101,34 @@ extern struct fc_function_template zfcp_transport_functions; /******************************** ERP ****************************************/ extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u8, void *, u32, int); -extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, u8, void *); -extern int zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, u8, void *); +extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, u8, void *); +extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, u8, void *); extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, u8, void *); extern void zfcp_erp_modify_port_status(struct zfcp_port *, u8, void *, u32, int); extern int zfcp_erp_port_reopen(struct zfcp_port *, int, u8, void *); -extern int zfcp_erp_port_shutdown(struct zfcp_port *, int, u8, void *); -extern int zfcp_erp_port_forced_reopen(struct zfcp_port *, int, u8, void *); +extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, u8, void *); +extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, u8, void *); extern void zfcp_erp_port_failed(struct zfcp_port *, u8, void *); -extern int zfcp_erp_port_reopen_all(struct zfcp_adapter *, int, u8, void *); extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, u8, void *, u32, int); -extern int zfcp_erp_unit_reopen(struct zfcp_unit *, int, u8, void *); -extern int zfcp_erp_unit_shutdown(struct zfcp_unit *, int, u8, void *); +extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, u8, void *); +extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, u8, void *); extern void zfcp_erp_unit_failed(struct zfcp_unit *, u8, void *); extern int zfcp_erp_thread_setup(struct zfcp_adapter *); -extern int zfcp_erp_thread_kill(struct zfcp_adapter *); -extern int zfcp_erp_wait(struct zfcp_adapter *); -extern void zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long); +extern void zfcp_erp_thread_kill(struct zfcp_adapter *); +extern void zfcp_erp_wait(struct zfcp_adapter *); +extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long); extern void zfcp_erp_port_boxed(struct zfcp_port *, u8 id, void *ref); extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8 id, void *ref); extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8 id, void *ref); extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8 id, void *ref); extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *); -extern void zfcp_erp_port_access_changed(struct zfcp_port *, u8, void *); -extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *); - +extern void zfcp_erp_timeout_handler(unsigned long); /******************************** AUX ****************************************/ extern void zfcp_sg_free_table(struct scatterlist *sg, int count); extern int zfcp_sg_setup_table(struct scatterlist *sg, int count); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index e6d815593b49..19c1ca913874 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -8,6 +8,31 @@ #include "zfcp_ext.h" +static void zfcp_fsf_request_timeout_handler(unsigned long data) +{ + struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; + zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62, + NULL); +} + +static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, + unsigned long timeout) +{ + fsf_req->timer.function = zfcp_fsf_request_timeout_handler; + fsf_req->timer.data = (unsigned long) fsf_req->adapter; + fsf_req->timer.expires = jiffies + timeout; + add_timer(&fsf_req->timer); +} + +static void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req) +{ + BUG_ON(!fsf_req->erp_action); + fsf_req->timer.function = zfcp_erp_timeout_handler; + fsf_req->timer.data = (unsigned long) fsf_req->erp_action; + fsf_req->timer.expires = jiffies + 30 * HZ; + add_timer(&fsf_req->timer); +} + /* association between FSF command and FSF QTCB type */ static u32 fsf_qtcb_type[] = { [FSF_QTCB_FCP_CMND] = FSF_IO_COMMAND, @@ -485,7 +510,7 @@ void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) req->handler(req); if (req->erp_action) - zfcp_erp_async_handler(req->erp_action, 0); + zfcp_erp_notify(req->erp_action, 0); req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) @@ -1108,7 +1133,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, if (erp_action) { erp_action->fsf_req = req; req->erp_action = erp_action; - zfcp_erp_start_timer(req); + zfcp_fsf_start_erp_timer(req); } else zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); @@ -1263,7 +1288,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) req->handler = zfcp_fsf_exchange_config_data_handler; erp_action->fsf_req = req; - zfcp_erp_start_timer(req); + zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); @@ -1353,7 +1378,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) req->erp_action = erp_action; erp_action->fsf_req = req; - zfcp_erp_start_timer(req); + zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); @@ -1530,7 +1555,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req = req; atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); - zfcp_erp_start_timer(req); + zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); @@ -1601,7 +1626,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req = req; atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); - zfcp_erp_start_timer(req); + zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); @@ -1699,7 +1724,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &erp_action->port->status); - zfcp_erp_start_timer(req); + zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); @@ -1878,7 +1903,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); - zfcp_erp_start_timer(req); + zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); @@ -1963,7 +1988,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) erp_action->fsf_req = req; atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); - zfcp_erp_start_timer(req); + zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); -- cgit v1.2.3 From 92c299d11acd3f3e75a721acb8f57c457d5c394f Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 2 Jul 2008 10:56:41 +0200 Subject: [SCSI] zfcp: Cleanup external header file Sort the extern definitions by file. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ext.h | 244 +++++++++++++++++++++---------------------- 1 file changed, 119 insertions(+), 125 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 13eb0a67da66..8065b2b224b7 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -11,160 +11,154 @@ #include "zfcp_def.h" -extern struct zfcp_data zfcp_data; - -/* zfcp_sysfs.c */ -extern struct attribute_group zfcp_sysfs_unit_attrs; -extern struct attribute_group zfcp_sysfs_adapter_attrs; -extern struct attribute_group zfcp_sysfs_ns_port_attrs; -extern struct attribute_group zfcp_sysfs_port_attrs; -extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; -extern struct device_attribute *zfcp_sysfs_shost_attrs[]; - -/**************************** CONFIGURATION *********************************/ -extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, fcp_lun_t); -extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, wwn_t); -extern int zfcp_adapter_enqueue(struct ccw_device *); -extern int zfcp_adapter_debug_register(struct zfcp_adapter *); -extern void zfcp_adapter_dequeue(struct zfcp_adapter *); -extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); -extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, - u32, u32); -extern void zfcp_port_dequeue(struct zfcp_port *); +/* zfcp_aux.c */ +extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, + fcp_lun_t); +extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, + wwn_t); +extern int zfcp_adapter_enqueue(struct ccw_device *); +extern void zfcp_adapter_dequeue(struct zfcp_adapter *); +extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32, + u32); +extern void zfcp_port_dequeue(struct zfcp_port *); extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); -extern void zfcp_unit_dequeue(struct zfcp_unit *); -extern int zfcp_scan_ports(struct zfcp_adapter *); -extern void _zfcp_scan_ports_later(struct work_struct *work); - -/******************************* S/390 IO ************************************/ -extern int zfcp_ccw_register(void); - -extern int zfcp_qdio_allocate(struct zfcp_adapter *); -extern void zfcp_qdio_free(struct zfcp_adapter *); -extern int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req); - -extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req - (struct zfcp_fsf_req *); -extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr - (struct zfcp_fsf_req *); -extern int zfcp_qdio_sbals_from_sg - (struct zfcp_fsf_req *, unsigned long, struct scatterlist *, int); -extern int zfcp_qdio_open(struct zfcp_adapter *adapter); -extern void zfcp_qdio_close(struct zfcp_adapter *adapter); -/******************************** FSF ****************************************/ -extern int zfcp_fsf_open_port(struct zfcp_erp_action *); -extern int zfcp_fsf_close_port(struct zfcp_erp_action *); -extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); - -extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); -extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); - -extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); -extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, - struct fsf_qtcb_bottom_config *); -extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); -extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, - struct fsf_qtcb_bottom_port *); -extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, - struct zfcp_fsf_cfdc *fsf_cfdc); -extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); -extern int zfcp_fsf_status_read(struct zfcp_adapter *); -extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); -extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, - struct zfcp_erp_action *); -extern int zfcp_fsf_send_els(struct zfcp_send_els *); -extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, - struct zfcp_unit *, - struct scsi_cmnd *, int, int); -extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *); -extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); -extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *, - struct zfcp_unit *, u8, - int); -extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command( - unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int); +extern void zfcp_unit_dequeue(struct zfcp_unit *); +extern int zfcp_reqlist_isempty(struct zfcp_adapter *); +extern void zfcp_sg_free_table(struct scatterlist *, int); +extern int zfcp_sg_setup_table(struct scatterlist *, int); -/******************************* FC/FCP **************************************/ -extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); -extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); -extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); -extern void zfcp_test_link(struct zfcp_port *); +/* zfcp_ccw.c */ +extern int zfcp_ccw_register(void); -/******************************* SCSI ****************************************/ -extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); -extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); -extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); -extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); +/* zfcp_cfdc.c */ +extern struct miscdevice zfcp_cfdc_misc; -extern struct fc_function_template zfcp_transport_functions; +/* zfcp_dbf.c */ +extern int zfcp_adapter_debug_register(struct zfcp_adapter *); +extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); +extern void zfcp_rec_dbf_event_thread(u8, struct zfcp_adapter *); +extern void zfcp_rec_dbf_event_thread_lock(u8, struct zfcp_adapter *); +extern void zfcp_rec_dbf_event_adapter(u8, void *, struct zfcp_adapter *); +extern void zfcp_rec_dbf_event_port(u8, void *, struct zfcp_port *); +extern void zfcp_rec_dbf_event_unit(u8, void *, struct zfcp_unit *); +extern void zfcp_rec_dbf_event_trigger(u8, void *, u8, u8, void *, + struct zfcp_adapter *, + struct zfcp_port *, struct zfcp_unit *); +extern void zfcp_rec_dbf_event_action(u8, struct zfcp_erp_action *); +extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); +extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, + struct fsf_status_read_buffer *); +extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, + unsigned int, unsigned int, unsigned int, + int, int); +extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); +extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); +extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); +extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); +extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); +extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, + struct scsi_cmnd *, + struct zfcp_fsf_req *); +extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *, + struct scsi_cmnd *, struct zfcp_fsf_req *, + unsigned long); +extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, + struct scsi_cmnd *); -/******************************** ERP ****************************************/ +/* zfcp_erp.c */ extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u8, void *, u32, int); extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, u8, void *); extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, u8, void *); extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, u8, void *); - extern void zfcp_erp_modify_port_status(struct zfcp_port *, u8, void *, u32, int); extern int zfcp_erp_port_reopen(struct zfcp_port *, int, u8, void *); extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, u8, void *); extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, u8, void *); extern void zfcp_erp_port_failed(struct zfcp_port *, u8, void *); - extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, u8, void *, u32, int); extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, u8, void *); extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, u8, void *); extern void zfcp_erp_unit_failed(struct zfcp_unit *, u8, void *); - extern int zfcp_erp_thread_setup(struct zfcp_adapter *); extern void zfcp_erp_thread_kill(struct zfcp_adapter *); extern void zfcp_erp_wait(struct zfcp_adapter *); extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long); - -extern void zfcp_erp_port_boxed(struct zfcp_port *, u8 id, void *ref); -extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8 id, void *ref); -extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8 id, void *ref); -extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8 id, void *ref); +extern void zfcp_erp_port_boxed(struct zfcp_port *, u8, void *); +extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8, void *); +extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8, void *); +extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8, void *); extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *); extern void zfcp_erp_timeout_handler(unsigned long); -/******************************** AUX ****************************************/ -extern void zfcp_sg_free_table(struct scatterlist *sg, int count); -extern int zfcp_sg_setup_table(struct scatterlist *sg, int count); -extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter); -extern void zfcp_rec_dbf_event_thread_lock(u8 id, struct zfcp_adapter *adapter); -extern void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *); -extern void zfcp_rec_dbf_event_port(u8 id, void *ref, struct zfcp_port *port); -extern void zfcp_rec_dbf_event_unit(u8 id, void *ref, struct zfcp_unit *unit); -extern void zfcp_rec_dbf_event_trigger(u8 id, void *ref, u8 want, u8 need, - void *action, struct zfcp_adapter *, - struct zfcp_port *, struct zfcp_unit *); -extern void zfcp_rec_dbf_event_action(u8 id, struct zfcp_erp_action *); - -extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); -extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, - struct fsf_status_read_buffer *); -extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, - unsigned int, unsigned int, unsigned int, - int, int); -extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); +/* zfcp_fc.c */ +extern int zfcp_scan_ports(struct zfcp_adapter *); +extern void _zfcp_scan_ports_later(struct work_struct *); +extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); +extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); +extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); +extern void zfcp_test_link(struct zfcp_port *); + +/* zfcp_fsf.c */ +extern int zfcp_fsf_open_port(struct zfcp_erp_action *); +extern int zfcp_fsf_close_port(struct zfcp_erp_action *); +extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); +extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); +extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); +extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); +extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, + struct fsf_qtcb_bottom_config *); +extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); +extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, + struct fsf_qtcb_bottom_port *); +extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *, + struct zfcp_fsf_cfdc *); +extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); +extern int zfcp_fsf_status_read(struct zfcp_adapter *); +extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); +extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, + struct zfcp_erp_action *); +extern int zfcp_fsf_send_els(struct zfcp_send_els *); +extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, + struct zfcp_unit *, + struct scsi_cmnd *, int, int); +extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *); +extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); +extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *, + struct zfcp_unit *, u8, int); +extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, + struct zfcp_adapter *, + struct zfcp_unit *, int); -extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, - struct scsi_cmnd *, - struct zfcp_fsf_req *); -extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *, - struct scsi_cmnd *, struct zfcp_fsf_req *, - unsigned long); -extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, - struct scsi_cmnd *); -extern int zfcp_reqlist_isempty(struct zfcp_adapter *); +/* zfcp_qdio.c */ +extern int zfcp_qdio_allocate(struct zfcp_adapter *); +extern void zfcp_qdio_free(struct zfcp_adapter *); +extern int zfcp_qdio_send(struct zfcp_fsf_req *); +extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req( + struct zfcp_fsf_req *); +extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr( + struct zfcp_fsf_req *); +extern int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *, unsigned long, + struct scatterlist *, int); +extern int zfcp_qdio_open(struct zfcp_adapter *); +extern void zfcp_qdio_close(struct zfcp_adapter *); + +/* zfcp_scsi.c */ +extern struct zfcp_data zfcp_data; +extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); +extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); +extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); +extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); +extern struct fc_function_template zfcp_transport_functions; -extern struct miscdevice zfcp_cfdc_misc; +/* zfcp_sysfs.c */ +extern struct attribute_group zfcp_sysfs_unit_attrs; +extern struct attribute_group zfcp_sysfs_adapter_attrs; +extern struct attribute_group zfcp_sysfs_ns_port_attrs; +extern struct attribute_group zfcp_sysfs_port_attrs; +extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; +extern struct device_attribute *zfcp_sysfs_shost_attrs[]; #endif /* ZFCP_EXT_H */ -- cgit v1.2.3