diff options
Diffstat (limited to 'drivers/s390/char')
-rw-r--r-- | drivers/s390/char/Kconfig | 12 | ||||
-rw-r--r-- | drivers/s390/char/Makefile | 3 | ||||
-rw-r--r-- | drivers/s390/char/monwriter.c | 4 | ||||
-rw-r--r-- | drivers/s390/char/raw3270.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp.c | 7 | ||||
-rw-r--r-- | drivers/s390/char/sclp.h | 24 | ||||
-rw-r--r-- | drivers/s390/char/sclp_config.c | 14 | ||||
-rw-r--r-- | drivers/s390/char/sclp_ocf.c | 145 | ||||
-rw-r--r-- | drivers/s390/char/sclp_sdias.c | 3 | ||||
-rw-r--r-- | drivers/s390/char/sclp_tty.c | 122 | ||||
-rw-r--r-- | drivers/s390/char/tape_3590.c | 11 | ||||
-rw-r--r-- | drivers/s390/char/tape_block.c | 444 | ||||
-rw-r--r-- | drivers/s390/char/tape_std.c | 3 |
13 files changed, 216 insertions, 578 deletions
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index dcee3c5c8954..a4f117d9fdc6 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -119,18 +119,6 @@ config S390_TAPE comment "S/390 tape interface support" depends on S390_TAPE -config S390_TAPE_BLOCK - def_bool y - prompt "Support for tape block devices" - depends on S390_TAPE && BLOCK - help - Select this option if you want to access your channel-attached tape - devices using the block device interface. This interface is similar - to CD-ROM devices on other platforms. The tapes can only be - accessed read-only when using this interface. Have a look at - <file:Documentation/s390/TAPE> for further information about creating - volumes for and using this interface. It is safe to say "Y" here. - comment "S/390 tape hardware support" depends on S390_TAPE diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index efb500ab66c0..f3c325207445 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -3,7 +3,7 @@ # obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ - sclp_cmd.o sclp_config.o sclp_cpi_sys.o + sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o @@ -22,7 +22,6 @@ obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o obj-$(CONFIG_VMCP) += vmcp.o -tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o tape-$(CONFIG_PROC_FS) += tape_proc.o tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index e0702d3ea33b..4600aa10a1c6 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -97,7 +97,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) { struct monwrite_hdr *monhdr = &monpriv->hdr; struct mon_buf *monbuf; - int rc; + int rc = 0; if (monhdr->datalen > MONWRITE_MAX_DATALEN || monhdr->mon_function > MONWRITE_START_CONFIG || @@ -135,7 +135,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) mon_buf_count++; } monpriv->current_buf = monbuf; - return 0; + return rc; } static int monwrite_new_data(struct mon_private *monpriv) diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index e21a5c39ef20..810ac38631c3 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -598,7 +598,6 @@ __raw3270_size_device(struct raw3270 *rp) static const unsigned char wbuf[] = { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 }; struct raw3270_ua *uap; - unsigned short count; int rc; /* @@ -653,7 +652,6 @@ __raw3270_size_device(struct raw3270 *rp) if (rc) return rc; /* Got a Query Reply */ - count = sizeof(rp->init_data) - rp->init_request.rescnt; uap = (struct raw3270_ua *) (rp->init_data + 1); /* Paranoia check. */ if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81) diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index b76c61f82485..eaa7e78186f9 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -19,7 +19,6 @@ #include <linux/suspend.h> #include <linux/completion.h> #include <linux/platform_device.h> -#include <asm/s390_ext.h> #include <asm/types.h> #include <asm/irq.h> @@ -885,12 +884,12 @@ sclp_check_interface(void) spin_unlock_irqrestore(&sclp_lock, flags); /* Enable service-signal interruption - needs to happen * with IRQs enabled. */ - ctl_set_bit(0, 9); + service_subclass_irq_register(); /* Wait for signal from interrupt or timeout */ sclp_sync_wait(); /* Disable service-signal interruption - needs to happen * with IRQs enabled. */ - ctl_clear_bit(0,9); + service_subclass_irq_unregister(); spin_lock_irqsave(&sclp_lock, flags); del_timer(&sclp_request_timer); if (sclp_init_req.status == SCLP_REQ_DONE && @@ -1070,7 +1069,7 @@ sclp_init(void) spin_unlock_irqrestore(&sclp_lock, flags); /* Enable service-signal external interruption - needs to happen with * IRQs enabled. */ - ctl_set_bit(0, 9); + service_subclass_irq_register(); sclp_init_mask(1); return 0; diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 6bb5a6bdfab5..49a1bb52bc87 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -28,6 +28,7 @@ #define EVTYP_CONFMGMDATA 0x04 #define EVTYP_SDIAS 0x1C #define EVTYP_ASYNC 0x0A +#define EVTYP_OCF 0x1E #define EVTYP_OPCMD_MASK 0x80000000 #define EVTYP_MSG_MASK 0x40000000 @@ -40,6 +41,7 @@ #define EVTYP_CONFMGMDATA_MASK 0x10000000 #define EVTYP_SDIAS_MASK 0x00000010 #define EVTYP_ASYNC_MASK 0x00400000 +#define EVTYP_OCF_MASK 0x00000004 #define GNRLMSGFLGS_DOM 0x8000 #define GNRLMSGFLGS_SNDALRM 0x4000 @@ -186,4 +188,26 @@ sclp_ascebc_str(unsigned char *str, int nr) (MACHINE_IS_VM) ? ASCEBC(str, nr) : ASCEBC_500(str, nr); } +static inline struct gds_vector * +sclp_find_gds_vector(void *start, void *end, u16 id) +{ + struct gds_vector *v; + + for (v = start; (void *) v < end; v = (void *) v + v->length) + if (v->gds_id == id) + return v; + return NULL; +} + +static inline struct gds_subvector * +sclp_find_gds_subvector(void *start, void *end, u8 key) +{ + struct gds_subvector *sv; + + for (sv = start; (void *) sv < end; sv = (void *) sv + sv->length) + if (sv->key == key) + return sv; + return NULL; +} + #endif /* __SCLP_H__ */ diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 16e232a99fb7..95b909ac2b73 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -71,21 +71,9 @@ static struct sclp_register sclp_conf_register = static int __init sclp_conf_init(void) { - int rc; - INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); - - rc = sclp_register(&sclp_conf_register); - if (rc) - return rc; - - if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) { - pr_warning("no configuration management.\n"); - sclp_unregister(&sclp_conf_register); - rc = -ENOSYS; - } - return rc; + return sclp_register(&sclp_conf_register); } __initcall(sclp_conf_init); diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c new file mode 100644 index 000000000000..ab294d5a534e --- /dev/null +++ b/drivers/s390/char/sclp_ocf.c @@ -0,0 +1,145 @@ +/* + * drivers/s390/char/sclp_ocf.c + * SCLP OCF communication parameters sysfs interface + * + * Copyright IBM Corp. 2011 + * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> + */ + +#define KMSG_COMPONENT "sclp_ocf" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/stat.h> +#include <linux/device.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/kmod.h> +#include <linux/timer.h> +#include <linux/err.h> +#include <asm/ebcdic.h> +#include <asm/sclp.h> + +#include "sclp.h" + +#define OCF_LENGTH_HMC_NETWORK 8UL +#define OCF_LENGTH_CPC_NAME 8UL + +static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1]; +static char cpc_name[OCF_LENGTH_CPC_NAME + 1]; + +static DEFINE_SPINLOCK(sclp_ocf_lock); +static struct work_struct sclp_ocf_change_work; + +static struct kset *ocf_kset; + +static void sclp_ocf_change_notify(struct work_struct *work) +{ + kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE); +} + +/* Handler for OCF event. Look for the CPC image name. */ +static void sclp_ocf_handler(struct evbuf_header *evbuf) +{ + struct gds_vector *v; + struct gds_subvector *sv, *netid, *cpc; + size_t size; + + /* Find the 0x9f00 block. */ + v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length, + 0x9f00); + if (!v) + return; + /* Find the 0x9f22 block inside the 0x9f00 block. */ + v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22); + if (!v) + return; + /* Find the 0x81 block inside the 0x9f22 block. */ + sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81); + if (!sv) + return; + /* Find the 0x01 block inside the 0x81 block. */ + netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1); + /* Find the 0x02 block inside the 0x81 block. */ + cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2); + /* Copy network name and cpc name. */ + spin_lock(&sclp_ocf_lock); + if (netid) { + size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length); + memcpy(hmc_network, netid + 1, size); + EBCASC(hmc_network, size); + hmc_network[size] = 0; + } + if (cpc) { + size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length); + memcpy(cpc_name, cpc + 1, size); + EBCASC(cpc_name, size); + cpc_name[size] = 0; + } + spin_unlock(&sclp_ocf_lock); + schedule_work(&sclp_ocf_change_work); +} + +static struct sclp_register sclp_ocf_event = { + .receive_mask = EVTYP_OCF_MASK, + .receiver_fn = sclp_ocf_handler, +}; + +static ssize_t cpc_name_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + int rc; + + spin_lock_irq(&sclp_ocf_lock); + rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name); + spin_unlock_irq(&sclp_ocf_lock); + return rc; +} + +static struct kobj_attribute cpc_name_attr = + __ATTR(cpc_name, 0444, cpc_name_show, NULL); + +static ssize_t hmc_network_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + int rc; + + spin_lock_irq(&sclp_ocf_lock); + rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network); + spin_unlock_irq(&sclp_ocf_lock); + return rc; +} + +static struct kobj_attribute hmc_network_attr = + __ATTR(hmc_network, 0444, hmc_network_show, NULL); + +static struct attribute *ocf_attrs[] = { + &cpc_name_attr.attr, + &hmc_network_attr.attr, + NULL, +}; + +static struct attribute_group ocf_attr_group = { + .attrs = ocf_attrs, +}; + +static int __init ocf_init(void) +{ + int rc; + + INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify); + ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj); + if (!ocf_kset) + return -ENOMEM; + + rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group); + if (rc) { + kset_unregister(ocf_kset); + return rc; + } + + return sclp_register(&sclp_ocf_event); +} + +device_initcall(ocf_init); diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c index 6a1c58dc61a7..fa733ecd3d70 100644 --- a/drivers/s390/char/sclp_sdias.c +++ b/drivers/s390/char/sclp_sdias.c @@ -69,9 +69,6 @@ static DEFINE_MUTEX(sdias_mutex); static void sdias_callback(struct sclp_req *request, void *data) { - struct sdias_sccb *cbsccb; - - cbsccb = (struct sdias_sccb *) request->sccb; sclp_req_done = 1; wake_up(&sdias_wq); /* Inform caller, that request is complete */ TRACE("callback done\n"); diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 8258d590505f..a879c139926a 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -408,118 +408,72 @@ static int sclp_switch_cases(unsigned char *buf, int count) return op - buf; } -static void -sclp_get_input(unsigned char *start, unsigned char *end) +static void sclp_get_input(struct gds_subvector *sv) { + unsigned char *str; int count; - count = end - start; + str = (unsigned char *) (sv + 1); + count = sv->length - sizeof(*sv); if (sclp_tty_tolower) - EBC_TOLOWER(start, count); - count = sclp_switch_cases(start, count); + EBC_TOLOWER(str, count); + count = sclp_switch_cases(str, count); /* convert EBCDIC to ASCII (modify original input in SCCB) */ - sclp_ebcasc_str(start, count); + sclp_ebcasc_str(str, count); /* transfer input to high level driver */ - sclp_tty_input(start, count); -} - -static inline struct gds_vector * -find_gds_vector(struct gds_vector *start, struct gds_vector *end, u16 id) -{ - struct gds_vector *vec; - - for (vec = start; vec < end; vec = (void *) vec + vec->length) - if (vec->gds_id == id) - return vec; - return NULL; + sclp_tty_input(str, count); } -static inline struct gds_subvector * -find_gds_subvector(struct gds_subvector *start, - struct gds_subvector *end, u8 key) +static inline void sclp_eval_selfdeftextmsg(struct gds_subvector *sv) { - struct gds_subvector *subvec; + void *end; - for (subvec = start; subvec < end; - subvec = (void *) subvec + subvec->length) - if (subvec->key == key) - return subvec; - return NULL; + end = (void *) sv + sv->length; + for (sv = sv + 1; (void *) sv < end; sv = (void *) sv + sv->length) + if (sv->key == 0x30) + sclp_get_input(sv); } -static inline void -sclp_eval_selfdeftextmsg(struct gds_subvector *start, - struct gds_subvector *end) +static inline void sclp_eval_textcmd(struct gds_vector *v) { - struct gds_subvector *subvec; - - subvec = start; - while (subvec < end) { - subvec = find_gds_subvector(subvec, end, 0x30); - if (!subvec) - break; - sclp_get_input((unsigned char *)(subvec + 1), - (unsigned char *) subvec + subvec->length); - subvec = (void *) subvec + subvec->length; - } -} + struct gds_subvector *sv; + void *end; -static inline void -sclp_eval_textcmd(struct gds_subvector *start, - struct gds_subvector *end) -{ - struct gds_subvector *subvec; + end = (void *) v + v->length; + for (sv = (struct gds_subvector *) (v + 1); + (void *) sv < end; sv = (void *) sv + sv->length) + if (sv->key == GDS_KEY_SELFDEFTEXTMSG) + sclp_eval_selfdeftextmsg(sv); - subvec = start; - while (subvec < end) { - subvec = find_gds_subvector(subvec, end, - GDS_KEY_SELFDEFTEXTMSG); - if (!subvec) - break; - sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1), - (void *)subvec + subvec->length); - subvec = (void *) subvec + subvec->length; - } } -static inline void -sclp_eval_cpmsu(struct gds_vector *start, struct gds_vector *end) +static inline void sclp_eval_cpmsu(struct gds_vector *v) { - struct gds_vector *vec; + void *end; - vec = start; - while (vec < end) { - vec = find_gds_vector(vec, end, GDS_ID_TEXTCMD); - if (!vec) - break; - sclp_eval_textcmd((struct gds_subvector *)(vec + 1), - (void *) vec + vec->length); - vec = (void *) vec + vec->length; - } + end = (void *) v + v->length; + for (v = v + 1; (void *) v < end; v = (void *) v + v->length) + if (v->gds_id == GDS_ID_TEXTCMD) + sclp_eval_textcmd(v); } -static inline void -sclp_eval_mdsmu(struct gds_vector *start, void *end) +static inline void sclp_eval_mdsmu(struct gds_vector *v) { - struct gds_vector *vec; - - vec = find_gds_vector(start, end, GDS_ID_CPMSU); - if (vec) - sclp_eval_cpmsu(vec + 1, (void *) vec + vec->length); + v = sclp_find_gds_vector(v + 1, (void *) v + v->length, GDS_ID_CPMSU); + if (v) + sclp_eval_cpmsu(v); } -static void -sclp_tty_receiver(struct evbuf_header *evbuf) +static void sclp_tty_receiver(struct evbuf_header *evbuf) { - struct gds_vector *start, *end, *vec; + struct gds_vector *v; - start = (struct gds_vector *)(evbuf + 1); - end = (void *) evbuf + evbuf->length; - vec = find_gds_vector(start, end, GDS_ID_MDSMU); - if (vec) - sclp_eval_mdsmu(vec + 1, (void *) vec + vec->length); + v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length, + GDS_ID_MDSMU); + if (v) + sclp_eval_mdsmu(v); } static void diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index b98dcbd16711..a7d570728882 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -796,10 +796,8 @@ static void tape_3590_med_state_set(struct tape_device *device, static int tape_3590_done(struct tape_device *device, struct tape_request *request) { - struct tape_3590_disc_data *disc_data; DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); - disc_data = device->discdata; switch (request->op) { case TO_BSB: @@ -1394,17 +1392,12 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) static int tape_3590_crypt_error(struct tape_device *device, struct tape_request *request, struct irb *irb) { - u8 cu_rc, ekm_rc1; + u8 cu_rc; u16 ekm_rc2; - u32 drv_rc; - const char *bus_id; char *sense; sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; - bus_id = dev_name(&device->cdev->dev); cu_rc = sense[0]; - drv_rc = *((u32*) &sense[5]) & 0xffffff; - ekm_rc1 = sense[9]; ekm_rc2 = *((u16*) &sense[10]); if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) /* key not defined on EKM */ @@ -1429,7 +1422,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, struct irb *irb) { struct tape_3590_sense *sense; - int rc; #ifdef CONFIG_S390_TAPE_BLOCK if (request->op == TO_BLOCK) { @@ -1454,7 +1446,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, * - "break": basic error recovery is done * - "goto out:": just print error message if available */ - rc = -EIO; switch (sense->rc_rqc) { case 0x1110: diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c deleted file mode 100644 index 1b3924c2fffd..000000000000 --- a/drivers/s390/char/tape_block.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * drivers/s390/char/tape_block.c - * block device frontend for tape device driver - * - * S390 and zSeries version - * Copyright (C) 2001,2003 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Carsten Otte <cotte@de.ibm.com> - * Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Martin Schwidefsky <schwidefsky@de.ibm.com> - * Stefan Bader <shbader@de.ibm.com> - */ - -#define KMSG_COMPONENT "tape" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#include <linux/fs.h> -#include <linux/module.h> -#include <linux/blkdev.h> -#include <linux/mutex.h> -#include <linux/interrupt.h> -#include <linux/buffer_head.h> -#include <linux/kernel.h> - -#include <asm/debug.h> - -#define TAPE_DBF_AREA tape_core_dbf - -#include "tape.h" - -#define TAPEBLOCK_MAX_SEC 100 -#define TAPEBLOCK_MIN_REQUEUE 3 - -/* - * 2003/11/25 Stefan Bader <shbader@de.ibm.com> - * - * In 2.5/2.6 the block device request function is very likely to be called - * with disabled interrupts (e.g. generic_unplug_device). So the driver can't - * just call any function that tries to allocate CCW requests from that con- - * text since it might sleep. There are two choices to work around this: - * a) do not allocate with kmalloc but use its own memory pool - * b) take requests from the queue outside that context, knowing that - * allocation might sleep - */ - -/* - * 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 unsigned int tapeblock_check_events(struct gendisk *, unsigned int); -static int tapeblock_revalidate_disk(struct gendisk *); - -static const struct block_device_operations tapeblock_fops = { - .owner = THIS_MODULE, - .open = tapeblock_open, - .release = tapeblock_release, - .check_events = tapeblock_check_events, - .revalidate_disk = tapeblock_revalidate_disk, -}; - -static int tapeblock_major = 0; - -static void -tapeblock_trigger_requeue(struct tape_device *device) -{ - /* Protect against rescheduling. */ - if (atomic_cmpxchg(&device->blk_data.requeue_scheduled, 0, 1) != 0) - return; - schedule_work(&device->blk_data.requeue_task); -} - -/* - * Post finished request. - */ -static void -__tapeblock_end_request(struct tape_request *ccw_req, void *data) -{ - struct tape_device *device; - struct request *req; - - DBF_LH(6, "__tapeblock_end_request()\n"); - - device = ccw_req->device; - req = (struct request *) data; - blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO); - if (ccw_req->rc == 0) - /* Update position. */ - device->blk_data.block_position = - (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B; - else - /* We lost the position information due to an error. */ - device->blk_data.block_position = -1; - device->discipline->free_bread(ccw_req); - if (!list_empty(&device->req_queue) || - blk_peek_request(device->blk_data.request_queue)) - tapeblock_trigger_requeue(device); -} - -/* - * Feed the tape device CCW queue with requests supplied in a list. - */ -static int -tapeblock_start_request(struct tape_device *device, struct request *req) -{ - struct tape_request * ccw_req; - int rc; - - DBF_LH(6, "tapeblock_start_request(%p, %p)\n", device, req); - - ccw_req = device->discipline->bread(device, req); - if (IS_ERR(ccw_req)) { - DBF_EVENT(1, "TBLOCK: bread failed\n"); - blk_end_request_all(req, -EIO); - return PTR_ERR(ccw_req); - } - ccw_req->callback = __tapeblock_end_request; - ccw_req->callback_data = (void *) req; - ccw_req->retries = TAPEBLOCK_RETRIES; - - rc = tape_do_io_async(device, ccw_req); - if (rc) { - /* - * Start/enqueueing failed. No retries in - * this case. - */ - blk_end_request_all(req, -EIO); - device->discipline->free_bread(ccw_req); - } - - return rc; -} - -/* - * Move requests from the block device request queue to the tape device ccw - * queue. - */ -static void -tapeblock_requeue(struct work_struct *work) { - struct tape_blk_data * blkdat; - struct tape_device * device; - struct request_queue * queue; - int nr_queued; - struct request * req; - struct list_head * l; - int rc; - - blkdat = container_of(work, struct tape_blk_data, requeue_task); - device = blkdat->device; - if (!device) - return; - - spin_lock_irq(get_ccwdev_lock(device->cdev)); - queue = device->blk_data.request_queue; - - /* Count number of requests on ccw queue. */ - nr_queued = 0; - list_for_each(l, &device->req_queue) - nr_queued++; - spin_unlock(get_ccwdev_lock(device->cdev)); - - spin_lock_irq(&device->blk_data.request_queue_lock); - while ( - blk_peek_request(queue) && - nr_queued < TAPEBLOCK_MIN_REQUEUE - ) { - req = blk_fetch_request(queue); - if (rq_data_dir(req) == WRITE) { - DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); - spin_unlock_irq(&device->blk_data.request_queue_lock); - blk_end_request_all(req, -EIO); - spin_lock_irq(&device->blk_data.request_queue_lock); - continue; - } - nr_queued++; - spin_unlock_irq(&device->blk_data.request_queue_lock); - rc = tapeblock_start_request(device, req); - spin_lock_irq(&device->blk_data.request_queue_lock); - } - spin_unlock_irq(&device->blk_data.request_queue_lock); - atomic_set(&device->blk_data.requeue_scheduled, 0); -} - -/* - * Tape request queue function. Called from ll_rw_blk.c - */ -static void -tapeblock_request_fn(struct request_queue *queue) -{ - struct tape_device *device; - - device = (struct tape_device *) queue->queuedata; - DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device); - BUG_ON(device == NULL); - tapeblock_trigger_requeue(device); -} - -/* - * This function is called for every new tapedevice - */ -int -tapeblock_setup_device(struct tape_device * device) -{ - struct tape_blk_data * blkdat; - struct gendisk * disk; - int rc; - - blkdat = &device->blk_data; - blkdat->device = device; - spin_lock_init(&blkdat->request_queue_lock); - atomic_set(&blkdat->requeue_scheduled, 0); - - blkdat->request_queue = blk_init_queue( - tapeblock_request_fn, - &blkdat->request_queue_lock - ); - if (!blkdat->request_queue) - return -ENOMEM; - - rc = elevator_change(blkdat->request_queue, "noop"); - if (rc) - goto cleanup_queue; - - blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); - blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); - blk_queue_max_segments(blkdat->request_queue, -1L); - blk_queue_max_segment_size(blkdat->request_queue, -1L); - blk_queue_segment_boundary(blkdat->request_queue, -1L); - - disk = alloc_disk(1); - if (!disk) { - rc = -ENOMEM; - goto cleanup_queue; - } - - disk->major = tapeblock_major; - disk->first_minor = device->first_minor; - disk->fops = &tapeblock_fops; - disk->private_data = tape_get_device(device); - disk->queue = blkdat->request_queue; - set_capacity(disk, 0); - sprintf(disk->disk_name, "btibm%d", - device->first_minor / TAPE_MINORS_PER_DEV); - - blkdat->disk = disk; - blkdat->medium_changed = 1; - blkdat->request_queue->queuedata = tape_get_device(device); - - add_disk(disk); - - tape_get_device(device); - INIT_WORK(&blkdat->requeue_task, tapeblock_requeue); - - return 0; - -cleanup_queue: - blk_cleanup_queue(blkdat->request_queue); - blkdat->request_queue = NULL; - - return rc; -} - -void -tapeblock_cleanup_device(struct tape_device *device) -{ - flush_work_sync(&device->blk_data.requeue_task); - tape_put_device(device); - - if (!device->blk_data.disk) { - goto cleanup_queue; - } - - del_gendisk(device->blk_data.disk); - device->blk_data.disk->private_data = NULL; - tape_put_device(device); - put_disk(device->blk_data.disk); - - device->blk_data.disk = NULL; -cleanup_queue: - device->blk_data.request_queue->queuedata = NULL; - tape_put_device(device); - - blk_cleanup_queue(device->blk_data.request_queue); - device->blk_data.request_queue = NULL; -} - -/* - * Detect number of blocks of the tape. - * FIXME: can we extent this to detect the blocks size as well ? - */ -static int -tapeblock_revalidate_disk(struct gendisk *disk) -{ - struct tape_device * device; - unsigned int nr_of_blks; - int rc; - - device = (struct tape_device *) disk->private_data; - BUG_ON(!device); - - if (!device->blk_data.medium_changed) - return 0; - - rc = tape_mtop(device, MTFSFM, 1); - if (rc) - return rc; - - rc = tape_mtop(device, MTTELL, 1); - if (rc < 0) - return rc; - - pr_info("%s: Determining the size of the recorded area...\n", - dev_name(&device->cdev->dev)); - DBF_LH(3, "Image file ends at %d\n", rc); - nr_of_blks = rc; - - /* This will fail for the first file. Catch the error by checking the - * position. */ - tape_mtop(device, MTBSF, 1); - - rc = tape_mtop(device, MTTELL, 1); - if (rc < 0) - return rc; - - if (rc > nr_of_blks) - return -EINVAL; - - DBF_LH(3, "Image file starts at %d\n", rc); - device->bof = rc; - nr_of_blks -= rc; - - pr_info("%s: The size of the recorded area is %i blocks\n", - dev_name(&device->cdev->dev), nr_of_blks); - set_capacity(device->blk_data.disk, - nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); - - device->blk_data.block_position = 0; - device->blk_data.medium_changed = 0; - return 0; -} - -static unsigned int -tapeblock_check_events(struct gendisk *disk, unsigned int clearing) -{ - struct tape_device *device; - - device = (struct tape_device *) disk->private_data; - DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n", - device, device->blk_data.medium_changed); - - return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0; -} - -/* - * Block frontend tape device open function. - */ -static int -tapeblock_open(struct block_device *bdev, fmode_t mode) -{ - struct gendisk * disk = bdev->bd_disk; - struct tape_device * device; - int rc; - - mutex_lock(&tape_block_mutex); - device = tape_get_device(disk->private_data); - - if (device->required_tapemarks) { - DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); - pr_warning("%s: Opening the tape failed because of missing " - "end-of-file marks\n", dev_name(&device->cdev->dev)); - rc = -EPERM; - goto put_device; - } - - rc = tape_open(device); - if (rc) - goto put_device; - - rc = tapeblock_revalidate_disk(disk); - if (rc) - goto release; - - /* - * Note: The reference to <device> is hold until the release function - * is called. - */ - tape_state_set(device, TS_BLKUSE); - mutex_unlock(&tape_block_mutex); - return 0; - -release: - tape_release(device); - put_device: - tape_put_device(device); - mutex_unlock(&tape_block_mutex); - return rc; -} - -/* - * Block frontend tape device release function. - * - * Note: One reference to the tape device was made by the open function. So - * we just get the pointer here and release the reference. - */ -static int -tapeblock_release(struct gendisk *disk, fmode_t mode) -{ - struct tape_device *device = disk->private_data; - - mutex_lock(&tape_block_mutex); - tape_state_set(device, TS_IN_USE); - tape_release(device); - tape_put_device(device); - mutex_unlock(&tape_block_mutex); - - return 0; -} - -/* - * Initialize block device frontend. - */ -int -tapeblock_init(void) -{ - int rc; - - /* Register the tape major number to the kernel */ - rc = register_blkdev(tapeblock_major, "tBLK"); - if (rc < 0) - return rc; - - if (tapeblock_major == 0) - tapeblock_major = rc; - return 0; -} - -/* - * Deregister major for block device frontend - */ -void -tapeblock_exit(void) -{ - unregister_blkdev(tapeblock_major, "tBLK"); -} diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 3c3f342149ec..e7650170274a 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -564,7 +564,6 @@ int tape_std_mtreten(struct tape_device *device, int mt_count) { struct tape_request *request; - int rc; request = tape_alloc_request(4, 0); if (IS_ERR(request)) @@ -576,7 +575,7 @@ tape_std_mtreten(struct tape_device *device, int mt_count) tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL); tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr); /* execute it, MTRETEN rc gets ignored */ - rc = tape_do_io_interruptible(device, request); + tape_do_io_interruptible(device, request); tape_free_request(request); return tape_mtop(device, MTREW, 1); } |