diff options
Diffstat (limited to 'drivers/s390')
43 files changed, 1803 insertions, 1377 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 8373ca0..aa95f10 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -21,7 +21,6 @@ #include <linux/hdreg.h> #include <linux/async.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <asm/ccwdev.h> #include <asm/ebcdic.h> @@ -2197,7 +2196,6 @@ static void dasd_setup_queue(struct dasd_block *block) */ blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1); - blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN); } /* @@ -2236,7 +2234,6 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) if (!block) return -ENODEV; - lock_kernel(); base = block->base; atomic_inc(&block->open_count); if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { @@ -2271,14 +2268,12 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) goto out; } - unlock_kernel(); return 0; out: module_put(base->discipline->owner); unlock: atomic_dec(&block->open_count); - unlock_kernel(); return rc; } @@ -2286,10 +2281,8 @@ static int dasd_release(struct gendisk *disk, fmode_t mode) { struct dasd_block *block = disk->private_data; - lock_kernel(); atomic_dec(&block->open_count); module_put(block->base->discipline->owner); - unlock_kernel(); return 0; } diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 7158f95..c71d89d 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -670,6 +670,7 @@ static const struct file_operations dasd_eer_fops = { .read = &dasd_eer_read, .poll = &dasd_eer_poll, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice *dasd_eer_dev = NULL; diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 1557214..26075e9 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -16,7 +16,6 @@ #include <linux/major.h> #include <linux/fs.h> #include <linux/blkpg.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <asm/compat.h> #include <asm/ccwdev.h> @@ -370,9 +369,8 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, return ret; } -static int -dasd_do_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) +int dasd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) { struct dasd_block *block = bdev->bd_disk->private_data; void __user *argp; @@ -430,14 +428,3 @@ dasd_do_ioctl(struct block_device *bdev, fmode_t mode, return -EINVAL; } } - -int dasd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - int rc; - - lock_kernel(); - rc = dasd_do_ioctl(bdev, mode, cmd, arg); - unlock_kernel(); - return rc; -} diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 2bd72aa..9b43ae9 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> #include <linux/completion.h> #include <linux/interrupt.h> #include <linux/platform_device.h> @@ -776,7 +775,6 @@ dcssblk_open(struct block_device *bdev, fmode_t mode) struct dcssblk_dev_info *dev_info; int rc; - lock_kernel(); dev_info = bdev->bd_disk->private_data; if (NULL == dev_info) { rc = -ENODEV; @@ -786,7 +784,6 @@ dcssblk_open(struct block_device *bdev, fmode_t mode) bdev->bd_block_size = 4096; rc = 0; out: - unlock_kernel(); return rc; } @@ -797,7 +794,6 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) struct segment_info *entry; int rc; - lock_kernel(); if (!dev_info) { rc = -ENODEV; goto out; @@ -815,7 +811,6 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) up_write(&dcssblk_devices_sem); rc = 0; out: - unlock_kernel(); return rc; } diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 857dfcb..eb28fb0 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -520,6 +520,7 @@ static const struct file_operations fs3270_fops = { .compat_ioctl = fs3270_ioctl, /* ioctl */ .open = fs3270_open, /* open */ .release = fs3270_close, /* release */ + .llseek = no_llseek, }; /* diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index e021ec6..5b8b859 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -447,6 +447,7 @@ static const struct file_operations mon_fops = { .release = &mon_close, .read = &mon_read, .poll = &mon_poll, + .llseek = noop_llseek, }; static struct miscdevice mon_dev = { diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 572a1e7..e0702d3 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -274,6 +274,7 @@ static const struct file_operations monwrite_fops = { .open = &monwrite_open, .release = &monwrite_close, .write = &monwrite_write, + .llseek = noop_llseek, }; static struct miscdevice mon_dev = { diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index f6d72e1..5707a80 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -468,7 +468,7 @@ sclp_sync_wait(void) cr0_sync &= 0xffff00a0; cr0_sync |= 0x00000200; __ctl_load(cr0_sync, 0, 0); - __raw_local_irq_stosm(0x01); + __arch_local_irq_stosm(0x01); /* Loop until driver state indicates finished request */ while (sclp_running_state != sclp_running_state_idle) { /* Check for expired request timer */ diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 85cf607..f0fa9ca 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -16,7 +16,7 @@ #include <linux/fs.h> #include <linux/module.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/buffer_head.h> #include <linux/kernel.h> @@ -45,6 +45,7 @@ /* * file operation structure for tape block frontend */ +static DEFINE_MUTEX(tape_block_mutex); static int tapeblock_open(struct block_device *, fmode_t); static int tapeblock_release(struct gendisk *, fmode_t); static int tapeblock_medium_changed(struct gendisk *); @@ -361,7 +362,7 @@ tapeblock_open(struct block_device *bdev, fmode_t mode) struct tape_device * device; int rc; - lock_kernel(); + mutex_lock(&tape_block_mutex); device = tape_get_device(disk->private_data); if (device->required_tapemarks) { @@ -385,14 +386,14 @@ tapeblock_open(struct block_device *bdev, fmode_t mode) * is called. */ tape_state_set(device, TS_BLKUSE); - unlock_kernel(); + mutex_unlock(&tape_block_mutex); return 0; release: tape_release(device); put_device: tape_put_device(device); - unlock_kernel(); + mutex_unlock(&tape_block_mutex); return rc; } @@ -407,11 +408,11 @@ tapeblock_release(struct gendisk *disk, fmode_t mode) { struct tape_device *device = disk->private_data; - lock_kernel(); + mutex_lock(&tape_block_mutex); tape_state_set(device, TS_IN_USE); tape_release(device); tape_put_device(device); - unlock_kernel(); + mutex_unlock(&tape_block_mutex); return 0; } diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index 539045a..883e2db 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -53,6 +53,7 @@ static const struct file_operations tape_fops = #endif .open = tapechar_open, .release = tapechar_release, + .llseek = no_llseek, }; static int tapechar_major = TAPECHAR_MAJOR; diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 04e532e..0e7cb1a 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -177,6 +177,7 @@ static const struct file_operations vmcp_fops = { .write = vmcp_write, .unlocked_ioctl = vmcp_ioctl, .compat_ioctl = vmcp_ioctl, + .llseek = no_llseek, }; static struct miscdevice vmcp_dev = { diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index e40a1b8..0d6dc4b 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -97,6 +97,7 @@ static const struct file_operations vmlogrdr_fops = { .open = vmlogrdr_open, .release = vmlogrdr_release, .read = vmlogrdr_read, + .llseek = no_llseek, }; diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index e13508c..12ef912 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -297,6 +297,7 @@ static const struct file_operations vmwdt_fops = { .unlocked_ioctl = &vmwdt_ioctl, .write = &vmwdt_write, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice vmwdt_dev = { diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index f5ea338..3b94044 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -459,6 +459,7 @@ static const struct file_operations zcore_memmap_fops = { .read = zcore_memmap_read, .open = zcore_memmap_open, .release = zcore_memmap_release, + .llseek = no_llseek, }; static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, @@ -486,6 +487,7 @@ static const struct file_operations zcore_reipl_fops = { .write = zcore_reipl_write, .open = zcore_reipl_open, .release = zcore_reipl_release, + .llseek = no_llseek, }; #ifdef CONFIG_32BIT diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index a83877c..f2b77e7 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -806,6 +806,7 @@ static const struct file_operations chsc_fops = { .open = nonseekable_open, .unlocked_ioctl = chsc_ioctl, .compat_ioctl = chsc_ioctl, + .llseek = no_llseek, }; static struct miscdevice chsc_misc_device = { diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index ac94ac75..ca8e1c2 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -1067,6 +1067,7 @@ static ssize_t cio_settle_write(struct file *file, const char __user *buf, static const struct file_operations cio_settle_proc_fops = { .open = nonseekable_open, .write = cio_settle_write, + .llseek = no_llseek, }; static int __init cio_settle_init(void) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index f0037ee..0f4ef87 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -208,6 +208,7 @@ struct qdio_dev_perf_stat { unsigned int eqbs_partial; unsigned int sqbs; unsigned int sqbs_partial; + unsigned int int_discarded; } ____cacheline_aligned; struct qdio_queue_perf_stat { @@ -222,6 +223,10 @@ struct qdio_queue_perf_stat { unsigned int nr_sbal_total; }; +enum qdio_queue_irq_states { + QDIO_QUEUE_IRQS_DISABLED, +}; + struct qdio_input_q { /* input buffer acknowledgement flag */ int polling; @@ -231,6 +236,10 @@ struct qdio_input_q { int ack_count; /* last time of noticing incoming data */ u64 timestamp; + /* upper-layer polling flag */ + unsigned long queue_irq_state; + /* callback to start upper-layer polling */ + void (*queue_start_poll) (struct ccw_device *, int, unsigned long); }; struct qdio_output_q { @@ -399,6 +408,26 @@ static inline int multicast_outbound(struct qdio_q *q) #define sub_buf(bufnr, dec) \ ((bufnr - dec) & QDIO_MAX_BUFFERS_MASK) +#define queue_irqs_enabled(q) \ + (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) == 0) +#define queue_irqs_disabled(q) \ + (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) != 0) + +#define TIQDIO_SHARED_IND 63 + +/* device state change indicators */ +struct indicator_t { + u32 ind; /* u32 because of compare-and-swap performance */ + atomic_t count; /* use count, 0 or 1 for non-shared indicators */ +}; + +extern struct indicator_t *q_indicators; + +static inline int shared_ind(struct qdio_irq *irq_ptr) +{ + return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; +} + /* prototypes for thin interrupt */ void qdio_setup_thinint(struct qdio_irq *irq_ptr); int qdio_establish_thinint(struct qdio_irq *irq_ptr); diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 6ce83f5..28868e7 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -56,9 +56,16 @@ static int qstat_show(struct seq_file *m, void *v) seq_printf(m, "DSCI: %d nr_used: %d\n", *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used)); - seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move); - seq_printf(m, "polling: %d ack start: %d ack count: %d\n", - q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count); + seq_printf(m, "ftc: %d last_move: %d\n", + q->first_to_check, q->last_move); + if (q->is_input_q) { + seq_printf(m, "polling: %d ack start: %d ack count: %d\n", + q->u.in.polling, q->u.in.ack_start, + q->u.in.ack_count); + seq_printf(m, "IRQs disabled: %u\n", + test_bit(QDIO_QUEUE_IRQS_DISABLED, + &q->u.in.queue_irq_state)); + } seq_printf(m, "SBAL states:\n"); seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); @@ -113,22 +120,6 @@ static int qstat_show(struct seq_file *m, void *v) return 0; } -static ssize_t qstat_seq_write(struct file *file, const char __user *buf, - size_t count, loff_t *off) -{ - struct seq_file *seq = file->private_data; - struct qdio_q *q = seq->private; - - if (!q) - return 0; - if (q->is_input_q) - xchg(q->irq_ptr->dsci, 1); - local_bh_disable(); - tasklet_schedule(&q->tasklet); - local_bh_enable(); - return count; -} - static int qstat_seq_open(struct inode *inode, struct file *filp) { return single_open(filp, qstat_show, @@ -139,7 +130,6 @@ static const struct file_operations debugfs_fops = { .owner = THIS_MODULE, .open = qstat_seq_open, .read = seq_read, - .write = qstat_seq_write, .llseek = seq_lseek, .release = single_release, }; @@ -166,7 +156,8 @@ static char *qperf_names[] = { "QEBSM eqbs", "QEBSM eqbs partial", "QEBSM sqbs", - "QEBSM sqbs partial" + "QEBSM sqbs partial", + "Discarded interrupts" }; static int qperf_show(struct seq_file *m, void *v) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 00520f9..5fcfa7f 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -884,8 +884,19 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) return; - for_each_input_queue(irq_ptr, q, i) - tasklet_schedule(&q->tasklet); + for_each_input_queue(irq_ptr, q, i) { + if (q->u.in.queue_start_poll) { + /* skip if polling is enabled or already in work */ + if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, + &q->u.in.queue_irq_state)) { + qperf_inc(q, int_discarded); + continue; + } + q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, + q->irq_ptr->int_parm); + } else + tasklet_schedule(&q->tasklet); + } if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)) return; @@ -1519,6 +1530,129 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, } EXPORT_SYMBOL_GPL(do_QDIO); +/** + * qdio_start_irq - process input buffers + * @cdev: associated ccw_device for the qdio subchannel + * @nr: input queue number + * + * Return codes + * 0 - success + * 1 - irqs not started since new data is available + */ +int qdio_start_irq(struct ccw_device *cdev, int nr) +{ + struct qdio_q *q; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; + + if (!irq_ptr) + return -ENODEV; + q = irq_ptr->input_qs[nr]; + + WARN_ON(queue_irqs_enabled(q)); + + if (!shared_ind(q->irq_ptr)) + xchg(q->irq_ptr->dsci, 0); + + qdio_stop_polling(q); + clear_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state); + + /* + * We need to check again to not lose initiative after + * resetting the ACK state. + */ + if (!shared_ind(q->irq_ptr) && *q->irq_ptr->dsci) + goto rescan; + if (!qdio_inbound_q_done(q)) + goto rescan; + return 0; + +rescan: + if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, + &q->u.in.queue_irq_state)) + return 0; + else + return 1; + +} +EXPORT_SYMBOL(qdio_start_irq); + +/** + * qdio_get_next_buffers - process input buffers + * @cdev: associated ccw_device for the qdio subchannel + * @nr: input queue number + * @bufnr: first filled buffer number + * @error: buffers are in error state + * + * Return codes + * < 0 - error + * = 0 - no new buffers found + * > 0 - number of processed buffers + */ +int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr, + int *error) +{ + struct qdio_q *q; + int start, end; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; + + if (!irq_ptr) + return -ENODEV; + q = irq_ptr->input_qs[nr]; + WARN_ON(queue_irqs_enabled(q)); + + qdio_sync_after_thinint(q); + + /* + * The interrupt could be caused by a PCI request. Check the + * PCI capable outbound queues. + */ + qdio_check_outbound_after_thinint(q); + + if (!qdio_inbound_q_moved(q)) + return 0; + + /* Note: upper-layer MUST stop processing immediately here ... */ + if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) + return -EIO; + + start = q->first_to_kick; + end = q->first_to_check; + *bufnr = start; + *error = q->qdio_error; + + /* for the next time */ + q->first_to_kick = end; + q->qdio_error = 0; + return sub_buf(end, start); +} +EXPORT_SYMBOL(qdio_get_next_buffers); + +/** + * qdio_stop_irq - disable interrupt processing for the device + * @cdev: associated ccw_device for the qdio subchannel + * @nr: input queue number + * + * Return codes + * 0 - interrupts were already disabled + * 1 - interrupts successfully disabled + */ +int qdio_stop_irq(struct ccw_device *cdev, int nr) +{ + struct qdio_q *q; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; + + if (!irq_ptr) + return -ENODEV; + q = irq_ptr->input_qs[nr]; + + if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, + &q->u.in.queue_irq_state)) + return 0; + else + return 1; +} +EXPORT_SYMBOL(qdio_stop_irq); + static int __init init_QDIO(void) { int rc; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 34c7e40..a13cf7e 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -161,6 +161,7 @@ static void setup_queues(struct qdio_irq *irq_ptr, setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); q->is_input_q = 1; + q->u.in.queue_start_poll = qdio_init->queue_start_poll; setup_storage_lists(q, irq_ptr, input_sbal_array, i); input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 8daf1b9..752dbee 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -25,24 +25,20 @@ */ #define TIQDIO_NR_NONSHARED_IND 63 #define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1) -#define TIQDIO_SHARED_IND 63 /* list of thin interrupt input queues */ static LIST_HEAD(tiq_list); DEFINE_MUTEX(tiq_list_lock); /* adapter local summary indicator */ -static unsigned char *tiqdio_alsi; +static u8 *tiqdio_alsi; -/* device state change indicators */ -struct indicator_t { - u32 ind; /* u32 because of compare-and-swap performance */ - atomic_t count; /* use count, 0 or 1 for non-shared indicators */ -}; -static struct indicator_t *q_indicators; +struct indicator_t *q_indicators; static int css_qdio_omit_svs; +static u64 last_ai_time; + static inline unsigned long do_clear_global_summary(void) { register unsigned long __fn asm("1") = 3; @@ -116,59 +112,73 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) } } -static inline int shared_ind(struct qdio_irq *irq_ptr) +static inline int shared_ind_used(void) { - return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; + return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count); } /** * tiqdio_thinint_handler - thin interrupt handler for qdio - * @ind: pointer to adapter local summary indicator - * @drv_data: NULL + * @alsi: pointer to adapter local summary indicator + * @data: NULL */ -static void tiqdio_thinint_handler(void *ind, void *drv_data) +static void tiqdio_thinint_handler(void *alsi, void *data) { struct qdio_q *q; + last_ai_time = S390_lowcore.int_clock; + /* * SVS only when needed: issue SVS to benefit from iqdio interrupt - * avoidance (SVS clears adapter interrupt suppression overwrite) + * avoidance (SVS clears adapter interrupt suppression overwrite). */ if (!css_qdio_omit_svs) do_clear_global_summary(); - /* - * reset local summary indicator (tiqdio_alsi) to stop adapter - * interrupts for now - */ - xchg((u8 *)ind, 0); + /* reset local summary indicator */ + if (shared_ind_used()) + xchg(tiqdio_alsi, 0); /* protect tiq_list entries, only changed in activate or shutdown */ rcu_read_lock(); /* check for work on all inbound thinint queues */ - list_for_each_entry_rcu(q, &tiq_list, entry) + list_for_each_entry_rcu(q, &tiq_list, entry) { + /* only process queues from changed sets */ - if (*q->irq_ptr->dsci) { - qperf_inc(q, adapter_int); + if (!*q->irq_ptr->dsci) + continue; + if (q->u.in.queue_start_poll) { + /* skip if polling is enabled or already in work */ + if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, + &q->u.in.queue_irq_state)) { + qperf_inc(q, int_discarded); + continue; + } + + /* avoid dsci clear here, done after processing */ + q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, + q->irq_ptr->int_parm); + } else { /* only clear it if the indicator is non-shared */ if (!shared_ind(q->irq_ptr)) xchg(q->irq_ptr->dsci, 0); /* - * don't call inbound processing directly since - * that could starve other thinint queues + * Call inbound processing but not directly + * since that could starve other thinint queues. */ tasklet_schedule(&q->tasklet); } - + qperf_inc(q, adapter_int); + } rcu_read_unlock(); /* - * if we used the shared indicator clear it now after all queues - * were processed + * If the shared indicator was used clear it now after all queues + * were processed. */ - if (atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) { + if (shared_ind_used()) { xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); /* prevent racing */ diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 41e0aae..f522174 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -897,7 +897,8 @@ static const struct file_operations zcrypt_fops = { .compat_ioctl = zcrypt_compat_ioctl, #endif .open = zcrypt_open, - .release = zcrypt_release + .release = zcrypt_release, + .llseek = no_llseek, }; /* diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 977bb4d..456b187 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -100,6 +100,6 @@ config QETH_IPV6 config CCWGROUP tristate - default (LCS || CTCM || QETH) + default (LCS || CTCM || QETH || CLAW) endmenu diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index 2861e787..b64881f 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -540,7 +540,7 @@ void ctc_mpc_dealloc_ch(int port_num) CTCM_DBF_TEXT_(MPC_SETUP, CTC_DBF_DEBUG, "%s: %s: refcount = %d\n", - CTCM_FUNTAIL, dev->name, atomic_read(&dev->refcnt)); + CTCM_FUNTAIL, dev->name, netdev_refcnt_read(dev)); fsm_deltimer(&priv->restart_timer); grp->channels_terminating = 0; diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index d125776..6be43eb 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -676,6 +676,7 @@ enum qeth_discipline_id { }; struct qeth_discipline { + void (*start_poll)(struct ccw_device *, int, unsigned long); qdio_handler_t *input_handler; qdio_handler_t *output_handler; int (*recover)(void *ptr); @@ -702,6 +703,16 @@ struct qeth_skb_data { #define QETH_SKB_MAGIC 0x71657468 #define QETH_SIGA_CC2_RETRIES 3 +struct qeth_rx { + int b_count; + int b_index; + struct qdio_buffer_element *b_element; + int e_offset; + int qdio_err; +}; + +#define QETH_NAPI_WEIGHT 128 + struct qeth_card { struct list_head list; enum qeth_card_states state; @@ -749,6 +760,8 @@ struct qeth_card { debug_info_t *debug; struct mutex conf_mutex; struct mutex discipline_mutex; + struct napi_struct napi; + struct qeth_rx rx; }; struct qeth_card_list_struct { @@ -831,6 +844,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, struct qdio_buffer *, struct qdio_buffer_element **, int *, struct qeth_hdr **); void qeth_schedule_recovery(struct qeth_card *); +void qeth_qdio_start_poll(struct ccw_device *, int, unsigned long); +void qeth_qdio_input_handler(struct ccw_device *, + unsigned int, unsigned int, int, + int, unsigned long); void qeth_qdio_output_handler(struct ccw_device *, unsigned int, int, int, int, unsigned long); void qeth_clear_ipacmd_list(struct qeth_card *); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3a5a18a..7642670 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2911,6 +2911,27 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) } } +void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue, + unsigned long card_ptr) +{ + struct qeth_card *card = (struct qeth_card *)card_ptr; + + if (card->dev) + napi_schedule(&card->napi); +} +EXPORT_SYMBOL_GPL(qeth_qdio_start_poll); + +void qeth_qdio_input_handler(struct ccw_device *ccwdev, unsigned int qdio_err, + unsigned int queue, int first_element, int count, + unsigned long card_ptr) +{ + struct qeth_card *card = (struct qeth_card *)card_ptr; + + if (qdio_err) + qeth_schedule_recovery(card); +} +EXPORT_SYMBOL_GPL(qeth_qdio_input_handler); + void qeth_qdio_output_handler(struct ccw_device *ccwdev, unsigned int qdio_error, int __queue, int first_element, int count, unsigned long card_ptr) @@ -3843,6 +3864,7 @@ static int qeth_qdio_establish(struct qeth_card *card) init_data.no_output_qs = card->qdio.no_out_queues; init_data.input_handler = card->discipline.input_handler; init_data.output_handler = card->discipline.output_handler; + init_data.queue_start_poll = card->discipline.start_poll; init_data.int_parm = (unsigned long) card; init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; @@ -4513,8 +4535,8 @@ static struct { /* 20 */{"queue 1 buffer usage"}, {"queue 2 buffer usage"}, {"queue 3 buffer usage"}, - {"rx handler time"}, - {"rx handler count"}, + {"rx poll time"}, + {"rx poll count"}, {"rx do_QDIO time"}, {"rx do_QDIO count"}, {"tx handler time"}, diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 830d6352..847e8797 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -310,6 +310,8 @@ static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) struct qeth_vlan_vid *id; QETH_CARD_TEXT_(card, 4, "aid:%d", vid); + if (!vid) + return; if (card->info.type == QETH_CARD_TYPE_OSM) { QETH_CARD_TEXT(card, 3, "aidOSM"); return; @@ -407,29 +409,25 @@ static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) return rc; } -static void qeth_l2_process_inbound_buffer(struct qeth_card *card, - struct qeth_qdio_buffer *buf, int index) +static int qeth_l2_process_inbound_buffer(struct qeth_card *card, + int budget, int *done) { - struct qdio_buffer_element *element; + int work_done = 0; struct sk_buff *skb; struct qeth_hdr *hdr; - int offset; unsigned int len; - /* get first element of current buffer */ - element = (struct qdio_buffer_element *)&buf->buffer->element[0]; - offset = 0; - if (card->options.performance_stats) - card->perf_stats.bufs_rec++; - while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element, - &offset, &hdr))) { - skb->dev = card->dev; - /* is device UP ? */ - if (!(card->dev->flags & IFF_UP)) { - dev_kfree_skb_any(skb); - continue; + *done = 0; + BUG_ON(!budget); + while (budget) { + skb = qeth_core_get_next_skb(card, + card->qdio.in_q->bufs[card->rx.b_index].buffer, + &card->rx.b_element, &card->rx.e_offset, &hdr); + if (!skb) { + *done = 1; + break; } - + skb->dev = card->dev; switch (hdr->hdr.l2.id) { case QETH_HEADER_TYPE_LAYER2: skb->pkt_type = PACKET_HOST; @@ -441,7 +439,7 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card, if (skb->protocol == htons(ETH_P_802_2)) *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; len = skb->len; - netif_rx(skb); + netif_receive_skb(skb); break; case QETH_HEADER_TYPE_OSN: if (card->info.type == QETH_CARD_TYPE_OSN) { @@ -459,9 +457,87 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card, QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); continue; } + work_done++; + budget--; card->stats.rx_packets++; card->stats.rx_bytes += len; } + return work_done; +} + +static int qeth_l2_poll(struct napi_struct *napi, int budget) +{ + struct qeth_card *card = container_of(napi, struct qeth_card, napi); + int work_done = 0; + struct qeth_qdio_buffer *buffer; + int done; + int new_budget = budget; + + if (card->options.performance_stats) { + card->perf_stats.inbound_cnt++; + card->perf_stats.inbound_start_time = qeth_get_micros(); + } + + while (1) { + if (!card->rx.b_count) { + card->rx.qdio_err = 0; + card->rx.b_count = qdio_get_next_buffers( + card->data.ccwdev, 0, &card->rx.b_index, + &card->rx.qdio_err); + if (card->rx.b_count <= 0) { + card->rx.b_count = 0; + break; + } + card->rx.b_element = + &card->qdio.in_q->bufs[card->rx.b_index] + .buffer->element[0]; + card->rx.e_offset = 0; + } + + while (card->rx.b_count) { + buffer = &card->qdio.in_q->bufs[card->rx.b_index]; + if (!(card->rx.qdio_err && + qeth_check_qdio_errors(card, buffer->buffer, + card->rx.qdio_err, "qinerr"))) + work_done += qeth_l2_process_inbound_buffer( + card, new_budget, &done); + else + done = 1; + + if (done) { + if (card->options.performance_stats) + card->perf_stats.bufs_rec++; + qeth_put_buffer_pool_entry(card, + buffer->pool_entry); + qeth_queue_input_buffer(card, card->rx.b_index); + card->rx.b_count--; + if (card->rx.b_count) { + card->rx.b_index = + (card->rx.b_index + 1) % + QDIO_MAX_BUFFERS_PER_Q; + card->rx.b_element = + &card->qdio.in_q + ->bufs[card->rx.b_index] + .buffer->element[0]; + card->rx.e_offset = 0; + } + } + + if (work_done >= budget) + goto out; + else + new_budget = budget - work_done; + } + } + + napi_complete(napi); + if (qdio_start_irq(card->data.ccwdev, 0)) + napi_schedule(&card->napi); +out: + if (card->options.performance_stats) + card->perf_stats.inbound_time += qeth_get_micros() - + card->perf_stats.inbound_start_time; + return work_done; } static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, @@ -755,49 +831,10 @@ tx_drop: return NETDEV_TX_OK; } -static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev, - unsigned int qdio_err, unsigned int queue, - int first_element, int count, unsigned long card_ptr) -{ - struct net_device *net_dev; - struct qeth_card *card; - struct qeth_qdio_buffer *buffer; - int index; - int i; - - card = (struct qeth_card *) card_ptr; - net_dev = card->dev; - if (card->options.performance_stats) { - card->perf_stats.inbound_cnt++; - card->perf_stats.inbound_start_time = qeth_get_micros(); - } - if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { - QETH_CARD_TEXT(card, 1, "qdinchk"); - QETH_CARD_TEXT_(card, 1, "%04X%04X", first_element, - count); - QETH_CARD_TEXT_(card, 1, "%04X", queue); - qeth_schedule_recovery(card); - return; - } - for (i = first_element; i < (first_element + count); ++i) { - index = i % QDIO_MAX_BUFFERS_PER_Q; - buffer = &card->qdio.in_q->bufs[index]; - if (!(qdio_err && - qeth_check_qdio_errors(card, buffer->buffer, qdio_err, - "qinerr"))) - qeth_l2_process_inbound_buffer(card, buffer, index); - /* clear buffer and give back to hardware */ - qeth_put_buffer_pool_entry(card, buffer->pool_entry); - qeth_queue_input_buffer(card, index); - } - if (card->options.performance_stats) - card->perf_stats.inbound_time += qeth_get_micros() - - card->perf_stats.inbound_start_time; -} - static int qeth_l2_open(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; + int rc = 0; QETH_CARD_TEXT(card, 4, "qethopen"); if (card->state != CARD_STATE_SOFTSETUP) @@ -814,18 +851,24 @@ static int qeth_l2_open(struct net_device *dev) if (!card->lan_online && netif_carrier_ok(dev)) netif_carrier_off(dev); - return 0; + if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { + napi_enable(&card->napi); + napi_schedule(&card->napi); + } else + rc = -EIO; + return rc; } - static int qeth_l2_stop(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; QETH_CARD_TEXT(card, 4, "qethstop"); netif_tx_disable(dev); - if (card->state == CARD_STATE_UP) + if (card->state == CARD_STATE_UP) { card->state = CARD_STATE_SOFTSETUP; + napi_disable(&card->napi); + } return 0; } @@ -836,8 +879,9 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) INIT_LIST_HEAD(&card->vid_list); INIT_LIST_HEAD(&card->mc_list); card->options.layer2 = 1; + card->discipline.start_poll = qeth_qdio_start_poll; card->discipline.input_handler = (qdio_handler_t *) - qeth_l2_qdio_input_handler; + qeth_qdio_input_handler; card->discipline.output_handler = (qdio_handler_t *) qeth_qdio_output_handler; card->discipline.recover = qeth_l2_recover; @@ -923,6 +967,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) card->info.broadcast_capable = 1; qeth_l2_request_initial_mac(card); SET_NETDEV_DEV(card->dev, &card->gdev->dev); + netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT); return register_netdev(card->dev); } @@ -955,6 +1000,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); card->state = CARD_STATE_HARDSETUP; + memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card); /* softsetup */ @@ -1086,9 +1132,6 @@ static int qeth_l2_recover(void *ptr) card->use_hard_stop = 1; __qeth_l2_set_offline(card->gdev, 1); rc = __qeth_l2_set_online(card->gdev, 1); - /* don't run another scheduled recovery */ - qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); - qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); if (!rc) dev_info(&card->gdev->dev, "Device successfully recovered!\n"); @@ -1099,6 +1142,8 @@ static int qeth_l2_recover(void *ptr) dev_warn(&card->gdev->dev, "The qeth device driver " "failed to recover an error on the device\n"); } + qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); + qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); return 0; } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index e22ae24..74d1401 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -103,12 +103,7 @@ int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr) void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf) { - sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x" - ":%02x%02x:%02x%02x:%02x%02x:%02x%02x", - addr[0], addr[1], addr[2], addr[3], - addr[4], addr[5], addr[6], addr[7], - addr[8], addr[9], addr[10], addr[11], - addr[12], addr[13], addr[14], addr[15]); + sprintf(buf, "%pI6", addr); } int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr) @@ -1825,7 +1820,7 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card) return; vg = card->vlangrp; - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + for (i = 0; i < VLAN_N_VID; i++) { struct net_device *netdev = vlan_group_get_device(vg, i); if (netdev == NULL || !(netdev->flags & IFF_UP)) @@ -1888,7 +1883,7 @@ static void qeth_l3_add_vlan_mc6(struct qeth_card *card) return; vg = card->vlangrp; - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + for (i = 0; i < VLAN_N_VID; i++) { struct net_device *netdev = vlan_group_get_device(vg, i); if (netdev == NULL || !(netdev->flags & IFF_UP)) @@ -2018,13 +2013,14 @@ static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) qeth_l3_set_multicast_list(card->dev); } -static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, - struct sk_buff *skb, struct qeth_hdr *hdr) +static inline int qeth_l3_rebuild_skb(struct qeth_card *card, + struct sk_buff *skb, struct qeth_hdr *hdr, + unsigned short *vlan_id) { - unsigned short vlan_id = 0; __be16 prot; struct iphdr *ip_hdr; unsigned char tg_addr[MAX_ADDR_LEN]; + int is_vlan = 0; if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) { prot = htons((hdr->hdr.l3.flags & QETH_HDR_IPV6)? ETH_P_IPV6 : @@ -2087,8 +2083,9 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, if (hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) { - vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME)? + *vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ? hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); + is_vlan = 1; } switch (card->options.checksum_type) { @@ -2109,54 +2106,44 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, skb->ip_summed = CHECKSUM_NONE; } - return vlan_id; + return is_vlan; } -static void qeth_l3_process_inbound_buffer(struct qeth_card *card, - struct qeth_qdio_buffer *buf, int index) +static int qeth_l3_process_inbound_buffer(struct qeth_card *card, + int budget, int *done) { - struct qdio_buffer_element *element; + int work_done = 0; struct sk_buff *skb; struct qeth_hdr *hdr; - int offset; __u16 vlan_tag = 0; + int is_vlan; unsigned int len; - /* get first element of current buffer */ - element = (struct qdio_buffer_element *)&buf->buffer->element[0]; - offset = 0; - if (card->options.performance_stats) - card->perf_stats.bufs_rec++; - while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element, - &offset, &hdr))) { - skb->dev = card->dev; - /* is device UP ? */ - if (!(card->dev->flags & IFF_UP)) { - dev_kfree_skb_any(skb); - continue; - } + *done = 0; + BUG_ON(!budget); + while (budget) { + skb = qeth_core_get_next_skb(card, + card->qdio.in_q->bufs[card->rx.b_index].buffer, + &card->rx.b_element, &card->rx.e_offset, &hdr); + if (!skb) { + *done = 1; + break; + } + skb->dev = card->dev; switch (hdr->hdr.l3.id) { case QETH_HEADER_TYPE_LAYER3: - vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); + is_vlan = qeth_l3_rebuild_skb(card, skb, hdr, + &vlan_tag); len = skb->len; - if (vlan_tag && !card->options.sniffer) - if (card->vlangrp) - vlan_hwaccel_rx(skb, card->vlangrp, - vlan_tag); - else { - dev_kfree_skb_any(skb); - continue; - } + if (is_vlan && !card->options.sniffer) + vlan_gro_receive(&card->napi, card->vlangrp, + vlan_tag, skb); else - netif_rx(skb); + napi_gro_receive(&card->napi, skb); break; case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); - if (card->options.checksum_type == NO_CHECKSUMMING) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb->ip_summed = CHECKSUM_NONE; len = skb->len; netif_receive_skb(skb); break; @@ -2166,10 +2153,87 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); continue; } - + work_done++; + budget--; card->stats.rx_packets++; card->stats.rx_bytes += len; } + return work_done; +} + +static int qeth_l3_poll(struct napi_struct *napi, int budget) +{ + struct qeth_card *card = container_of(napi, struct qeth_card, napi); + int work_done = 0; + struct qeth_qdio_buffer *buffer; + int done; + int new_budget = budget; + + if (card->options.performance_stats) { + card->perf_stats.inbound_cnt++; + card->perf_stats.inbound_start_time = qeth_get_micros(); + } + + while (1) { + if (!card->rx.b_count) { + card->rx.qdio_err = 0; + card->rx.b_count = qdio_get_next_buffers( + card->data.ccwdev, 0, &card->rx.b_index, + &card->rx.qdio_err); + if (card->rx.b_count <= 0) { + card->rx.b_count = 0; + break; + } + card->rx.b_element = + &card->qdio.in_q->bufs[card->rx.b_index] + .buffer->element[0]; + card->rx.e_offset = 0; + } + + while (card->rx.b_count) { + buffer = &card->qdio.in_q->bufs[card->rx.b_index]; + if (!(card->rx.qdio_err && + qeth_check_qdio_errors(card, buffer->buffer, + card->rx.qdio_err, "qinerr"))) + work_done += qeth_l3_process_inbound_buffer( + card, new_budget, &done); + else + done = 1; + + if (done) { + if (card->options.performance_stats) + card->perf_stats.bufs_rec++; + qeth_put_buffer_pool_entry(card, + buffer->pool_entry); + qeth_queue_input_buffer(card, card->rx.b_index); + card->rx.b_count--; + if (card->rx.b_count) { + card->rx.b_index = + (card->rx.b_index + 1) % + QDIO_MAX_BUFFERS_PER_Q; + card->rx.b_element = + &card->qdio.in_q + ->bufs[card->rx.b_index] + .buffer->element[0]; + card->rx.e_offset = 0; + } + } + + if (work_done >= budget) + goto out; + else + new_budget = budget - work_done; + } + } + + napi_complete(napi); + if (qdio_start_irq(card->data.ccwdev, 0)) + napi_schedule(&card->napi); +out: + if (card->options.performance_stats) + card->perf_stats.inbound_time += qeth_get_micros() - + card->perf_stats.inbound_start_time; + return work_done; } static int qeth_l3_verify_vlan_dev(struct net_device *dev, @@ -2183,7 +2247,7 @@ static int qeth_l3_verify_vlan_dev(struct net_device *dev, if (!vg) return rc; - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + for (i = 0; i < VLAN_N_VID; i++) { if (vlan_group_get_device(vg, i) == dev) { rc = QETH_VLAN_CARD; break; @@ -3103,6 +3167,7 @@ tx_drop: static int qeth_l3_open(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; + int rc = 0; QETH_CARD_TEXT(card, 4, "qethopen"); if (card->state != CARD_STATE_SOFTSETUP) @@ -3113,7 +3178,12 @@ static int qeth_l3_open(struct net_device *dev) if (!card->lan_online && netif_carrier_ok(dev)) netif_carrier_off(dev); - return 0; + if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { + napi_enable(&card->napi); + napi_schedule(&card->napi); + } else + rc = -EIO; + return rc; } static int qeth_l3_stop(struct net_device *dev) @@ -3122,8 +3192,10 @@ static int qeth_l3_stop(struct net_device *dev) QETH_CARD_TEXT(card, 4, "qethstop"); netif_tx_disable(dev); - if (card->state == CARD_STATE_UP) + if (card->state == CARD_STATE_UP) { card->state = CARD_STATE_SOFTSETUP; + napi_disable(&card->napi); + } return 0; } @@ -3293,57 +3365,19 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->gso_max_size = 15 * PAGE_SIZE; SET_NETDEV_DEV(card->dev, &card->gdev->dev); + netif_napi_add(card->dev, &card->napi, qeth_l3_poll, QETH_NAPI_WEIGHT); return register_netdev(card->dev); } -static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, - unsigned int qdio_err, unsigned int queue, int first_element, - int count, unsigned long card_ptr) -{ - struct net_device *net_dev; - struct qeth_card *card; - struct qeth_qdio_buffer *buffer; - int index; - int i; - - card = (struct qeth_card *) card_ptr; - net_dev = card->dev; - if (card->options.performance_stats) { - card->perf_stats.inbound_cnt++; - card->perf_stats.inbound_start_time = qeth_get_micros(); - } - if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { - QETH_CARD_TEXT(card, 1, "qdinchk"); - QETH_CARD_TEXT_(card, 1, "%04X%04X", - first_element, count); - QETH_CARD_TEXT_(card, 1, "%04X", queue); - qeth_schedule_recovery(card); - return; - } - for (i = first_element; i < (first_element + count); ++i) { - index = i % QDIO_MAX_BUFFERS_PER_Q; - buffer = &card->qdio.in_q->bufs[index]; - if (!(qdio_err && - qeth_check_qdio_errors(card, buffer->buffer, - qdio_err, "qinerr"))) - qeth_l3_process_inbound_buffer(card, buffer, index); - /* clear buffer and give back to hardware */ - qeth_put_buffer_pool_entry(card, buffer->pool_entry); - qeth_queue_input_buffer(card, index); - } - if (card->options.performance_stats) - card->perf_stats.inbound_time += qeth_get_micros() - - card->perf_stats.inbound_start_time; -} - static int qeth_l3_probe_device(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); qeth_l3_create_device_attributes(&gdev->dev); card->options.layer2 = 0; + card->discipline.start_poll = qeth_qdio_start_poll; card->discipline.input_handler = (qdio_handler_t *) - qeth_l3_qdio_input_handler; + qeth_qdio_input_handler; card->discipline.output_handler = (qdio_handler_t *) qeth_qdio_output_handler; card->discipline.recover = qeth_l3_recover; @@ -3402,6 +3436,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) } card->state = CARD_STATE_HARDSETUP; + memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card); /* softsetup */ @@ -3538,9 +3573,6 @@ static int qeth_l3_recover(void *ptr) card->use_hard_stop = 1; __qeth_l3_set_offline(card->gdev, 1); rc = __qeth_l3_set_online(card->gdev, 1); - /* don't run another scheduled recovery */ - qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); - qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); if (!rc) dev_info(&card->gdev->dev, "Device successfully recovered!\n"); @@ -3551,6 +3583,8 @@ static int qeth_l3_recover(void *ptr) dev_warn(&card->gdev->dev, "The qeth device driver " "failed to recover an error on the device\n"); } + qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); + qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); return 0; } diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index cb301cc..c454ffe 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -2,7 +2,8 @@ # Makefile for the S/390 specific device drivers # -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.o zfcp_fc.o zfcp_cfdc.o +zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_cfdc.o zfcp_dbf.o zfcp_erp.o \ + zfcp_fc.o zfcp_fsf.o zfcp_qdio.o zfcp_scsi.o zfcp_sysfs.o \ + zfcp_unit.o obj-$(CONFIG_ZFCP) += zfcp.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 96fa1f5..044fb22 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -56,7 +56,6 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) struct ccw_device *cdev; struct zfcp_adapter *adapter; struct zfcp_port *port; - struct zfcp_unit *unit; cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); if (!cdev) @@ -72,17 +71,11 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) port = zfcp_get_port_by_wwpn(adapter, wwpn); if (!port) goto out_port; + flush_work(&port->rport_work); - unit = zfcp_unit_enqueue(port, lun); - if (IS_ERR(unit)) - goto out_unit; - - zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); - zfcp_erp_wait(adapter); - flush_work(&unit->scsi_work); - -out_unit: + zfcp_unit_add(port, lun); put_device(&port->dev); + out_port: zfcp_ccw_adapter_put(adapter); out_ccw_device: @@ -158,6 +151,9 @@ static int __init zfcp_module_init(void) fc_attach_transport(&zfcp_transport_functions); if (!zfcp_data.scsi_transport_template) goto out_transport; + scsi_transport_reserve_device(zfcp_data.scsi_transport_template, + sizeof(struct zfcp_scsi_dev)); + retval = misc_register(&zfcp_cfdc_misc); if (retval) { @@ -211,30 +207,6 @@ static void __exit zfcp_module_exit(void) module_exit(zfcp_module_exit); /** - * 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 - * - * Returns: pointer to zfcp_unit or NULL - */ -struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) -{ - unsigned long flags; - struct zfcp_unit *unit; - - read_lock_irqsave(&port->unit_list_lock, flags); - list_for_each_entry(unit, &port->unit_list, list) - if (unit->fcp_lun == fcp_lun) { - if (!get_device(&unit->dev)) - unit = NULL; - read_unlock_irqrestore(&port->unit_list_lock, flags); - return unit; - } - read_unlock_irqrestore(&port->unit_list_lock, flags); - 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 @@ -259,92 +231,6 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, return NULL; } -/** - * zfcp_unit_release - dequeue unit - * @dev: pointer to device - * - * waits until all work is done on unit and removes it then from the unit->list - * of the associated port. - */ -static void zfcp_unit_release(struct device *dev) -{ - struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); - - put_device(&unit->port->dev); - kfree(unit); -} - -/** - * 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 - * Returns: pointer to enqueued unit on success, ERR_PTR on error - * - * Sets up some unit internal structures and creates sysfs entry. - */ -struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) -{ - struct zfcp_unit *unit; - int retval = -ENOMEM; - - get_device(&port->dev); - - unit = zfcp_get_unit_by_lun(port, fcp_lun); - if (unit) { - put_device(&unit->dev); - retval = -EEXIST; - goto err_out; - } - - unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); - if (!unit) - goto err_out; - - unit->port = port; - unit->fcp_lun = fcp_lun; - unit->dev.parent = &port->dev; - unit->dev.release = zfcp_unit_release; - - if (dev_set_name(&unit->dev, "0x%016llx", - (unsigned long long) fcp_lun)) { - kfree(unit); - goto err_out; - } - retval = -EINVAL; - - INIT_WORK(&unit->scsi_work, zfcp_scsi_scan_work); - - 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->dev)) { - put_device(&unit->dev); - goto err_out; - } - - if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) - goto err_out_put; - - write_lock_irq(&port->unit_list_lock); - list_add_tail(&unit->list, &port->unit_list); - write_unlock_irq(&port->unit_list_lock); - - atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); - - return unit; - -err_out_put: - device_unregister(&unit->dev); -err_out: - put_device(&port->dev); - return ERR_PTR(retval); -} - static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) { adapter->pool.erp_req = diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index ce1cc7a..0833c2b 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -46,8 +46,7 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) if (!adapter) return 0; - zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ccresu2", NULL); zfcp_erp_wait(adapter); @@ -164,14 +163,7 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev) BUG_ON(!zfcp_reqlist_isempty(adapter->req_list)); adapter->req_no = 0; - zfcp_erp_modify_adapter_status(adapter, "ccsonl1", NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); - zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "ccsonl2", NULL); - zfcp_erp_wait(adapter); - - flush_work(&adapter->scan_work); - + zfcp_ccw_activate(cdev); zfcp_ccw_adapter_put(adapter); return 0; } @@ -224,9 +216,8 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event) break; case CIO_OPER: dev_info(&cdev->dev, "The FCP device is operational again\n"); - zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ccnoti4", NULL); break; diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index fcbd2b7..d692e22 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -2,9 +2,10 @@ * zfcp device driver * * Userspace interface for accessing the - * Access Control Lists / Control File Data Channel + * Access Control Lists / Control File Data Channel; + * handling of response code and states for ports and LUNs. * - * Copyright IBM Corporation 2008, 2009 + * Copyright IBM Corporation 2008, 2010 */ #define KMSG_COMPONENT "zfcp" @@ -251,8 +252,9 @@ static const struct file_operations zfcp_cfdc_fops = { .open = nonseekable_open, .unlocked_ioctl = zfcp_cfdc_dev_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = zfcp_cfdc_dev_ioctl + .compat_ioctl = zfcp_cfdc_dev_ioctl, #endif + .llseek = no_llseek, }; struct miscdevice zfcp_cfdc_misc = { @@ -260,3 +262,184 @@ struct miscdevice zfcp_cfdc_misc = { .name = "zfcp_cfdc", .fops = &zfcp_cfdc_fops, }; + +/** + * zfcp_cfdc_adapter_access_changed - Process change in adapter ACT + * @adapter: Adapter where the Access Control Table (ACT) changed + * + * After a change in the adapter ACT, check if access to any + * previously denied resources is now possible. + */ +void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter) +{ + unsigned long flags; + struct zfcp_port *port; + struct scsi_device *sdev; + struct zfcp_scsi_dev *zfcp_sdev; + int status; + + if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) + return; + + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) { + status = atomic_read(&port->status); + if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || + (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) + zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED, + "cfaac_1", NULL); + } + read_unlock_irqrestore(&adapter->port_list_lock, flags); + + shost_for_each_device(sdev, port->adapter->scsi_host) { + zfcp_sdev = sdev_to_zfcp(sdev); + status = atomic_read(&zfcp_sdev->status); + if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || + (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) + zfcp_erp_lun_reopen(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED, + "cfaac_2", NULL); + } +} + +static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) +{ + u16 subtable = table >> 16; + u16 rule = table & 0xffff; + const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" }; + + if (subtable && subtable < ARRAY_SIZE(act_type)) + dev_warn(&adapter->ccw_device->dev, + "Access denied according to ACT rule type %s, " + "rule %d\n", act_type[subtable], rule); +} + +/** + * zfcp_cfdc_port_denied - Process "access denied" for port + * @port: The port where the acces has been denied + * @qual: The FSF status qualifier for the access denied FSF status + */ +void zfcp_cfdc_port_denied(struct zfcp_port *port, + union fsf_status_qual *qual) +{ + dev_warn(&port->adapter->ccw_device->dev, + "Access denied to port 0x%016Lx\n", + (unsigned long long)port->wwpn); + + zfcp_act_eval_err(port->adapter, qual->halfword[0]); + zfcp_act_eval_err(port->adapter, qual->halfword[1]); + zfcp_erp_set_port_status(port, + ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED); +} + +/** + * zfcp_cfdc_lun_denied - Process "access denied" for LUN + * @sdev: The SCSI device / LUN where the access has been denied + * @qual: The FSF status qualifier for the access denied FSF status + */ +void zfcp_cfdc_lun_denied(struct scsi_device *sdev, + union fsf_status_qual *qual) +{ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev, + "Access denied to LUN 0x%016Lx on port 0x%016Lx\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->halfword[0]); + zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->halfword[1]); + zfcp_erp_set_lun_status(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED); + + atomic_clear_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); + atomic_clear_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); +} + +/** + * zfcp_cfdc_lun_shrng_vltn - Evaluate LUN sharing violation status + * @sdev: The LUN / SCSI device where sharing violation occurred + * @qual: The FSF status qualifier from the LUN sharing violation + */ +void zfcp_cfdc_lun_shrng_vltn(struct scsi_device *sdev, + union fsf_status_qual *qual) +{ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + if (qual->word[0]) + dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev, + "LUN 0x%Lx on port 0x%Lx is already in " + "use by CSS%d, MIF Image ID %x\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn, + qual->fsf_queue_designator.cssid, + qual->fsf_queue_designator.hla); + else + zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->word[2]); + + zfcp_erp_set_lun_status(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED); + atomic_clear_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); + atomic_clear_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); +} + +/** + * zfcp_cfdc_open_lun_eval - Eval access ctrl. status for successful "open lun" + * @sdev: The SCSI device / LUN where to evaluate the status + * @bottom: The qtcb bottom with the status from the "open lun" + * + * Returns: 0 if LUN is usable, -EACCES if the access control table + * reports an unsupported configuration. + */ +int zfcp_cfdc_open_lun_eval(struct scsi_device *sdev, + struct fsf_qtcb_bottom_support *bottom) +{ + int shared, rw; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; + + if ((adapter->connection_features & FSF_FEATURE_NPIV_MODE) || + !(adapter->adapter_features & FSF_FEATURE_LUN_SHARING) || + zfcp_ccw_priv_sch(adapter)) + return 0; + + shared = !(bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE); + rw = (bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER); + + if (shared) + atomic_set_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); + + if (!rw) { + atomic_set_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); + dev_info(&adapter->ccw_device->dev, "SCSI device at LUN " + "0x%016Lx on port 0x%016Lx opened read-only\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + } + + if (!shared && !rw) { + dev_err(&adapter->ccw_device->dev, "Exclusive read-only access " + "not supported (LUN 0x%016Lx, port 0x%016Lx)\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6", NULL); + return -EACCES; + } + + if (shared && rw) { + dev_err(&adapter->ccw_device->dev, + "Shared read-write access not supported " + "(LUN 0x%016Lx, port 0x%016Lx)\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8", NULL); + return -EACCES; + } + + return 0; +} diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index a86117b..2cdd6b2 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -154,7 +154,6 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level, scsi_cmnd = (struct scsi_cmnd *)fsf_req->data; if (scsi_cmnd) { response->u.fcp.cmnd = (unsigned long)scsi_cmnd; - response->u.fcp.serial = scsi_cmnd->serial_number; response->u.fcp.data_dir = qtcb->bottom.io.data_direction; } @@ -330,7 +329,6 @@ static void zfcp_dbf_hba_view_response(char **p, break; zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir); zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); - zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial); *p += sprintf(*p, "\n"); break; @@ -482,7 +480,7 @@ static int zfcp_dbf_rec_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.trigger.fcp_lun); zfcp_dbf_out(&p, "adapter_status", "0x%08x", r->u.trigger.as); zfcp_dbf_out(&p, "port_status", "0x%08x", r->u.trigger.ps); - zfcp_dbf_out(&p, "unit_status", "0x%08x", r->u.trigger.us); + zfcp_dbf_out(&p, "lun_status", "0x%08x", r->u.trigger.ls); break; case ZFCP_REC_DBF_ID_ACTION: zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.action.action); @@ -600,19 +598,20 @@ void zfcp_dbf_rec_port(char *id, void *ref, struct zfcp_port *port) } /** - * zfcp_dbf_rec_unit - trace event for unit state change + * zfcp_dbf_rec_lun - trace event for LUN state change * @id: identifier for trigger of state change * @ref: additional reference (e.g. request) - * @unit: unit + * @sdev: SCSI device */ -void zfcp_dbf_rec_unit(char *id, void *ref, struct zfcp_unit *unit) +void zfcp_dbf_rec_lun(char *id, void *ref, struct scsi_device *sdev) { - struct zfcp_port *port = unit->port; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_port *port = zfcp_sdev->port; struct zfcp_dbf *dbf = port->adapter->dbf; - zfcp_dbf_rec_target(id, ref, dbf, &unit->status, - &unit->erp_counter, port->wwpn, port->d_id, - unit->fcp_lun); + zfcp_dbf_rec_target(id, ref, dbf, &zfcp_sdev->status, + &zfcp_sdev->erp_counter, port->wwpn, port->d_id, + zfcp_scsi_dev_lun(sdev)); } /** @@ -624,11 +623,11 @@ void zfcp_dbf_rec_unit(char *id, void *ref, struct zfcp_unit *unit) * @action: address of error recovery action struct * @adapter: adapter * @port: port - * @unit: unit + * @sdev: SCSI device */ void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit) + struct scsi_device *sdev) { struct zfcp_dbf *dbf = adapter->dbf; struct zfcp_dbf_rec_record *r = &dbf->rec_buf; @@ -647,9 +646,10 @@ void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action, r->u.trigger.ps = atomic_read(&port->status); r->u.trigger.wwpn = port->wwpn; } - if (unit) - r->u.trigger.us = atomic_read(&unit->status); - r->u.trigger.fcp_lun = unit ? unit->fcp_lun : ZFCP_DBF_INVALID_LUN; + if (sdev) + r->u.trigger.ls = atomic_read(&sdev_to_zfcp(sdev)->status); + r->u.trigger.fcp_lun = sdev ? zfcp_scsi_dev_lun(sdev) : + ZFCP_DBF_INVALID_LUN; debug_event(dbf->rec, action ? 1 : 4, r, sizeof(*r)); spin_unlock_irqrestore(&dbf->rec_lock, flags); } @@ -879,7 +879,6 @@ void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level, } rec->scsi_result = scsi_cmnd->result; rec->scsi_cmnd = (unsigned long)scsi_cmnd; - rec->scsi_serial = scsi_cmnd->serial_number; memcpy(rec->scsi_opcode, scsi_cmnd->cmnd, min((int)scsi_cmnd->cmd_len, ZFCP_DBF_SCSI_OPCODE)); @@ -948,7 +947,6 @@ static int zfcp_dbf_scsi_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "scsi_lun", "0x%08x", r->scsi_lun); zfcp_dbf_out(&p, "scsi_result", "0x%08x", r->scsi_result); zfcp_dbf_out(&p, "scsi_cmnd", "0x%0Lx", r->scsi_cmnd); - zfcp_dbf_out(&p, "scsi_serial", "0x%016Lx", r->scsi_serial); zfcp_dbf_outd(&p, "scsi_opcode", r->scsi_opcode, ZFCP_DBF_SCSI_OPCODE, 0, ZFCP_DBF_SCSI_OPCODE); zfcp_dbf_out(&p, "scsi_retries", "0x%02x", r->scsi_retries); diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 2bcc340..04081b1 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -60,7 +60,7 @@ struct zfcp_dbf_rec_record_trigger { u8 need; u32 as; u32 ps; - u32 us; + u32 ls; u64 ref; u64 action; u64 wwpn; @@ -110,7 +110,6 @@ struct zfcp_dbf_hba_record_response { union { struct { u64 cmnd; - u64 serial; u32 data_dir; } fcp; struct { @@ -206,7 +205,6 @@ struct zfcp_dbf_scsi_record { u32 scsi_lun; u32 scsi_result; u64 scsi_cmnd; - u64 scsi_serial; #define ZFCP_DBF_SCSI_OPCODE 16 u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE]; u8 scsi_retries; @@ -350,16 +348,16 @@ void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf, /** * zfcp_dbf_scsi_devreset - trace event for Logical Unit or Target Reset * @tag: tag indicating success or failure of reset operation + * @scmnd: SCSI command which caused this error recovery * @flag: indicates type of reset (Target Reset, Logical Unit Reset) - * @unit: unit that needs reset - * @scsi_cmnd: SCSI command which caused this error recovery */ static inline -void zfcp_dbf_scsi_devreset(const char *tag, u8 flag, struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd) +void zfcp_dbf_scsi_devreset(const char *tag, struct scsi_cmnd *scmnd, u8 flag) { + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device); + zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1, - unit->port->adapter->dbf, scsi_cmnd, NULL, 0); + zfcp_sdev->port->adapter->dbf, scmnd, NULL, 0); } #endif /* ZFCP_DBF_H */ diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index e1c6b6e..9ae1d0a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -85,8 +85,8 @@ struct zfcp_reqlist; #define ZFCP_STATUS_PORT_LINK_TEST 0x00000002 /* logical unit status */ -#define ZFCP_STATUS_UNIT_SHARED 0x00000004 -#define ZFCP_STATUS_UNIT_READONLY 0x00000008 +#define ZFCP_STATUS_LUN_SHARED 0x00000004 +#define ZFCP_STATUS_LUN_READONLY 0x00000008 /* FSF request status (this does not have a common part) */ #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 @@ -118,7 +118,7 @@ struct zfcp_erp_action { int action; /* requested action code */ struct zfcp_adapter *adapter; /* device which should be recovered */ struct zfcp_port *port; - struct zfcp_unit *unit; + struct scsi_device *sdev; u32 status; /* recovery status */ u32 step; /* active step of this erp action */ unsigned long fsf_req_id; @@ -219,21 +219,66 @@ struct zfcp_port { unsigned int starget_id; }; +/** + * struct zfcp_unit - LUN configured via zfcp sysfs + * @dev: struct device for sysfs representation and reference counting + * @list: entry in LUN/unit list per zfcp_port + * @port: reference to zfcp_port where this LUN is configured + * @fcp_lun: 64 bit LUN value + * @scsi_work: for running scsi_scan_target + * + * This is the representation of a LUN that has been configured for + * usage. The main data here is the 64 bit LUN value, data for + * running I/O and recovery is in struct zfcp_scsi_dev. + */ struct zfcp_unit { - struct device dev; - struct list_head list; /* list of logical units */ - struct zfcp_port *port; /* remote port of unit */ - atomic_t status; /* status of this logical unit */ - u64 fcp_lun; /* own FCP_LUN */ - u32 handle; /* handle assigned by FSF */ - 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; + struct device dev; + struct list_head list; + struct zfcp_port *port; + u64 fcp_lun; struct work_struct scsi_work; }; /** + * struct zfcp_scsi_dev - zfcp data per SCSI device + * @status: zfcp internal status flags + * @lun_handle: handle from "open lun" for issuing FSF requests + * @erp_action: zfcp erp data for opening and recovering this LUN + * @erp_counter: zfcp erp counter for this LUN + * @latencies: FSF channel and fabric latencies + * @port: zfcp_port where this LUN belongs to + */ +struct zfcp_scsi_dev { + atomic_t status; + u32 lun_handle; + struct zfcp_erp_action erp_action; + atomic_t erp_counter; + struct zfcp_latencies latencies; + struct zfcp_port *port; +}; + +/** + * sdev_to_zfcp - Access zfcp LUN data for SCSI device + * @sdev: scsi_device where to get the zfcp_scsi_dev pointer + */ +static inline struct zfcp_scsi_dev *sdev_to_zfcp(struct scsi_device *sdev) +{ + return scsi_transport_device_data(sdev); +} + +/** + * zfcp_scsi_dev_lun - Return SCSI device LUN as 64 bit FCP LUN + * @sdev: SCSI device where to get the LUN from + */ +static inline u64 zfcp_scsi_dev_lun(struct scsi_device *sdev) +{ + u64 fcp_lun; + + int_to_scsilun(sdev->lun, (struct scsi_lun *)&fcp_lun); + return fcp_lun; +} + +/** * struct zfcp_fsf_req - basic FSF request structure * @list: list of FSF requests * @req_id: unique request ID @@ -249,7 +294,6 @@ struct zfcp_unit { * @erp_action: reference to erp action if request issued on behalf of ERP * @pool: reference to memory pool if used for this request * @issued: time when request was send (STCK) - * @unit: reference to unit if this request is a SCSI request * @handler: handler which should be called to process response */ struct zfcp_fsf_req { @@ -267,7 +311,6 @@ struct zfcp_fsf_req { struct zfcp_erp_action *erp_action; mempool_t *pool; unsigned long long issued; - struct zfcp_unit *unit; void (*handler)(struct zfcp_fsf_req *); }; @@ -282,9 +325,4 @@ struct zfcp_data { struct kmem_cache *adisc_cache; }; -/********************** ZFCP SPECIFIC DEFINES ********************************/ - -#define ZFCP_SET 0x00000100 -#define ZFCP_CLEAR 0x00000200 - #endif /* ZFCP_DEF_H */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 160b432..d37c733 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -21,6 +21,7 @@ enum zfcp_erp_act_flags { ZFCP_STATUS_ERP_DISMISSING = 0x00100000, ZFCP_STATUS_ERP_DISMISSED = 0x00200000, ZFCP_STATUS_ERP_LOWMEM = 0x00400000, + ZFCP_STATUS_ERP_NO_REF = 0x00800000, }; enum zfcp_erp_steps { @@ -29,12 +30,12 @@ enum zfcp_erp_steps { ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, ZFCP_ERP_STEP_PORT_OPENING = 0x0800, - ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, - ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, + ZFCP_ERP_STEP_LUN_CLOSING = 0x1000, + ZFCP_ERP_STEP_LUN_OPENING = 0x2000, }; enum zfcp_erp_act_type { - ZFCP_ERP_ACTION_REOPEN_UNIT = 1, + ZFCP_ERP_ACTION_REOPEN_LUN = 1, ZFCP_ERP_ACTION_REOPEN_PORT = 2, ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, @@ -56,9 +57,8 @@ enum zfcp_erp_act_result { static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) { - zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | mask, - ZFCP_CLEAR); + zfcp_erp_clear_adapter_status(adapter, + ZFCP_STATUS_COMMON_UNBLOCKED | mask); } static int zfcp_erp_action_exists(struct zfcp_erp_action *act) @@ -88,24 +88,24 @@ static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) zfcp_erp_action_ready(act); } -static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) +static void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev) { - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) - zfcp_erp_action_dismiss(&unit->erp_action); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE) + zfcp_erp_action_dismiss(&zfcp_sdev->erp_action); } static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) { - struct zfcp_unit *unit; + struct scsi_device *sdev; if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) zfcp_erp_action_dismiss(&port->erp_action); - else { - read_lock(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) - zfcp_erp_action_dismiss_unit(unit); - read_unlock(&port->unit_list_lock); - } + else + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + zfcp_erp_action_dismiss_lun(sdev); } static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) @@ -124,15 +124,17 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit) + struct scsi_device *sdev) { int need = want; - int u_status, p_status, a_status; + int l_status, p_status, a_status; + struct zfcp_scsi_dev *zfcp_sdev; switch (want) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - u_status = atomic_read(&unit->status); - if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + l_status = atomic_read(&zfcp_sdev->status); + if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE) return 0; p_status = atomic_read(&port->status); if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || @@ -169,22 +171,26 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, return need; } -static struct zfcp_erp_action *zfcp_erp_setup_act(int need, +static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit) + struct scsi_device *sdev) { struct zfcp_erp_action *erp_action; - u32 status = 0; + struct zfcp_scsi_dev *zfcp_sdev; switch (need) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (!get_device(&unit->dev)) - return NULL; - 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; + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + if (!(act_status & ZFCP_STATUS_ERP_NO_REF)) + if (scsi_device_get(sdev)) + return NULL; + atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + &zfcp_sdev->status); + erp_action = &zfcp_sdev->erp_action; + if (!(atomic_read(&zfcp_sdev->status) & + ZFCP_STATUS_COMMON_RUNNING)) + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; case ZFCP_ERP_ACTION_REOPEN_PORT: @@ -195,7 +201,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, 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; + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: @@ -205,7 +211,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, erp_action = &adapter->erp_action; if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; default: @@ -215,16 +221,17 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, memset(erp_action, 0, sizeof(struct zfcp_erp_action)); erp_action->adapter = adapter; erp_action->port = port; - erp_action->unit = unit; + erp_action->sdev = sdev; erp_action->action = need; - erp_action->status = status; + erp_action->status = act_status; return erp_action; } static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit, char *id, void *ref) + struct scsi_device *sdev, + char *id, void *ref, u32 act_status) { int retval = 1, need; struct zfcp_erp_action *act = NULL; @@ -232,21 +239,21 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, if (!adapter->erp_thread) return -EIO; - need = zfcp_erp_required_act(want, adapter, port, unit); + need = zfcp_erp_required_act(want, adapter, port, sdev); if (!need) goto out; - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); - act = zfcp_erp_setup_act(need, adapter, port, unit); + act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); if (!act) goto out; + atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); wake_up(&adapter->erp_ready_wq); zfcp_dbf_rec_thread("eracte1", adapter->dbf); retval = 0; out: - zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, unit); + zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev); return retval; } @@ -258,11 +265,12 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, /* ensure propagation of failed status to new devices */ if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_erp_adapter_failed(adapter, "erareo1", NULL); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); return -EIO; } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, - adapter, NULL, NULL, id, ref); + adapter, NULL, NULL, id, ref, 0); } /** @@ -282,10 +290,11 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, write_lock_irqsave(&adapter->erp_lock, flags); if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - zfcp_erp_adapter_failed(adapter, "erareo1", NULL); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); else zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, - NULL, NULL, id, ref); + NULL, NULL, id, ref, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } @@ -317,25 +326,10 @@ void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, 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, char *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, "erpblk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | clear, - ZFCP_CLEAR); + zfcp_erp_clear_port_status(port, + ZFCP_STATUS_COMMON_UNBLOCKED | clear); } static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, @@ -348,7 +342,7 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, return; zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, - port->adapter, port, NULL, id, ref); + port->adapter, port, NULL, id, ref, 0); } /** @@ -376,12 +370,12 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { /* ensure propagation of failed status to new devices */ - zfcp_erp_port_failed(port, "erpreo1", NULL); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); return -EIO; } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, - port->adapter, port, NULL, id, ref); + port->adapter, port, NULL, id, ref, 0); } /** @@ -404,53 +398,88 @@ int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) return retval; } -static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) +static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask) { - zfcp_erp_modify_unit_status(unit, "erublk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, - ZFCP_CLEAR); + zfcp_erp_clear_lun_status(sdev, + ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask); } -static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, - void *ref) +static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, + void *ref, u32 act_status) { - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; - zfcp_erp_unit_block(unit, clear); + zfcp_erp_lun_block(sdev, clear); - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) return; - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, - adapter, unit->port, unit, id, ref); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, + zfcp_sdev->port, sdev, id, ref, act_status); } /** - * zfcp_erp_unit_reopen - initiate reopen of a unit - * @unit: unit to be reopened - * @clear_mask: specifies flags in unit status to be cleared + * zfcp_erp_lun_reopen - initiate reopen of a LUN + * @sdev: SCSI device / LUN to be reopened + * @clear_mask: specifies flags in LUN status to be cleared * Return: 0 on success, < 0 on error */ -void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, - void *ref) +void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, + void *ref) { unsigned long flags; - struct zfcp_port *port = unit->port; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_port *port = zfcp_sdev->port; struct zfcp_adapter *adapter = port->adapter; write_lock_irqsave(&adapter->erp_lock, flags); - _zfcp_erp_unit_reopen(unit, clear, id, ref); + _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } -static int status_change_set(unsigned long mask, atomic_t *status) +/** + * zfcp_erp_lun_shutdown - Shutdown LUN + * @sdev: SCSI device / LUN to shut down. + * @clear: Status flags to clear. + * @id: Id for debug trace event. + * @ref: Reference for debug trace event. + */ +void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id, + void *ref) { - return (atomic_read(status) ^ mask) & mask; + int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + zfcp_erp_lun_reopen(sdev, clear | flags, id, ref); } -static int status_change_clear(unsigned long mask, atomic_t *status) +/** + * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion + * @sdev: SCSI device / LUN to shut down. + * @id: Id for debug trace event. + * + * Do not acquire a reference for the LUN when creating the ERP + * action. It is safe, because this function waits for the ERP to + * complete first. This allows to shutdown the LUN, even when the SCSI + * device is in the state SDEV_DEL when scsi_device_get will fail. + */ +void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id) { - return atomic_read(status) & mask; + unsigned long flags; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_port *port = zfcp_sdev->port; + struct zfcp_adapter *adapter = port->adapter; + int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + + write_lock_irqsave(&adapter->erp_lock, flags); + _zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF); + write_unlock_irqrestore(&adapter->erp_lock, flags); + + zfcp_erp_wait(adapter); +} + +static int status_change_set(unsigned long mask, atomic_t *status) +{ + return (atomic_read(status) ^ mask) & mask; } static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) @@ -467,11 +496,13 @@ static void zfcp_erp_port_unblock(struct zfcp_port *port) atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } -static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) +static void zfcp_erp_lun_unblock(struct scsi_device *sdev) { - if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) - zfcp_dbf_rec_unit("eruubl1", NULL, unit); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status)) + zfcp_dbf_rec_lun("erlubl1", NULL, sdev); + atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); } static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) @@ -559,15 +590,14 @@ static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, read_unlock(&adapter->port_list_lock); } -static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, - char *id, void *ref) +static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear, + char *id, void *ref) { - struct zfcp_unit *unit; + struct scsi_device *sdev; - read_lock(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) - _zfcp_erp_unit_reopen(unit, clear, id, ref); - read_unlock(&port->unit_list_lock); + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0); } static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) @@ -582,8 +612,8 @@ static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) case ZFCP_ERP_ACTION_REOPEN_PORT: _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); break; - case ZFCP_ERP_ACTION_REOPEN_UNIT: - _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL); + case ZFCP_ERP_ACTION_REOPEN_LUN: + _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0); break; } } @@ -598,7 +628,7 @@ static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL); break; case ZFCP_ERP_ACTION_REOPEN_PORT: - _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL); + _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL); break; } } @@ -742,9 +772,8 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) zfcp_fsf_req_dismiss_all(adapter); adapter->fsf_req_seq_no = 0; zfcp_fc_wka_ports_force_offline(adapter->gs); - /* all ports and units are closed */ - zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, - ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); + /* all ports and LUNs are closed */ + zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN); atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); @@ -861,7 +890,7 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) struct zfcp_port *port = act->port; if (port->wwpn != adapter->peer_wwpn) { - zfcp_erp_port_failed(port, "eroptp1", NULL); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); return ZFCP_ERP_FAILED; } port->d_id = adapter->peer_d_id; @@ -933,82 +962,87 @@ close_init_done: return zfcp_erp_port_strategy_open_common(erp_action); } -static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) +static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev) { + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_UNIT_SHARED | - ZFCP_STATUS_UNIT_READONLY, - &unit->status); + ZFCP_STATUS_LUN_SHARED | ZFCP_STATUS_LUN_READONLY, + &zfcp_sdev->status); } -static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy_close(struct zfcp_erp_action *erp_action) { - int retval = zfcp_fsf_close_unit(erp_action); + int retval = zfcp_fsf_close_lun(erp_action); if (retval == -ENOMEM) return ZFCP_ERP_NOMEM; - erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; + erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING; if (retval) return ZFCP_ERP_FAILED; return ZFCP_ERP_CONTINUES; } -static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy_open(struct zfcp_erp_action *erp_action) { - int retval = zfcp_fsf_open_unit(erp_action); + int retval = zfcp_fsf_open_lun(erp_action); if (retval == -ENOMEM) return ZFCP_ERP_NOMEM; - erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; + erp_action->step = ZFCP_ERP_STEP_LUN_OPENING; if (retval) return ZFCP_ERP_FAILED; return ZFCP_ERP_CONTINUES; } -static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy(struct zfcp_erp_action *erp_action) { - struct zfcp_unit *unit = erp_action->unit; + struct scsi_device *sdev = erp_action->sdev; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 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); + zfcp_erp_lun_strategy_clearstati(sdev); + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) + return zfcp_erp_lun_strategy_close(erp_action); /* already closed, fall through */ - case ZFCP_ERP_STEP_UNIT_CLOSING: - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + case ZFCP_ERP_STEP_LUN_CLOSING: + if (atomic_read(&zfcp_sdev->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); + return zfcp_erp_lun_strategy_open(erp_action); - case ZFCP_ERP_STEP_UNIT_OPENING: - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + case ZFCP_ERP_STEP_LUN_OPENING: + if (atomic_read(&zfcp_sdev->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_lun(struct scsi_device *sdev, int result) { + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + switch (result) { case ZFCP_ERP_SUCCEEDED : - atomic_set(&unit->erp_counter, 0); - zfcp_erp_unit_unblock(unit); + atomic_set(&zfcp_sdev->erp_counter, 0); + zfcp_erp_lun_unblock(sdev); break; case ZFCP_ERP_FAILED : - atomic_inc(&unit->erp_counter); - if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { - dev_err(&unit->port->adapter->ccw_device->dev, - "ERP failed for unit 0x%016Lx on " + atomic_inc(&zfcp_sdev->erp_counter); + if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) { + dev_err(&zfcp_sdev->port->adapter->ccw_device->dev, + "ERP failed for LUN 0x%016Lx on " "port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "erusck1", NULL); + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_erp_unit_block(unit, 0); + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + zfcp_erp_lun_block(sdev, 0); result = ZFCP_ERP_EXIT; } return result; @@ -1032,7 +1066,8 @@ static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) dev_err(&port->adapter->ccw_device->dev, "ERP failed for remote port 0x%016Lx\n", (unsigned long long)port->wwpn); - zfcp_erp_port_failed(port, "erpsck1", NULL); + zfcp_erp_set_port_status(port, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } @@ -1059,7 +1094,8 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, dev_err(&adapter->ccw_device->dev, "ERP cannot recover an error " "on the FCP device\n"); - zfcp_erp_adapter_failed(adapter, "erasck1", NULL); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } @@ -1076,12 +1112,12 @@ static int zfcp_erp_strategy_check_target(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; + struct scsi_device *sdev = erp_action->sdev; switch (erp_action->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - result = zfcp_erp_strategy_check_unit(unit, result); + case ZFCP_ERP_ACTION_REOPEN_LUN: + result = zfcp_erp_strategy_check_lun(sdev, result); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: @@ -1116,7 +1152,8 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) int action = act->action; struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; - struct zfcp_unit *unit = act->unit; + struct scsi_device *sdev = act->sdev; + struct zfcp_scsi_dev *zfcp_sdev; u32 erp_status = act->status; switch (action) { @@ -1139,11 +1176,12 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) } break; - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { - _zfcp_erp_unit_reopen(unit, - ZFCP_STATUS_COMMON_ERP_FAILED, - "ersscg3", NULL); + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) { + _zfcp_erp_lun_reopen(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED, + "ersscg3", NULL, 0); return ZFCP_ERP_EXIT; } break; @@ -1154,6 +1192,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_scsi_dev *zfcp_sdev; adapter->erp_total_count--; if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { @@ -1165,9 +1204,10 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) zfcp_dbf_rec_action("eractd1", erp_action); switch (erp_action->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(erp_action->sdev); atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, - &erp_action->unit->status); + &zfcp_sdev->status); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: @@ -1187,11 +1227,12 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) { struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; - struct zfcp_unit *unit = act->unit; + struct scsi_device *sdev = act->sdev; switch (act->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - put_device(&unit->dev); + case ZFCP_ERP_ACTION_REOPEN_LUN: + if (!(act->status & ZFCP_STATUS_ERP_NO_REF)) + scsi_device_put(sdev); break; case ZFCP_ERP_ACTION_REOPEN_PORT: @@ -1222,8 +1263,8 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) 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); + case ZFCP_ERP_ACTION_REOPEN_LUN: + return zfcp_erp_lun_strategy(erp_action); } return ZFCP_ERP_FAILED; } @@ -1376,42 +1417,6 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) } /** - * 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, char *id, void *ref) -{ - zfcp_erp_modify_adapter_status(adapter, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); -} - -/** - * 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, char *id, void *ref) -{ - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); -} - -/** - * zfcp_erp_unit_failed - Set unit status to failed. - * @unit: Failed unit. - * @id: Event id for debug trace. - * @ref: Reference for debug trace. - */ -void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref) -{ - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); -} - -/** * zfcp_erp_wait - wait for completion of error recovery on an adapter * @adapter: adapter for which to wait for completion of its error recovery */ @@ -1423,210 +1428,148 @@ void zfcp_erp_wait(struct zfcp_adapter *adapter) } /** - * zfcp_erp_modify_adapter_status - change adapter status bits + * zfcp_erp_set_adapter_status - set 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. + * Changes in common status bits are propagated to attached ports and LUNs. */ -void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, - void *ref, u32 mask, int set_or_clear) +void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask) { struct zfcp_port *port; + struct scsi_device *sdev; unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &adapter->status)) - zfcp_dbf_rec_adapter(id, ref, adapter->dbf); - atomic_set_mask(mask, &adapter->status); - } else { - if (status_change_clear(mask, &adapter->status)) - zfcp_dbf_rec_adapter(id, ref, adapter->dbf); - atomic_clear_mask(mask, &adapter->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) - atomic_set(&adapter->erp_counter, 0); - } + atomic_set_mask(mask, &adapter->status); - if (common_mask) { - read_lock_irqsave(&adapter->port_list_lock, flags); - list_for_each_entry(port, &adapter->port_list, list) - zfcp_erp_modify_port_status(port, id, ref, common_mask, - set_or_clear); - read_unlock_irqrestore(&adapter->port_list_lock, flags); - } + if (!common_mask) + return; + + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) + atomic_set_mask(common_mask, &port->status); + read_unlock_irqrestore(&adapter->port_list_lock, flags); + + shost_for_each_device(sdev, adapter->scsi_host) + atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status); } /** - * 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 + * zfcp_erp_clear_adapter_status - clear adapter status bits + * @adapter: adapter to change the status * @mask: status bits to change - * @set_or_clear: ZFCP_SET or ZFCP_CLEAR * - * Changes in common status bits are propagated to attached units. + * Changes in common status bits are propagated to attached ports and LUNs. */ -void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, - u32 mask, int set_or_clear) +void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) { - struct zfcp_unit *unit; + struct zfcp_port *port; + struct scsi_device *sdev; unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; + u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; + + atomic_clear_mask(mask, &adapter->status); + + if (!common_mask) + return; + + if (clear_counter) + atomic_set(&adapter->erp_counter, 0); - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &port->status)) - zfcp_dbf_rec_port(id, ref, port); - atomic_set_mask(mask, &port->status); - } else { - if (status_change_clear(mask, &port->status)) - zfcp_dbf_rec_port(id, ref, port); - atomic_clear_mask(mask, &port->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) { + atomic_clear_mask(common_mask, &port->status); + if (clear_counter) atomic_set(&port->erp_counter, 0); } + read_unlock_irqrestore(&adapter->port_list_lock, flags); - if (common_mask) { - read_lock_irqsave(&port->unit_list_lock, flags); - list_for_each_entry(unit, &port->unit_list, list) - zfcp_erp_modify_unit_status(unit, id, ref, common_mask, - set_or_clear); - read_unlock_irqrestore(&port->unit_list_lock, flags); + shost_for_each_device(sdev, adapter->scsi_host) { + atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status); + if (clear_counter) + atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); } } /** - * 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 + * zfcp_erp_set_port_status - set port status bits + * @port: port to change the status * @mask: status bits to change - * @set_or_clear: ZFCP_SET or ZFCP_CLEAR - */ -void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, - u32 mask, int set_or_clear) -{ - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &unit->status)) - zfcp_dbf_rec_unit(id, ref, unit); - atomic_set_mask(mask, &unit->status); - } else { - if (status_change_clear(mask, &unit->status)) - zfcp_dbf_rec_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. + * + * Changes in common status bits are propagated to attached LUNs. */ -void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref) +void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) { - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); -} + struct scsi_device *sdev; + u32 common_mask = mask & ZFCP_COMMON_FLAGS; -/** - * 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, char *id, void *ref) -{ - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); -} + atomic_set_mask(mask, &port->status); -/** - * 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, char *id, void *ref) -{ - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED | - ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); + if (!common_mask) + return; + + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_set_mask(common_mask, + &sdev_to_zfcp(sdev)->status); } /** - * 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 + * zfcp_erp_clear_port_status - clear port status bits + * @port: adapter to change the status + * @mask: status bits to change * - * Since the adapter has denied access, stop using the unit. + * Changes in common status bits are propagated to attached LUNs. */ -void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref) +void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) { - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED | - ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); -} + struct scsi_device *sdev; + u32 common_mask = mask & ZFCP_COMMON_FLAGS; + u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; -static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id, - void *ref) -{ - int status = atomic_read(&unit->status); - if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_COMMON_ACCESS_BOXED))) + atomic_clear_mask(mask, &port->status); + + if (!common_mask) return; - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); + if (clear_counter) + atomic_set(&port->erp_counter, 0); + + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) { + atomic_clear_mask(common_mask, + &sdev_to_zfcp(sdev)->status); + if (clear_counter) + atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); + } } -static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, - void *ref) +/** + * zfcp_erp_set_lun_status - set lun status bits + * @sdev: SCSI device / lun to set the status bits + * @mask: status bits to change + */ +void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask) { - struct zfcp_unit *unit; - unsigned long flags; - int status = atomic_read(&port->status); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_COMMON_ACCESS_BOXED))) { - read_lock_irqsave(&port->unit_list_lock, flags); - list_for_each_entry(unit, &port->unit_list, list) - zfcp_erp_unit_access_changed(unit, id, ref); - read_unlock_irqrestore(&port->unit_list_lock, flags); - return; - } - - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); + atomic_set_mask(mask, &zfcp_sdev->status); } /** - * 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 + * zfcp_erp_clear_lun_status - clear lun status bits + * @sdev: SCSi device / lun to clear the status bits + * @mask: status bits to change */ -void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id, - void *ref) +void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask) { - unsigned long flags; - struct zfcp_port *port; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) - return; + atomic_clear_mask(mask, &zfcp_sdev->status); - read_lock_irqsave(&adapter->port_list_lock, flags); - list_for_each_entry(port, &adapter->port_list, list) - zfcp_erp_port_access_changed(port, id, ref); - read_unlock_irqrestore(&adapter->port_list_lock, flags); + if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) + atomic_set(&zfcp_sdev->erp_counter, 0); } + diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 3b93239..bf8f3e5 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -15,12 +15,10 @@ #include "zfcp_fc.h" /* zfcp_aux.c */ -extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, u32); -extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64); extern void zfcp_sg_free_table(struct scatterlist *, int); extern int zfcp_sg_setup_table(struct scatterlist *, int); extern void zfcp_device_unregister(struct device *, @@ -36,6 +34,14 @@ extern void zfcp_ccw_adapter_put(struct zfcp_adapter *); /* zfcp_cfdc.c */ extern struct miscdevice zfcp_cfdc_misc; +extern void zfcp_cfdc_port_denied(struct zfcp_port *, union fsf_status_qual *); +extern void zfcp_cfdc_lun_denied(struct scsi_device *, union fsf_status_qual *); +extern void zfcp_cfdc_lun_shrng_vltn(struct scsi_device *, + union fsf_status_qual *); +extern int zfcp_cfdc_open_lun_eval(struct scsi_device *, + struct fsf_qtcb_bottom_support *); +extern void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *); + /* zfcp_dbf.c */ extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); @@ -44,10 +50,10 @@ extern void zfcp_dbf_rec_thread(char *, struct zfcp_dbf *); extern void zfcp_dbf_rec_thread_lock(char *, struct zfcp_dbf *); extern void zfcp_dbf_rec_adapter(char *, void *, struct zfcp_dbf *); extern void zfcp_dbf_rec_port(char *, void *, struct zfcp_port *); -extern void zfcp_dbf_rec_unit(char *, void *, struct zfcp_unit *); +extern void zfcp_dbf_rec_lun(char *, void *, struct scsi_device *); extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *, struct zfcp_adapter *, struct zfcp_port *, - struct zfcp_unit *); + struct scsi_device *); extern void zfcp_dbf_rec_action(char *, struct zfcp_erp_action *); extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *, struct zfcp_dbf *); @@ -65,34 +71,26 @@ extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *, unsigned long); /* zfcp_erp.c */ -extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, char *, - void *, u32, int); +extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); +extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32); extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *, void *); extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *, void *); -extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, char *, void *); -extern void zfcp_erp_modify_port_status(struct zfcp_port *, char *, void *, u32, - int); +extern void zfcp_erp_set_port_status(struct zfcp_port *, u32); +extern void zfcp_erp_clear_port_status(struct zfcp_port *, u32); extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *, void *); extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *, void *); extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *, void *); -extern void zfcp_erp_port_failed(struct zfcp_port *, char *, void *); -extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, char *, void *, u32, - int); -extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, char *, void *); -extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, char *, void *); -extern void zfcp_erp_unit_failed(struct zfcp_unit *, char *, void *); +extern void zfcp_erp_set_lun_status(struct scsi_device *, u32); +extern void zfcp_erp_clear_lun_status(struct scsi_device *, u32); +extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *, void *); +extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *, void *); +extern void zfcp_erp_lun_shutdown_wait(struct scsi_device *, char *); 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 *, char *, void *); -extern void zfcp_erp_unit_boxed(struct zfcp_unit *, char *, void *); -extern void zfcp_erp_port_access_denied(struct zfcp_port *, char *, void *); -extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, char *, void *); -extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, - void *); extern void zfcp_erp_timeout_handler(unsigned long); /* zfcp_fc.c */ @@ -118,8 +116,8 @@ extern int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *); extern int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *); 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_open_lun(struct zfcp_erp_action *); +extern int zfcp_fsf_close_lun(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_qdio *, struct fsf_qtcb_bottom_config *); @@ -135,12 +133,10 @@ extern int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *, struct zfcp_fsf_ct_els *, mempool_t *, unsigned int); extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32, struct zfcp_fsf_ct_els *, unsigned int); -extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *, - struct scsi_cmnd *); +extern int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); -extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8); -extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, - struct zfcp_unit *); +extern struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *, u8); +extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *); extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int); /* zfcp_qdio.c */ @@ -163,8 +159,6 @@ extern void zfcp_scsi_rport_work(struct work_struct *); extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); -extern void zfcp_scsi_scan(struct zfcp_unit *); -extern void zfcp_scsi_scan_work(struct work_struct *); extern void zfcp_scsi_set_prot(struct zfcp_adapter *); extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int); @@ -175,4 +169,13 @@ extern struct attribute_group zfcp_sysfs_port_attrs; extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; extern struct device_attribute *zfcp_sysfs_shost_attrs[]; +/* zfcp_unit.c */ +extern int zfcp_unit_add(struct zfcp_port *, u64); +extern int zfcp_unit_remove(struct zfcp_port *, u64); +extern struct zfcp_unit *zfcp_unit_find(struct zfcp_port *, u64); +extern struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit); +extern void zfcp_unit_scsi_scan(struct zfcp_unit *); +extern void zfcp_unit_queue_scsi_scan(struct zfcp_port *); +extern unsigned int zfcp_unit_sdev_status(struct zfcp_unit *); + #endif /* ZFCP_EXT_H */ diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 6f3ed2b..86fd905 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -365,7 +365,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work) } if (!port->d_id) { - zfcp_erp_port_failed(port, "fcgpn_2", NULL); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); goto out; } diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9d1d7d1..beaf091 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -61,45 +61,6 @@ static u32 fsf_qtcb_type[] = { [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND }; -static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) -{ - u16 subtable = table >> 16; - u16 rule = table & 0xffff; - const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" }; - - if (subtable && subtable < ARRAY_SIZE(act_type)) - dev_warn(&adapter->ccw_device->dev, - "Access denied according to ACT rule type %s, " - "rule %d\n", act_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 to port 0x%016Lx\n", - (unsigned long long)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, "fspad_1", 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 to unit 0x%016Lx on port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)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, "fsuad_1", 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, "FCP device not " @@ -143,7 +104,7 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) read_unlock_irqrestore(&adapter->port_list_lock, flags); } -static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, +static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, struct fsf_link_down_info *link_down) { struct zfcp_adapter *adapter = req->adapter; @@ -223,7 +184,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, "the FC fabric is down\n"); } out: - zfcp_erp_adapter_failed(adapter, id, req); + zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); } static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) @@ -234,13 +195,13 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) switch (sr_buf->status_subtype) { case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: - zfcp_fsf_link_down_info_eval(req, "fssrld1", ldi); + zfcp_fsf_link_down_info_eval(req, ldi); break; case FSF_STATUS_READ_SUB_FDISC_FAILED: - zfcp_fsf_link_down_info_eval(req, "fssrld2", ldi); + zfcp_fsf_link_down_info_eval(req, ldi); break; case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: - zfcp_fsf_link_down_info_eval(req, "fssrld3", NULL); + zfcp_fsf_link_down_info_eval(req, NULL); }; } @@ -281,9 +242,8 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) dev_info(&adapter->ccw_device->dev, "The local link has been restored\n"); /* All ports should be marked as ready to run again */ - zfcp_erp_modify_adapter_status(adapter, "fssrh_1", NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, @@ -293,13 +253,12 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *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, "fssrh_3", - req); + zfcp_cfdc_adapter_access_changed(adapter); if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) queue_work(adapter->work_queue, &adapter->scan_work); break; case FSF_STATUS_READ_CFDC_UPDATED: - zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req); + zfcp_cfdc_adapter_access_changed(adapter); break; case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: adapter->adapter_features = sr_buf->payload.word[0]; @@ -399,16 +358,14 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req); break; case FSF_PROT_LINK_DOWN: - zfcp_fsf_link_down_info_eval(req, "fspse_5", - &psq->link_down_info); + zfcp_fsf_link_down_info_eval(req, &psq->link_down_info); /* go through reopen to flush pending requests */ zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req); break; case FSF_PROT_REEST_QUEUE: /* All ports should be marked as ready to run again */ - zfcp_erp_modify_adapter_status(adapter, "fspse_7", NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, @@ -578,7 +535,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); - zfcp_fsf_link_down_info_eval(req, "fsecdh2", + zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); break; default: @@ -644,7 +601,7 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: zfcp_fsf_exchange_port_evaluate(req); - zfcp_fsf_link_down_info_eval(req, "fsepdh1", + zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); break; } @@ -771,7 +728,7 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio) struct fsf_status_read_buffer *sr_buf; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -805,13 +762,14 @@ failed_buf: zfcp_fsf_req_free(req); zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) { - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) @@ -820,14 +778,15 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { - zfcp_erp_adapter_reopen(unit->port->adapter, 0, + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fsafch1", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; case FSF_LUN_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { - zfcp_erp_port_reopen(unit->port, 0, "fsafch2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; @@ -835,17 +794,23 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fsafch3", req); + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_BOXED: - zfcp_erp_unit_boxed(unit, "fsafch4", req); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, + "fsafch4", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (fsq->word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -859,19 +824,20 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) } /** - * zfcp_fsf_abort_fcp_command - abort running SCSI command - * @old_req_id: unsigned long - * @unit: pointer to struct zfcp_unit + * zfcp_fsf_abort_fcp_cmnd - abort running SCSI command + * @scmnd: The SCSI command to abort * Returns: pointer to struct zfcp_fsf_req */ -struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, - struct zfcp_unit *unit) +struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd) { struct zfcp_fsf_req *req = NULL; - struct zfcp_qdio *qdio = unit->port->adapter->qdio; + struct scsi_device *sdev = scmnd->device; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio; + unsigned long old_req_id = (unsigned long) scmnd->host_scribble; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND, @@ -882,16 +848,16 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, goto out; } - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) goto out_error_free; zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); - req->data = unit; + req->data = zfcp_sdev; 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->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->port->handle; req->qtcb->bottom.support.req_handle = (u64) old_req_id; zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); @@ -902,7 +868,7 @@ out_error_free: zfcp_fsf_req_free(req); req = NULL; out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return req; } @@ -1041,7 +1007,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, struct zfcp_fsf_req *req; int ret = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1073,7 +1039,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, failed_send: zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return ret; } @@ -1111,8 +1077,10 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) case FSF_RESPONSE_SIZE_TOO_LARGE: break; case FSF_ACCESS_DENIED: - if (port) - zfcp_fsf_access_denied_port(req, port); + if (port) { + zfcp_cfdc_port_denied(port, &header->fsf_status_qual); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + } break; case FSF_SBAL_MISMATCH: /* should never occure, avoided in zfcp_fsf_send_els */ @@ -1137,7 +1105,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, struct zfcp_qdio *qdio = adapter->qdio; int ret = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1173,7 +1141,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, failed_send: zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return ret; } @@ -1183,7 +1151,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) struct zfcp_qdio *qdio = erp_action->adapter->qdio; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1215,7 +1183,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1225,7 +1193,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, struct zfcp_fsf_req *req = NULL; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out_unlock; @@ -1251,7 +1219,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); if (!retval) wait_for_completion(&req->completion); @@ -1259,7 +1227,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, return retval; out_unlock: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1277,7 +1245,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1304,7 +1272,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1323,7 +1291,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out_unlock; @@ -1343,7 +1311,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, req->handler = zfcp_fsf_exchange_port_data_handler; zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); if (!retval) wait_for_completion(&req->completion); @@ -1353,7 +1321,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, return retval; out_unlock: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1370,14 +1338,16 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) case FSF_PORT_ALREADY_OPEN: break; case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(req, port); + zfcp_cfdc_port_denied(port, &header->fsf_status_qual); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: dev_warn(&req->adapter->ccw_device->dev, "Not enough FCP adapter resources to open " "remote port 0x%016Lx\n", (unsigned long long)port->wwpn); - zfcp_erp_port_failed(port, "fsoph_1", req); + zfcp_erp_set_port_status(port, + ZFCP_STATUS_COMMON_ERP_FAILED); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1437,7 +1407,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1468,7 +1438,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) put_device(&port->dev); } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1487,9 +1457,7 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: break; case FSF_GOOD: - zfcp_erp_modify_port_status(port, "fscph_2", req, - ZFCP_STATUS_COMMON_OPEN, - ZFCP_CLEAR); + zfcp_erp_clear_port_status(port, ZFCP_STATUS_COMMON_OPEN); break; } } @@ -1505,7 +1473,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1534,7 +1502,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1580,7 +1548,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1605,7 +1573,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) if (retval) zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1633,7 +1601,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1658,7 +1626,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) if (retval) zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1666,7 +1634,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) { struct zfcp_port *port = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; - struct zfcp_unit *unit; + struct scsi_device *sdev; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; @@ -1677,18 +1645,19 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(req, port); + zfcp_cfdc_port_denied(port, &header->fsf_status_qual); break; case FSF_PORT_BOXED: /* 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); - read_lock(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, - &unit->status); - read_unlock(&port->unit_list_lock); - zfcp_erp_port_boxed(port, "fscpph2", req); + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + &sdev_to_zfcp(sdev)->status); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, + "fscpph2", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1705,11 +1674,10 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - read_lock(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, - &unit->status); - read_unlock(&port->unit_list_lock); + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + &sdev_to_zfcp(sdev)->status); break; } } @@ -1725,7 +1693,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1754,69 +1722,57 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } -static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 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; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_COMMON_ACCESS_BOXED | - ZFCP_STATUS_UNIT_SHARED | - ZFCP_STATUS_UNIT_READONLY, - &unit->status); + ZFCP_STATUS_LUN_SHARED | + ZFCP_STATUS_LUN_READONLY, + &zfcp_sdev->status); switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fsouh_1", req); + zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1", req); /* fall through */ case FSF_LUN_ALREADY_OPEN: break; case FSF_ACCESS_DENIED: - 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); + zfcp_cfdc_lun_denied(sdev, &header->fsf_status_qual); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fsouh_2", req); + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_SHARING_VIOLATION: - if (header->fsf_status_qual.word[0]) - dev_warn(&adapter->ccw_device->dev, - "LUN 0x%Lx on port 0x%Lx is already in " - "use by CSS%d, MIF Image ID %x\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn, - queue_designator->cssid, - queue_designator->hla); - else - zfcp_act_eval_err(adapter, - header->fsf_status_qual.word[2]); - zfcp_erp_unit_access_denied(unit, "fsouh_3", req); - atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); - atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); + zfcp_cfdc_lun_shrng_vltn(sdev, &header->fsf_status_qual); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: dev_warn(&adapter->ccw_device->dev, "No handle is available for LUN " "0x%016Lx on port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_4", req); + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); /* fall through */ case FSF_INVALID_COMMAND_OPTION: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1824,7 +1780,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1833,70 +1789,26 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) break; case FSF_GOOD: - unit->handle = header->lun_handle; - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); - - if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && - (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) && - !zfcp_ccw_priv_sch(adapter)) { - exclusive = (bottom->lun_access_info & - FSF_UNIT_ACCESS_EXCLUSIVE); - readwrite = (bottom->lun_access_info & - FSF_UNIT_ACCESS_OUTBOUND_TRANSFER); - - if (!exclusive) - atomic_set_mask(ZFCP_STATUS_UNIT_SHARED, - &unit->status); - - if (!readwrite) { - atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, - &unit->status); - dev_info(&adapter->ccw_device->dev, - "SCSI device at LUN 0x%016Lx on port " - "0x%016Lx opened read-only\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - } - - if (exclusive && !readwrite) { - dev_err(&adapter->ccw_device->dev, - "Exclusive read-only access not " - "supported (unit 0x%016Lx, " - "port 0x%016Lx)\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_5", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_unit_shutdown(unit, 0, "fsouh_6", req); - } else if (!exclusive && readwrite) { - dev_err(&adapter->ccw_device->dev, - "Shared read-write access not " - "supported (unit 0x%016Lx, port " - "0x%016Lx)\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_7", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_unit_shutdown(unit, 0, "fsouh_8", req); - } - } + zfcp_sdev->lun_handle = header->lun_handle; + atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); + zfcp_cfdc_open_lun_eval(sdev, bottom); break; } } /** - * zfcp_fsf_open_unit - open unit + * zfcp_fsf_open_lun - open LUN * @erp_action: pointer to struct zfcp_erp_action * Returns: 0 on success, error otherwise */ -int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) +int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_qdio *qdio = adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1913,9 +1825,9 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) zfcp_qdio_set_sbale_last(qdio, &req->qdio_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->qtcb->bottom.support.fcp_lun = zfcp_scsi_dev_lun(erp_action->sdev); + req->handler = zfcp_fsf_open_lun_handler; + req->data = erp_action->sdev; req->erp_action = erp_action; erp_action->fsf_req_id = req->req_id; @@ -1929,34 +1841,40 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } -static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) { - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fscuh_1", req); + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(unit->port, 0, "fscuh_2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fscuh_3", req); + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (req->qtcb->header.fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1964,23 +1882,24 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) } break; case FSF_GOOD: - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); break; } } /** - * zfcp_fsf_close_unit - close zfcp unit - * @erp_action: pointer to struct zfcp_unit + * zfcp_fsf_close_LUN - close LUN + * @erp_action: pointer to erp_action triggering the "close LUN" * Returns: 0 on success, error otherwise */ -int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) +int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action) { struct zfcp_qdio *qdio = erp_action->adapter->qdio; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(erp_action->sdev); struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1997,9 +1916,9 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); 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->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->handler = zfcp_fsf_close_lun_handler; + req->data = erp_action->sdev; req->erp_action = erp_action; erp_action->fsf_req_id = req->req_id; @@ -2010,7 +1929,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -2025,7 +1944,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) { struct fsf_qual_latency_info *lat_in; struct latency_cont *lat = NULL; - struct zfcp_unit *unit = req->unit; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scsi->device); struct zfcp_blk_drv_data blktrc; int ticks = req->adapter->timer_ticks; @@ -2048,24 +1967,24 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) case FSF_DATADIR_DIF_READ_STRIP: case FSF_DATADIR_DIF_READ_CONVERT: case FSF_DATADIR_READ: - lat = &unit->latencies.read; + lat = &zfcp_sdev->latencies.read; break; case FSF_DATADIR_DIF_WRITE_INSERT: case FSF_DATADIR_DIF_WRITE_CONVERT: case FSF_DATADIR_WRITE: - lat = &unit->latencies.write; + lat = &zfcp_sdev->latencies.write; break; case FSF_DATADIR_CMND: - lat = &unit->latencies.cmd; + lat = &zfcp_sdev->latencies.cmd; break; } if (lat) { - spin_lock(&unit->latencies.lock); + spin_lock(&zfcp_sdev->latencies.lock); zfcp_fsf_update_lat(&lat->channel, lat_in->channel_lat); zfcp_fsf_update_lat(&lat->fabric, lat_in->fabric_lat); lat->counter++; - spin_unlock(&unit->latencies.lock); + spin_unlock(&zfcp_sdev->latencies.lock); } } @@ -2073,12 +1992,88 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) sizeof(blktrc)); } -static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) +{ + struct scsi_cmnd *scmnd = req->data; + struct scsi_device *sdev = scmnd->device; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct fsf_qtcb_header *header = &req->qtcb->header; + + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) + return; + + switch (header->fsf_status) { + case FSF_HANDLE_MISMATCH: + case FSF_PORT_HANDLE_NOT_VALID: + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1", + req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_FCPLUN_NOT_VALID: + case FSF_LUN_HANDLE_NOT_VALID: + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2", req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_SERVICE_CLASS_NOT_SUPPORTED: + zfcp_fsf_class_not_supp(req); + break; + case FSF_ACCESS_DENIED: + zfcp_cfdc_lun_denied(sdev, &header->fsf_status_qual); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_DIRECTION_INDICATOR_NOT_VALID: + dev_err(&req->adapter->ccw_device->dev, + "Incorrect direction %d, LUN 0x%016Lx on port " + "0x%016Lx closed\n", + req->qtcb->bottom.io.data_direction, + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, + "fssfch3", req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_CMND_LENGTH_NOT_VALID: + dev_err(&req->adapter->ccw_device->dev, + "Incorrect CDB length %d, LUN 0x%016Lx on " + "port 0x%016Lx closed\n", + req->qtcb->bottom.io.fcp_cmnd_length, + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, + "fssfch4", req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_PORT_BOXED: + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5", + req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_LUN_BOXED: + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, + "fssfch6", req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_ADAPTER_STATUS_AVAILABLE: + if (header->fsf_status_qual.word[0] == + FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) + zfcp_fc_test_link(zfcp_sdev->port); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + } +} + +static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) { struct scsi_cmnd *scpnt; struct fcp_resp_with_ext *fcp_rsp; unsigned long flags; + zfcp_fsf_fcp_handler_common(req); + read_lock_irqsave(&req->adapter->abort_lock, flags); scpnt = req->data; @@ -2125,97 +2120,6 @@ skip_fsfstatus: read_unlock_irqrestore(&req->adapter->abort_lock, flags); } -static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req) -{ - struct fcp_resp_with_ext *fcp_rsp; - struct fcp_resp_rsp_info *rsp_info; - - fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; - rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; - - if ((rsp_info->rsp_code != FCP_TMF_CMPL) || - (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; - - switch (header->fsf_status) { - case FSF_HANDLE_MISMATCH: - case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fssfch1", 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, "fssfch2", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_SERVICE_CLASS_NOT_SUPPORTED: - zfcp_fsf_class_not_supp(req); - break; - 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, - "Incorrect direction %d, unit 0x%016Lx on port " - "0x%016Lx closed\n", - req->qtcb->bottom.io.data_direction, - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch3", - req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_CMND_LENGTH_NOT_VALID: - dev_err(&req->adapter->ccw_device->dev, - "Incorrect CDB length %d, unit 0x%016Lx on " - "port 0x%016Lx closed\n", - req->qtcb->bottom.io.fcp_cmnd_length, - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch4", - req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fssfch5", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_LUN_BOXED: - zfcp_erp_unit_boxed(unit, "fssfch6", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_ADAPTER_STATUS_AVAILABLE: - if (header->fsf_status_qual.word[0] == - FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) - zfcp_fc_test_link(unit->port); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - } -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; - put_device(&unit->dev); - } -} - static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir) { switch (scsi_get_prot_op(scsi_cmnd)) { @@ -2255,22 +2159,22 @@ static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir) } /** - * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) - * @unit: unit where command is sent to + * zfcp_fsf_fcp_cmnd - initiate an FCP command (for a SCSI command) * @scsi_cmnd: scsi command to be sent */ -int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd) +int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) { struct zfcp_fsf_req *req; struct fcp_cmnd *fcp_cmnd; unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; int real_bytes, retval = -EIO, dix_bytes = 0; - struct zfcp_adapter *adapter = unit->port->adapter; + struct scsi_device *sdev = scsi_cmnd->device; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct zfcp_qdio *qdio = adapter->qdio; struct fsf_qtcb_bottom_io *io; - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return -EBUSY; @@ -2295,11 +2199,10 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, io = &req->qtcb->bottom.io; req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - 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->handler = zfcp_fsf_fcp_cmnd_handler; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->port->handle; io->service_class = FSF_CLASS_3; io->fcp_cmnd_length = FCP_CMND_LEN; @@ -2310,8 +2213,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction); - get_device(&unit->dev); - fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd); @@ -2338,7 +2239,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, goto out; failed_scsi_cmnd: - put_device(&unit->dev); zfcp_fsf_req_free(req); scsi_cmnd->host_scribble = NULL; out: @@ -2346,23 +2246,40 @@ out: return retval; } +static void zfcp_fsf_fcp_task_mgmt_handler(struct zfcp_fsf_req *req) +{ + struct fcp_resp_with_ext *fcp_rsp; + struct fcp_resp_rsp_info *rsp_info; + + zfcp_fsf_fcp_handler_common(req); + + fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; + rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; + + if ((rsp_info->rsp_code != FCP_TMF_CMPL) || + (req->status & ZFCP_STATUS_FSFREQ_ERROR)) + req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; +} + /** - * zfcp_fsf_send_fcp_ctm - send SCSI task management command - * @unit: pointer to struct zfcp_unit + * zfcp_fsf_fcp_task_mgmt - send SCSI task management command + * @scmnd: SCSI command to send the task management command for * @tm_flags: unsigned byte for task management flags * Returns: on success pointer to struct fsf_req, NULL otherwise */ -struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) +struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd, + u8 tm_flags) { struct zfcp_fsf_req *req = NULL; struct fcp_cmnd *fcp_cmnd; - struct zfcp_qdio *qdio = unit->port->adapter->qdio; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device); + struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio; - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return NULL; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -2376,10 +2293,10 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) } 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->data = scmnd; + req->handler = zfcp_fsf_fcp_task_mgmt_handler; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->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 = FCP_CMND_LEN; @@ -2387,7 +2304,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; - zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags); + zfcp_fc_fcp_tm(fcp_cmnd, scmnd->device, tm_flags); zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); if (!zfcp_fsf_req_send(req)) @@ -2396,7 +2313,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) zfcp_fsf_req_free(req); req = NULL; out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return req; } @@ -2432,7 +2349,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, return ERR_PTR(-EINVAL); } - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -2459,7 +2376,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); if (!retval) { wait_for_completion(&req->completion); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index b263575..a0554be 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -60,13 +60,11 @@ static inline void zfcp_qdio_account(struct zfcp_qdio *qdio) unsigned long long now, span; int used; - spin_lock(&qdio->stat_lock); now = get_clock_monotonic(); span = (now - qdio->req_q_time) >> 12; used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free); qdio->req_q_util += used * span; qdio->req_q_time = now; - spin_unlock(&qdio->stat_lock); } static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, @@ -84,7 +82,9 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, /* cleanup all SBALs being program-owned now */ zfcp_qdio_zero_sbals(qdio->req_q, idx, count); + spin_lock_irq(&qdio->stat_lock); zfcp_qdio_account(qdio); + spin_unlock_irq(&qdio->stat_lock); atomic_add(count, &qdio->req_q_free); wake_up(&qdio->req_q_wq); } @@ -201,11 +201,11 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) { - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (atomic_read(&qdio->req_q_free) || !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return 1; - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return 0; } @@ -223,7 +223,7 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) { long ret; - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); ret = wait_event_interruptible_timeout(qdio->req_q_wq, zfcp_qdio_sbal_check(qdio), 5 * HZ); @@ -239,7 +239,7 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL); } - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); return -EIO; } @@ -254,7 +254,9 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) int retval; u8 sbal_number = q_req->sbal_number; + spin_lock(&qdio->stat_lock); zfcp_qdio_account(qdio); + spin_unlock(&qdio->stat_lock); retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, q_req->sbal_first, sbal_number); @@ -277,16 +279,12 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, struct zfcp_qdio *qdio) { - + memset(id, 0, sizeof(*id)); id->cdev = qdio->adapter->ccw_device; id->q_format = QDIO_ZFCP_QFMT; memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8); ASCEBC(id->adapter_name, 8); id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV; - id->qib_param_field_format = 0; - id->qib_param_field = NULL; - id->input_slib_elements = NULL; - id->output_slib_elements = NULL; id->no_input_qs = 1; id->no_output_qs = 1; id->input_handler = zfcp_qdio_int_resp; @@ -328,9 +326,9 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) return; /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); wake_up(&qdio->req_q_wq); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index cb000c9..50286d8 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -49,11 +49,12 @@ static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, return sdev->queue_depth; } -static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) +static void zfcp_scsi_slave_destroy(struct scsi_device *sdev) { - struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; - unit->device = NULL; - put_device(&unit->dev); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + zfcp_erp_lun_shutdown_wait(sdev, "scssd_1"); + put_device(&zfcp_sdev->port->dev); } static int zfcp_scsi_slave_configure(struct scsi_device *sdp) @@ -78,23 +79,16 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, void (*done) (struct scsi_cmnd *)) { - struct zfcp_unit *unit; - struct zfcp_adapter *adapter; - int status, scsi_result, ret; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); + int status, scsi_result, ret; /* reset the status for this request */ scpnt->result = 0; scpnt->host_scribble = NULL; scpnt->scsi_done = done; - /* - * figure out adapter and target device - * (stored there by zfcp_scsi_slave_alloc) - */ - adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; - unit = scpnt->device->hostdata; - scsi_result = fc_remote_port_chkready(rport); if (unlikely(scsi_result)) { scpnt->result = scsi_result; @@ -103,11 +97,11 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, return 0; } - status = atomic_read(&unit->status); + status = atomic_read(&zfcp_sdev->status); if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) && - !(atomic_read(&unit->port->status) & + !(atomic_read(&zfcp_sdev->port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)) { - /* only unit access denied, but port is good + /* only LUN access denied, but port is good * not covered by FC transport, have to fail here */ zfcp_scsi_command_fail(scpnt, DID_ERROR); return 0; @@ -115,8 +109,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) { /* This could be either - * open unit pending: this is temporary, will result in - * open unit or ERP_FAILED, so retry command + * open LUN pending: this is temporary, will result in + * open LUN or ERP_FAILED, so retry command * call to rport_delete pending: mimic retry from * fc_remote_port_chkready until rport is BLOCKED */ @@ -124,7 +118,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, return 0; } - ret = zfcp_fsf_send_fcp_command_task(unit, scpnt); + ret = zfcp_fsf_fcp_cmnd(scpnt); if (unlikely(ret == -EBUSY)) return SCSI_MLQUEUE_DEVICE_BUSY; else if (unlikely(ret < 0)) @@ -133,45 +127,42 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, return ret; } -static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter, - unsigned int id, u64 lun) +static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) { - unsigned long flags; + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct zfcp_adapter *adapter = + (struct zfcp_adapter *) sdev->host->hostdata[0]; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct zfcp_port *port; - struct zfcp_unit *unit = NULL; + struct zfcp_unit *unit; - read_lock_irqsave(&adapter->port_list_lock, flags); - list_for_each_entry(port, &adapter->port_list, list) { - if (!port->rport || (id != port->rport->scsi_target_id)) - continue; - unit = zfcp_get_unit_by_lun(port, lun); - if (unit) - break; - } - read_unlock_irqrestore(&adapter->port_list_lock, flags); + port = zfcp_get_port_by_wwpn(adapter, rport->port_name); + if (!port) + return -ENXIO; - return unit; -} + unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev)); + if (unit) + put_device(&unit->dev); -static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) -{ - struct zfcp_adapter *adapter; - struct zfcp_unit *unit; - u64 lun; + if (!unit && !(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) { + put_device(&port->dev); + return -ENXIO; + } - adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; - if (!adapter) - goto out; + zfcp_sdev->port = port; + zfcp_sdev->latencies.write.channel.min = 0xFFFFFFFF; + zfcp_sdev->latencies.write.fabric.min = 0xFFFFFFFF; + zfcp_sdev->latencies.read.channel.min = 0xFFFFFFFF; + zfcp_sdev->latencies.read.fabric.min = 0xFFFFFFFF; + zfcp_sdev->latencies.cmd.channel.min = 0xFFFFFFFF; + zfcp_sdev->latencies.cmd.fabric.min = 0xFFFFFFFF; + spin_lock_init(&zfcp_sdev->latencies.lock); - int_to_scsilun(sdp->lun, (struct scsi_lun *)&lun); - unit = zfcp_unit_lookup(adapter, sdp->id, lun); - if (unit) { - sdp->hostdata = unit; - unit->device = sdp; - return 0; - } -out: - return -ENXIO; + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING); + zfcp_erp_lun_reopen(sdev, 0, "scsla_1", NULL); + zfcp_erp_wait(port->adapter); + + return 0; } static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) @@ -179,7 +170,6 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) struct Scsi_Host *scsi_host = scpnt->device->host; struct zfcp_adapter *adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; - struct zfcp_unit *unit = scpnt->device->hostdata; struct zfcp_fsf_req *old_req, *abrt_req; unsigned long flags; unsigned long old_reqid = (unsigned long) scpnt->host_scribble; @@ -203,7 +193,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) write_unlock_irqrestore(&adapter->abort_lock, flags); while (retry--) { - abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit); + abrt_req = zfcp_fsf_abort_fcp_cmnd(scpnt); if (abrt_req) break; @@ -238,14 +228,14 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) { - struct zfcp_unit *unit = scpnt->device->hostdata; - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct zfcp_fsf_req *fsf_req = NULL; int retval = SUCCESS, ret; int retry = 3; while (retry--) { - fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags); + fsf_req = zfcp_fsf_fcp_task_mgmt(scpnt, tm_flags); if (fsf_req) break; @@ -256,7 +246,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { - zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags); return SUCCESS; } } @@ -266,10 +256,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) wait_for_completion(&fsf_req->completion); if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { - zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags); retval = FAILED; } else - zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags); zfcp_fsf_req_free(fsf_req); return retval; @@ -287,8 +277,8 @@ static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { - struct zfcp_unit *unit = scpnt->device->hostdata; - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; int ret; zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt); @@ -319,8 +309,8 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) } /* 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_id = 511; + adapter->scsi_host->max_lun = 0xFFFFFFFF; adapter->scsi_host->max_channel = 0; adapter->scsi_host->unique_id = dev_id.devno; adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */ @@ -534,20 +524,6 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) } } -static void zfcp_scsi_queue_unit_register(struct zfcp_port *port) -{ - struct zfcp_unit *unit; - - read_lock_irq(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) { - get_device(&unit->dev); - if (scsi_queue_work(port->adapter->scsi_host, - &unit->scsi_work) <= 0) - put_device(&unit->dev); - } - read_unlock_irq(&port->unit_list_lock); -} - static void zfcp_scsi_rport_register(struct zfcp_port *port) { struct fc_rport_identifiers ids; @@ -574,7 +550,7 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) port->rport = rport; port->starget_id = rport->scsi_target_id; - zfcp_scsi_queue_unit_register(port); + zfcp_unit_queue_scsi_scan(port); } static void zfcp_scsi_rport_block(struct zfcp_port *port) @@ -638,29 +614,6 @@ void zfcp_scsi_rport_work(struct work_struct *work) } /** - * zfcp_scsi_scan - Register LUN with SCSI midlayer - * @unit: The LUN/unit to register - */ -void zfcp_scsi_scan(struct zfcp_unit *unit) -{ - struct fc_rport *rport = unit->port->rport; - - if (rport && rport->port_state == FC_PORTSTATE_ONLINE) - scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, - scsilun_to_int((struct scsi_lun *) - &unit->fcp_lun), 0); -} - -void zfcp_scsi_scan_work(struct work_struct *work) -{ - struct zfcp_unit *unit = container_of(work, struct zfcp_unit, - scsi_work); - - zfcp_scsi_scan(unit); - put_device(&unit->dev); -} - -/** * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host * @adapter: The adapter where to configure DIF/DIX for the SCSI host */ @@ -681,6 +634,7 @@ void zfcp_scsi_set_prot(struct zfcp_adapter *adapter) adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) { mask |= SHOST_DIX_TYPE1_PROTECTION; scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); + shost->sg_prot_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2; } @@ -734,7 +688,6 @@ struct fc_function_template zfcp_transport_functions = { .show_host_port_type = 1, .show_host_speed = 1, .show_host_port_id = 1, - .disable_target_scan = 1, .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els), }; diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index b4561c86..2f2c54f 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -68,63 +68,96 @@ ZFCP_DEFINE_ATTR(zfcp_port, port, access_denied, "%d\n", ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n", - atomic_read(&unit->status)); + zfcp_unit_sdev_status(unit)); ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n", - (atomic_read(&unit->status) & + (zfcp_unit_sdev_status(unit) & ZFCP_STATUS_COMMON_ERP_INUSE) != 0); ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n", - (atomic_read(&unit->status) & + (zfcp_unit_sdev_status(unit) & 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_unit_sdev_status(unit) & + ZFCP_STATUS_LUN_SHARED) != 0); ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_readonly, "%d\n", - (atomic_read(&unit->status) & - ZFCP_STATUS_UNIT_READONLY) != 0); + (zfcp_unit_sdev_status(unit) & + ZFCP_STATUS_LUN_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 = container_of(dev, struct _feat_def, 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 = container_of(dev, struct _feat_def, dev); \ - unsigned long val; \ - int retval = 0; \ - \ - if (!(_feat && get_device(&_feat->dev))) \ - return -EBUSY; \ - \ - 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: \ - put_device(&_feat->dev); \ - 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); +static ssize_t zfcp_sysfs_port_failed_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); + + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + return sprintf(buf, "1\n"); + + return sprintf(buf, "0\n"); +} + +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 = container_of(dev, struct zfcp_port, dev); + unsigned long val; + + if (strict_strtoul(buf, 0, &val) || val != 0) + return -EINVAL; + + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING); + zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2", + NULL); + zfcp_erp_wait(port->adapter); -ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2"); -ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2"); + return count; +} +static ZFCP_DEV_ATTR(port, failed, S_IWUSR | S_IRUGO, + zfcp_sysfs_port_failed_show, + zfcp_sysfs_port_failed_store); + +static ssize_t zfcp_sysfs_unit_failed_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); + struct scsi_device *sdev; + unsigned int status, failed = 1; + + sdev = zfcp_unit_sdev(unit); + if (sdev) { + status = atomic_read(&sdev_to_zfcp(sdev)->status); + failed = status & ZFCP_STATUS_COMMON_ERP_FAILED ? 1 : 0; + scsi_device_put(sdev); + } + + return sprintf(buf, "%d\n", failed); +} + +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 = container_of(dev, struct zfcp_unit, dev); + unsigned long val; + struct scsi_device *sdev; + + if (strict_strtoul(buf, 0, &val) || val != 0) + return -EINVAL; + + sdev = zfcp_unit_sdev(unit); + if (sdev) { + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING); + zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, + "syufai2", NULL); + zfcp_erp_wait(unit->port->adapter); + } else + zfcp_unit_scsi_scan(unit); + + return count; +} +static ZFCP_DEV_ATTR(unit, failed, S_IWUSR | S_IRUGO, + zfcp_sysfs_unit_failed_show, + zfcp_sysfs_unit_failed_store); static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, @@ -163,8 +196,7 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev, goto out; } - zfcp_erp_modify_adapter_status(adapter, "syafai1", NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "syafai2", NULL); zfcp_erp_wait(adapter); @@ -257,28 +289,15 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, const char *buf, size_t count) { struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); - struct zfcp_unit *unit; u64 fcp_lun; - int retval = -EINVAL; - - if (!(port && get_device(&port->dev))) - return -EBUSY; if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) - goto out; + return -EINVAL; - unit = zfcp_unit_enqueue(port, fcp_lun); - if (IS_ERR(unit)) - goto out; - else - retval = 0; + if (zfcp_unit_add(port, fcp_lun)) + return -EINVAL; - zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); - zfcp_erp_wait(unit->port->adapter); - zfcp_scsi_scan(unit); -out: - put_device(&port->dev); - return retval ? retval : (ssize_t) count; + return count; } static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); @@ -287,42 +306,15 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, const char *buf, size_t count) { struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); - struct zfcp_unit *unit; u64 fcp_lun; - int retval = -EINVAL; - struct scsi_device *sdev; - - if (!(port && get_device(&port->dev))) - return -EBUSY; if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) - goto out; + return -EINVAL; - unit = zfcp_get_unit_by_lun(port, fcp_lun); - if (!unit) - goto out; - else - retval = 0; - - sdev = scsi_device_lookup(port->adapter->scsi_host, 0, - port->starget_id, - scsilun_to_int((struct scsi_lun *)&fcp_lun)); - if (sdev) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } - - write_lock_irq(&port->unit_list_lock); - list_del(&unit->list); - write_unlock_irq(&port->unit_list_lock); - - put_device(&unit->dev); + if (zfcp_unit_remove(port, fcp_lun)) + return -EINVAL; - zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); - zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); -out: - put_device(&port->dev); - return retval ? retval : (ssize_t) count; + return count; } static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); @@ -363,9 +355,9 @@ 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; \ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \ + struct zfcp_latencies *lat = &zfcp_sdev->latencies; \ + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; \ unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \ \ spin_lock_bh(&lat->lock); \ @@ -394,8 +386,8 @@ zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ 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; \ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \ + struct zfcp_latencies *lat = &zfcp_sdev->latencies; \ unsigned long flags; \ \ spin_lock_irqsave(&lat->lock, flags); \ @@ -423,19 +415,28 @@ 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; \ + struct scsi_device *sdev = to_scsi_device(dev); \ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \ + struct zfcp_port *port = zfcp_sdev->port; \ \ 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", - dev_name(&unit->port->adapter->ccw_device->dev)); + dev_name(&port->adapter->ccw_device->dev)); ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", - (unsigned long long) unit->port->wwpn); -ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", - (unsigned long long) unit->fcp_lun); + (unsigned long long) port->wwpn); + +static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return sprintf(buf, "0x%016llx\n", zfcp_scsi_dev_lun(sdev)); +} +static DEVICE_ATTR(fcp_lun, S_IRUGO, zfcp_sysfs_scsi_fcp_lun_show, NULL); struct device_attribute *zfcp_sysfs_sdev_attrs[] = { &dev_attr_fcp_lun, diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c new file mode 100644 index 0000000..1119c53 --- /dev/null +++ b/drivers/s390/scsi/zfcp_unit.c @@ -0,0 +1,244 @@ +/* + * zfcp device driver + * + * Tracking of manually configured LUNs and helper functions to + * register the LUNs with the SCSI midlayer. + * + * Copyright IBM Corporation 2010 + */ + +#include "zfcp_def.h" +#include "zfcp_ext.h" + +/** + * zfcp_unit_scsi_scan - Register LUN with SCSI midlayer + * @unit: The zfcp LUN/unit to register + * + * When the SCSI midlayer is not allowed to automatically scan and + * attach SCSI devices, zfcp has to register the single devices with + * the SCSI midlayer. + */ +void zfcp_unit_scsi_scan(struct zfcp_unit *unit) +{ + struct fc_rport *rport = unit->port->rport; + unsigned int lun; + + lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun); + + if (rport && rport->port_state == FC_PORTSTATE_ONLINE) + scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, lun, 1); +} + +static void zfcp_unit_scsi_scan_work(struct work_struct *work) +{ + struct zfcp_unit *unit = container_of(work, struct zfcp_unit, + scsi_work); + + zfcp_unit_scsi_scan(unit); + put_device(&unit->dev); +} + +/** + * zfcp_unit_queue_scsi_scan - Register configured units on port + * @port: The zfcp_port where to register units + * + * After opening a port, all units configured on this port have to be + * registered with the SCSI midlayer. This function should be called + * after calling fc_remote_port_add, so that the fc_rport is already + * ONLINE and the call to scsi_scan_target runs the same way as the + * call in the FC transport class. + */ +void zfcp_unit_queue_scsi_scan(struct zfcp_port *port) +{ + struct zfcp_unit *unit; + + read_lock_irq(&port->unit_list_lock); + list_for_each_entry(unit, &port->unit_list, list) { + get_device(&unit->dev); + if (scsi_queue_work(port->adapter->scsi_host, + &unit->scsi_work) <= 0) + put_device(&unit->dev); + } + read_unlock_irq(&port->unit_list_lock); +} + +static struct zfcp_unit *_zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun) +{ + struct zfcp_unit *unit; + + list_for_each_entry(unit, &port->unit_list, list) + if (unit->fcp_lun == fcp_lun) { + get_device(&unit->dev); + return unit; + } + + return NULL; +} + +/** + * zfcp_unit_find - Find and return zfcp_unit with specified FCP LUN + * @port: zfcp_port where to look for the unit + * @fcp_lun: 64 Bit FCP LUN used to identify the zfcp_unit + * + * If zfcp_unit is found, a reference is acquired that has to be + * released later. + * + * Returns: Pointer to the zfcp_unit, or NULL if there is no zfcp_unit + * with the specified FCP LUN. + */ +struct zfcp_unit *zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun) +{ + struct zfcp_unit *unit; + + read_lock_irq(&port->unit_list_lock); + unit = _zfcp_unit_find(port, fcp_lun); + read_unlock_irq(&port->unit_list_lock); + return unit; +} + +/** + * zfcp_unit_release - Drop reference to zfcp_port and free memory of zfcp_unit. + * @dev: pointer to device in zfcp_unit + */ +static void zfcp_unit_release(struct device *dev) +{ + struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); + + put_device(&unit->port->dev); + kfree(unit); +} + +/** + * 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 + * Returns: 0 success + * + * Sets up some unit internal structures and creates sysfs entry. + */ +int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) +{ + struct zfcp_unit *unit; + + unit = zfcp_unit_find(port, fcp_lun); + if (unit) { + put_device(&unit->dev); + return -EEXIST; + } + + unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); + if (!unit) + return -ENOMEM; + + unit->port = port; + unit->fcp_lun = fcp_lun; + unit->dev.parent = &port->dev; + unit->dev.release = zfcp_unit_release; + INIT_WORK(&unit->scsi_work, zfcp_unit_scsi_scan_work); + + if (dev_set_name(&unit->dev, "0x%016llx", + (unsigned long long) fcp_lun)) { + kfree(unit); + return -ENOMEM; + } + + if (device_register(&unit->dev)) { + put_device(&unit->dev); + return -ENOMEM; + } + + if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { + device_unregister(&unit->dev); + return -EINVAL; + } + + get_device(&port->dev); + + write_lock_irq(&port->unit_list_lock); + list_add_tail(&unit->list, &port->unit_list); + write_unlock_irq(&port->unit_list_lock); + + zfcp_unit_scsi_scan(unit); + + return 0; +} + +/** + * zfcp_unit_sdev - Return SCSI device for zfcp_unit + * @unit: The zfcp_unit where to get the SCSI device for + * + * Returns: scsi_device pointer on success, NULL if there is no SCSI + * device for this zfcp_unit + * + * On success, the caller also holds a reference to the SCSI device + * that must be released with scsi_device_put. + */ +struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit) +{ + struct Scsi_Host *shost; + struct zfcp_port *port; + unsigned int lun; + + lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun); + port = unit->port; + shost = port->adapter->scsi_host; + return scsi_device_lookup(shost, 0, port->starget_id, lun); +} + +/** + * zfcp_unit_sdev_status - Return zfcp LUN status for SCSI device + * @unit: The unit to lookup the SCSI device for + * + * Returns the zfcp LUN status field of the SCSI device if the SCSI device + * for the zfcp_unit exists, 0 otherwise. + */ +unsigned int zfcp_unit_sdev_status(struct zfcp_unit *unit) +{ + unsigned int status = 0; + struct scsi_device *sdev; + struct zfcp_scsi_dev *zfcp_sdev; + + sdev = zfcp_unit_sdev(unit); + if (sdev) { + zfcp_sdev = sdev_to_zfcp(sdev); + status = atomic_read(&zfcp_sdev->status); + scsi_device_put(sdev); + } + + return status; +} + +/** + * zfcp_unit_remove - Remove entry from list of configured units + * @port: The port where to remove the unit from the configuration + * @fcp_lun: The 64 bit LUN of the unit to remove + * + * Returns: -EINVAL if a unit with the specified LUN does not exist, + * 0 on success. + */ +int zfcp_unit_remove(struct zfcp_port *port, u64 fcp_lun) +{ + struct zfcp_unit *unit; + struct scsi_device *sdev; + + write_lock_irq(&port->unit_list_lock); + unit = _zfcp_unit_find(port, fcp_lun); + if (unit) + list_del(&unit->list); + write_unlock_irq(&port->unit_list_lock); + + if (!unit) + return -EINVAL; + + sdev = zfcp_unit_sdev(unit); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } + + put_device(&unit->dev); + + zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); + + return 0; +} |