patch-2.4.25 linux-2.4.25/drivers/s390/block/dasd.c
Next file: linux-2.4.25/drivers/s390/block/dasd_3990_erp.c
Previous file: linux-2.4.25/drivers/pcmcia/yenta.c
Back to the patch index
Back to the overall index
- Lines: 611
- Date:
2004-02-18 05:36:31.000000000 -0800
- Orig file:
linux-2.4.24/drivers/s390/block/dasd.c
- Orig date:
2003-08-25 04:44:42.000000000 -0700
diff -urN linux-2.4.24/drivers/s390/block/dasd.c linux-2.4.25/drivers/s390/block/dasd.c
@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
- * $Revision: 1.289 $
+ * $Revision: 1.311 $
*
* History of changes (starts July 2000)
* 11/09/00 complete redesign after code review
@@ -36,6 +36,7 @@
* 07/09/01 fixed PL030324MSH (wrong statistics output)
* 07/16/01 merged in new fixes for handling low-mem situations
* 01/22/01 fixed PL030579KBE (wrong statistics)
+ * 08/07/03 fixed LTC BZ 3847 Erroneous message when formatting DASD
*/
#include <linux/config.h>
@@ -162,6 +163,8 @@
static inline dasd_device_t ** dasd_device_from_devno (int);
static void dasd_process_queues (dasd_device_t * device);
static int dasd_sleep_on_immediate (ccw_req_t *cqr);
+static int dasd_devno_from_devindex (int devindex);
+static int dasd_devindex_from_devno (int devno);
/********************************************************************************
* SECTION: static variables of dasd.c
@@ -229,29 +232,7 @@
dasd_create_range (int from, int to, int features)
{
dasd_range_t *range = NULL;
- int i;
-
- if ( from > to ) {
-
- MESSAGE (KERN_WARNING,
- "Adding device range %04x-%04x: "
- "range invalid, ignoring.",
- from,
- to);
-
- return NULL;
- }
- for (i=from;i<=to;i++) {
- if (dasd_device_from_devno(i)) {
- MESSAGE (KERN_WARNING,
- "device range %04x-%04x: device "
- "%04x is already in a range.",
- from,
- to,
- i);
- }
- }
range = (dasd_range_t *) kmalloc (sizeof (dasd_range_t), GFP_KERNEL);
if (range == NULL)
return NULL;
@@ -307,31 +288,70 @@
/*
* function: dasd_add_range
* creates a dasd_range_t according to the arguments and
- * appends it to the list of ranges
+ * appends it to the list of ranges.
+ * If a device in the range is already in an other range, we split the
+ * range and add the subranges (no duplicate devices).
* additionally a devreg_t is created and added to the list of devregs
*/
-static inline dasd_range_t *
+static inline void
dasd_add_range (int from, int to, int features)
{
dasd_range_t *range;
+ int start, end, index, i;
- range = dasd_create_range (from, to, features);
- if (!range)
- return NULL;
+ if (from > to) {
+ MESSAGE (KERN_DEBUG,
+ "Adding device range %04x-%04x: "
+ "range invalid, ignoring.",
+ from, to);
+ return;
+ }
+
+ /* loop over the given range, remove the already contained devices */
+ /* and add the remaining subranges */
+ for (start = index = from, end = -EINVAL; index <= to; index++) {
+
+ if (dasd_devindex_from_devno(index) > 0) {
+ /* current device is already in range */
+ MESSAGE (KERN_DEBUG,
+ "dasd_add_range %04x-%04x: "
+ "device %04x is already in range",
+ from, to, index);
+
+ if (start == index)
+ start++; /* first already in range */
+ else
+ end = index -1; /* current already in range */
+ } else {
+ if (index == to)
+ end = to; /* end of original range reached */
+ }
- dasd_append_range (range);
+ range = NULL;
+ if (end != -EINVAL) {
+ MESSAGE (KERN_DEBUG,
+ "dasd_add_range %04x-%04x: "
+ "add (sub)range %04x-%04x",
+ from, to, start, end);
+
+ range = dasd_create_range (start, end, features);
+ end = -EINVAL;
+ start = index + 1;
+ }
+
+ if (range) {
+ dasd_append_range (range);
#ifdef CONFIG_DASD_DYNAMIC
- /* allocate and chain devreg infos for the devnos... */
- {
- int i;
- for (i = range->from; i <= range->to; i++) {
- dasd_devreg_t *reg = dasd_create_devreg (i);
- s390_device_register (®->devreg);
- list_add (®->list, &dasd_devreg_head);
- }
- }
+ /* allocate and chain devreg infos for the devnos... */
+ for (i = range->from; i <= range->to; i++) {
+ dasd_devreg_t *reg = dasd_create_devreg (i);
+ s390_device_register (®->devreg);
+ list_add (®->list, &dasd_devreg_head);
+ }
#endif /* CONFIG_DASD_DYNAMIC */
- return range;
+ }
+ }
+ return;
}
/*
@@ -534,10 +554,10 @@
if (buffer==NULL) {
- MESSAGE (KERN_WARNING,
- "can't parse dasd= parameter %s due "
- "to low memory",
- str);
+ MESSAGE_LOG (KERN_WARNING,
+ "can't parse dasd= parameter %s due "
+ "to low memory",
+ str);
}
/* remove leading '0x' */
@@ -580,16 +600,16 @@
break;
}
- MESSAGE (KERN_WARNING,
- "unsupported feature: %s, "
- "ignoring setting",
- buffer);
+ MESSAGE_LOG (KERN_WARNING,
+ "unsupported feature: %s, "
+ "ignoring setting",
+ buffer);
}
}
}
*stra = temp+i;
- if ((val > 65535) || (val < 0))
+ if ((val > 0xFFFF) || (val < 0))
return -EINVAL;
return val;
}
@@ -1754,7 +1774,7 @@
now = get_clock ();
cqr->startclk = now;
- if (device->accessible)
+ if (!device->stopped)
rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
else
rc = -EBUSY;
@@ -2158,10 +2178,6 @@
/* to be filled with MIH */
}
break;
-
- case CQR_STATUS_PENDING:
- /* just wait */
- break;
default:
MESSAGE (KERN_EMERG,
"invalid cqr (%p) detected with status %02x ",
@@ -2235,65 +2251,42 @@
}
/*
- * DASD_HANDLE_STATE_CHANGE_PENDING
+ * function dasd_handle_state_change_pending
*
- * DESCRIPTION
- * Handles the state change pending interrupt.
- * Search for the device related request queue and check if the first
- * cqr in queue in in status 'CQR_STATUE_PENDING'.
- * If so the status is set to 'CQR_STATUS_QUEUED' to reactivate
- * the device.
- *
- * PARAMETER
- * stat device status of state change pending interrupt.
+ * handles the state change pending interrupt.
*/
void
dasd_handle_state_change_pending (devstat_t * stat)
{
- dasd_device_t **device_addr;
+
+ dasd_device_t **device_addr, *device;
ccw_req_t *cqr;
device_addr = dasd_device_from_devno (stat->devno);
- if (device_addr == NULL) {
-
- MESSAGE (KERN_DEBUG,
- "unable to find device for state change pending "
- "interrupt: devno%04x",
- stat->devno);
+ if (!device_addr)
return;
- }
-
- /* re-activate first request in queue */
- cqr = (*device_addr)->queue.head;
- if (cqr == NULL) {
- MESSAGE (KERN_DEBUG,
- "got state change pending interrupt on"
- "idle device: %04x",
- stat->devno);
- return;
- }
+ device = *device_addr;
+ if (!device)
+ return;
- if (cqr->status == CQR_STATUS_PENDING) {
-
- DEV_MESSAGE (KERN_DEBUG, (*device_addr), "%s",
- "device request queue restarted by "
- "state change pending interrupt");
-
- del_timer_sync (&(*device_addr)->blocking_timer);
-
- check_then_set (&cqr->status,
- CQR_STATUS_PENDING, CQR_STATUS_QUEUED);
-
+ /* restart all 'running' IO on queue */
+ cqr = device->queue.head;
+ while (cqr) {
+ if (cqr->status == CQR_STATUS_IN_IO) {
+ cqr->status = CQR_STATUS_QUEUED;
+ }
+ cqr = cqr->next;
}
- if (cqr->status == CQR_STATUS_IN_IO) {
- cqr->status = CQR_STATUS_QUEUED;
- DEV_MESSAGE (KERN_WARNING, (*device_addr), "%s",
- "redriving state change pending condition while in IO");
- }
- dasd_schedule_bh (*device_addr);
+ DEV_MESSAGE (KERN_DEBUG, device, "%s",
+ "device request queue restarted by "
+ "state change pending interrupt");
+
+ del_timer_sync (&(device->blocking_timer));
+ device->stopped &= ~DASD_STOPPED_PENDING;
+ dasd_schedule_bh (device);
} /* end dasd_handle_state_change_pending */
@@ -2634,15 +2627,18 @@
rc = -ENOMEM;
break;
}
- if ((rc = dasd_sleep_on_req (req)) != 0) {
- DEV_MESSAGE (KERN_WARNING, device,
- " Formatting of unit %d failed "
- "with rc = %d",
- fdata->start_unit, rc);
- break;
- }
- dasd_free_request (req, device); /* request is no longer used */
+ rc = dasd_sleep_on_req (req);
+ dasd_free_request (req, device); /* request is no longer used */
+
+ if ( rc ) {
+ if (rc != -ERESTARTSYS )
+ DEV_MESSAGE (KERN_WARNING, device,
+ " Formatting of unit %d failed"
+ " with rc = %d",
+ fdata->start_unit, rc);
+ break;
+ }
fdata->start_unit++;
}
return rc;
@@ -2864,6 +2860,37 @@
rc = dasd_format (device, &fdata);
break;
}
+ case BIODASDGATTR: { /* Get Attributes (cache operations) */
+
+ attrib_data_t attrib;
+
+ if (!capable (CAP_SYS_ADMIN)) {
+ rc = -EACCES;
+ break;
+ }
+
+ if (!data) {
+ rc = -EINVAL;
+ break;
+ }
+
+ if (!device->discipline->get_attrib) {
+ rc = -EINVAL;
+ break;
+ }
+
+ device->discipline->get_attrib (device,
+ &attrib);
+
+ rc = copy_to_user ((void *) data, &attrib,
+ sizeof (attrib_data_t));
+
+ if (rc) {
+ rc = -EFAULT;
+ }
+
+ break;
+ }
case BIODASDSATTR: { /* Set Attributes (cache operations) */
attrib_data_t attrib;
@@ -3410,7 +3437,7 @@
while ( cqr != NULL ) {
if ( cqr->status == CQR_STATUS_IN_IO )
device->discipline->term_IO (cqr);
- if ( cqr->status != CQR_STATUS_DONE ||
+ if ( cqr->status != CQR_STATUS_DONE &&
cqr->status != CQR_STATUS_FAILED ) {
cqr->status = CQR_STATUS_FAILED;
@@ -3530,6 +3557,8 @@
dasd_discipline_t *discipline,
int all, int force )
{
+ dasd_device_t **dptr;
+ dasd_device_t *device;
dasd_range_t *rrange;
int j;
@@ -3541,10 +3570,8 @@
}
do {
for (j = rrange->from; j <= rrange->to; j++) {
- dasd_device_t **dptr;
- dasd_device_t *device;
dptr = dasd_device_from_devno(j);
- if ( dptr == NULL ) {
+ if (dptr == NULL) {
continue;
}
device = *dptr;
@@ -3555,6 +3582,9 @@
dasd_disable_volume(device, force);
}
+
+ if (rrange->list.next == NULL)
+ break;
rrange = list_entry (rrange->list.next, dasd_range_t, list);
} while ( all && rrange && rrange != range );
@@ -3723,7 +3753,8 @@
"device is not accessible, disabling it temporary\n");
s390irq_spin_lock_irqsave (device->devinfo.irq,
flags);
- device->accessible = 0;
+ device->stopped |= DASD_STOPPED_NOT_ACC;
+
if (status == DEVSTAT_NOT_ACC_ERR) {
cqr = device->queue.head;
while (cqr) {
@@ -3755,7 +3786,7 @@
int devno;
int rc = 0;
major_info_t *major_info;
- dasd_range_t *rptr,range;
+ dasd_range_t range;
dasd_device_t *device;
struct list_head *l;
unsigned long flags;
@@ -3783,33 +3814,25 @@
break;
}
- if ( device &&
- (device->level == DASD_STATE_ONLINE) &&
- (!device->accessible) ) {
+ if (device &&
+ device->level >= DASD_STATE_READY) {
s390irq_spin_lock_irqsave (device->devinfo.irq,
flags);
DEV_MESSAGE (KERN_DEBUG, device, "%s",
- "device is accessible again, reenabling it\n");
- device->accessible = 1;
+ "device is accessible again, reenabling it\n");
+ device->stopped &= ~DASD_STOPPED_NOT_ACC;
+
s390irq_spin_unlock_irqrestore(device->devinfo.irq,
flags);
-
-
dasd_schedule_bh(device);
} else {
if (dasd_autodetect) {
- rptr = dasd_add_range (devno, devno, DASD_FEATURE_DEFAULT);
- if ( rptr == NULL ) {
- rc = -ENOMEM;
- goto out;
- }
- } else {
- range.from = devno;
- range.to = devno;
- rptr = ⦥
+ dasd_add_range (devno, devno, DASD_FEATURE_DEFAULT);
}
- dasd_enable_ranges (rptr, NULL, 0);
+ range.from = devno;
+ range.to = devno;
+ dasd_enable_ranges (&range, NULL, 0);
}
out:
return rc;
@@ -3868,7 +3891,6 @@
memset (device, 0, sizeof (dasd_device_t));
dasd_plug_device (device);
- device->accessible = 1;
INIT_LIST_HEAD (&device->lowmem_pool);
/* allocate pages for lowmem pool */
@@ -4040,13 +4062,18 @@
rc = s390_request_irq_special (device->devinfo.irq,
device->discipline->int_handler,
dasd_not_oper_handler,
- 0, DASD_NAME,
+ SA_DOPATHGROUP, DASD_NAME,
&device->dev_status);
if ( rc ) {
MESSAGE (KERN_DEBUG, "%s",
"No request IRQ");
+ if (rc == -EUSERS) {
+ /* Device is reserved by someone else. */
+ device->level = DASD_STATE_BOXED;
+ }
+
goto out;
}
}
@@ -4674,9 +4701,9 @@
for (; isspace(*str); str++);
if (range->from < 0 || range->to < 0) {
- MESSAGE (KERN_WARNING,
- "/proc/dasd/devices: range parse error in '%s'",
- buffer);
+ MESSAGE_LOG (KERN_WARNING,
+ "/proc/dasd/devices: range parse error in '%s'",
+ buffer);
return ERR_PTR (-EINVAL);
}
@@ -4698,7 +4725,7 @@
/* Negative numbers in str/from/to indicate errors */
if (IS_ERR (str) || (range.from < 0) || (range.to < 0)
- || (range.from > 65535) || (range.to > 65535))
+ || (range.from > 0xFFFF) || (range.to > 0xFFFF))
return;
if (strncmp (str, "on", 2) == 0) {
@@ -4708,12 +4735,12 @@
dasd_disable_ranges (&range, NULL, 0, 1);
} else {
- MESSAGE (KERN_WARNING,
- "/proc/dasd/devices: "
- "only 'on' and 'off' are alowed in 'set' "
- "command ('%s'/'%s')",
- buffer,
- str);
+ MESSAGE_LOG (KERN_WARNING,
+ "/proc/dasd/devices: "
+ "only 'on' and 'off' are alowed in 'set' "
+ "command ('%s'/'%s')",
+ buffer,
+ str);
}
return;
@@ -4734,7 +4761,7 @@
/* Negative numbers in str/from/to indicate errors */
if (IS_ERR (str) || (range.from < 0) || (range.to < 0)
- || (range.from > 65535) || (range.to > 65535))
+ || (range.from > 0xFFFF) || (range.to > 0xFFFF))
return;
dasd_add_range (range.from, range.to, range.features);
@@ -4795,13 +4822,13 @@
rc = s390_request_irq_special (device->devinfo.irq,
device->discipline->int_handler,
dasd_not_oper_handler,
- 0,
+ SA_DOPATHGROUP | SA_FORCE,
DASD_NAME,
&device->dev_status);
if ( rc )
goto out;
- rc = dasd_steal_lock (device);
+ rc = dasd_steal_lock (device);
/* unregister the int handler to enable re-sensing */
free_irq (device->devinfo.irq,
@@ -4841,10 +4868,10 @@
/* check for discipline = 'eckd' */
if (strncmp(str, "eckd", 4) != 0) {
- MESSAGE (KERN_WARNING,
- "/proc/dasd/devices: 'brk <devno> <discipline> "
- "is only allowed for 'eckd' (%s)",
- str);
+ MESSAGE_LOG (KERN_WARNING,
+ "/proc/dasd/devices: 'brk <devno> <discipline> "
+ "is only allowed for 'eckd' (%s)",
+ str);
return;
}
@@ -4897,10 +4924,10 @@
buffer[user_len] = '\0';
}
- MESSAGE (KERN_INFO,
- "/proc/dasd/devices: '%s'",
- buffer);
-
+ MESSAGE_LOG (KERN_INFO,
+ "/proc/dasd/devices: '%s'",
+ buffer);
+
if (strncmp (buffer, "set ", 4) == 0) {
/* handle 'set <devno> on/off' */
dasd_proc_set (buffer);
@@ -5270,10 +5297,10 @@
while ( (rc=request_module(name)) != 0 ) {
DECLARE_WAIT_QUEUE_HEAD(wait);
- MESSAGE (KERN_INFO,
- "request_module returned %d for %s",
- rc,
- (char*)name);
+ MESSAGE_LOG (KERN_INFO,
+ "request_module returned %d for %s",
+ rc,
+ (char*)name);
sleep_on_timeout(&wait,5* HZ); /* wait in steps of 5 seconds */
}
@@ -5371,14 +5398,13 @@
irq = get_irq_next (irq)) {
int devno = get_devno_by_irq (irq);
int index = dasd_devindex_from_devno (devno);
- if (index == -ENODEV) { /* not included in ranges */
+ if (index < 0) { /* not included in ranges */
DBF_EVENT (DBF_CRIT,
"add %04x to range",
devno);
- dasd_add_range (devno,
- devno,
+ dasd_add_range (devno, devno,
DASD_FEATURE_DEFAULT);
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)