* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
- * $Revision: 1.147 $
+ * $Revision: 1.151 $
*/
#include <linux/config.h>
dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
{
struct request *req;
+ struct dasd_device *device;
+ int status;
req = (struct request *) data;
- dasd_profile_end(cqr->device, cqr, req);
- spin_lock_irq(&cqr->device->request_queue_lock);
- dasd_end_request(req, (cqr->status == DASD_CQR_DONE));
- spin_unlock_irq(&cqr->device->request_queue_lock);
- dasd_sfree_request(cqr, cqr->device);
+ device = cqr->device;
+ dasd_profile_end(device, cqr, req);
+ status = cqr->device->discipline->free_cp(cqr,req);
+ spin_lock_irq(&device->request_queue_lock);
+ dasd_end_request(req, status);
+ spin_unlock_irq(&device->request_queue_lock);
}
dasd_schedule_bh(device);
} else {
list_for_each_entry(cqr, &device->ccw_queue, list)
- if (cqr->status == DASD_CQR_IN_IO)
+ if (cqr->status == DASD_CQR_IN_IO) {
cqr->status = DASD_CQR_QUEUED;
+ cqr->retries++;
+ }
device->stopped |= DASD_STOPPED_DC_WAIT;
dasd_set_timer(device, 0);
}
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
*
- * $Revision: 1.33 $
+ * $Revision: 1.34 $
*/
#include <linux/timer.h>
dasd_3990_erp_block_queue(erp, 30*HZ);
+ } else if (sense[25] == 0x1E) { /* busy */
+ DEV_MESSAGE(KERN_INFO, device,
+ "busy - redriving request later, "
+ "%d retries left",
+ erp->retries);
+ dasd_3990_erp_block_queue(erp, HZ);
} else {
/* no state change pending - retry */
"fetch mode active");
/* not possible to handle this situation in Linux */
- panic("No way to inform appliction about the possibly "
- "incorret data");
+ panic("No way to inform application about the possibly "
+ "incorrect data");
} else if (sense[2] & SNS2_ENV_DATA_PRESENT) {
erp = dasd_3990_erp_action_4(erp, sense);
break;
+ case 0x1E: /* busy */
+ DEV_MESSAGE(KERN_DEBUG, device, "%s",
+ "Busy condition exists "
+ "for the subsystem or device");
+ erp = dasd_3990_erp_action_4(erp, sense);
+ break;
+
default: /* all others errors - default erp */
break;
}
* functions may not be called from interrupt context. In particular
* dasd_get_device is a no-no from interrupt context.
*
- * $Revision: 1.33 $
+ * $Revision: 1.34 $
*/
#include <linux/config.h>
#include "dasd_int.h"
+kmem_cache_t *dasd_page_cache;
+EXPORT_SYMBOL(dasd_page_cache);
+
/*
* dasd_devmap_t is used to store the features and the relation
* between device number and device index. To find a dasd_devmap_t
"turning to probeonly mode");
return residual_str;
}
+ if (strncmp ("fixedbuffers", parsestring, length) == 0) {
+ if (dasd_page_cache)
+ return residual_str;
+ dasd_page_cache =
+ kmem_cache_create("dasd_page_cache", PAGE_SIZE, 0,
+ SLAB_CACHE_DMA, NULL, NULL );
+ if (!dasd_page_cache)
+ MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
+ "fixed buffer mode disabled.");
+ else
+ MESSAGE (KERN_INFO, "%s",
+ "turning on fixed buffer mode");
+ return residual_str;
+ }
return ERR_PTR(-EINVAL);
}
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.38 $
+ * $Revision: 1.39 $
*/
#include <linux/config.h>
return cqr;
}
+static int
+dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
+{
+ int status;
+
+ status = cqr->status == DASD_CQR_DONE;
+ dasd_sfree_request(cqr, cqr->device);
+ return status;
+}
+
static int
dasd_diag_fill_info(struct dasd_device * device,
struct dasd_information2_t * info)
.erp_action = dasd_diag_erp_action,
.erp_postaction = dasd_diag_erp_postaction,
.build_cp = dasd_diag_build_cp,
+ .free_cp = dasd_diag_free_cp,
.dump_sense = dasd_diag_dump_sense,
.fill_info = dasd_diag_fill_info,
};
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.61 $
+ * $Revision: 1.65 $
*/
#include <linux/config.h>
}
rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
dst = page_address(bv->bv_page) + bv->bv_offset;
+ if (dasd_page_cache) {
+ char *copy = kmem_cache_alloc(dasd_page_cache,
+ SLAB_DMA | __GFP_NOWARN);
+ if (copy && rq_data_dir(req) == WRITE)
+ memcpy(copy + bv->bv_offset, dst, bv->bv_len);
+ if (copy)
+ dst = copy + bv->bv_offset;
+ }
for (off = 0; off < bv->bv_len; off += blksize) {
sector_t trkid = recid;
unsigned int recoffs = sector_div(trkid, blk_per_trk);
return cqr;
}
+static int
+dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
+{
+ struct dasd_eckd_private *private;
+ struct ccw1 *ccw;
+ struct bio *bio;
+ struct bio_vec *bv;
+ char *dst, *cda;
+ unsigned int blksize, blk_per_trk, off;
+ sector_t recid;
+ int i, status;
+
+ if (!dasd_page_cache)
+ goto out;
+ private = (struct dasd_eckd_private *) cqr->device->private;
+ blksize = cqr->device->bp_block;
+ blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+ recid = req->sector >> cqr->device->s2b_shift;
+ ccw = cqr->cpaddr;
+ /* Skip over define extent & locate record. */
+ ccw++;
+ if (private->uses_cdl == 0 || recid > 2*blk_per_trk)
+ ccw++;
+ rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len; off += blksize) {
+ /* Skip locate record. */
+ if (private->uses_cdl && recid <= 2*blk_per_trk)
+ ccw++;
+ if (dst) {
+ if (ccw->flags & CCW_FLAG_IDA)
+ cda = *((char **)((addr_t) ccw->cda));
+ else
+ cda = (char *)((addr_t) ccw->cda);
+ if (dst != cda) {
+ if (rq_data_dir(req) == READ)
+ memcpy(dst, cda, bv->bv_len);
+ kmem_cache_free(dasd_page_cache,
+ (void *)((addr_t)cda & PAGE_MASK));
+ }
+ dst = NULL;
+ }
+ ccw++;
+ recid++;
+ }
+ }
+out:
+ status = cqr->status == DASD_CQR_DONE;
+ dasd_sfree_request(cqr, cqr->device);
+ return status;
+}
+
static int
dasd_eckd_fill_info(struct dasd_device * device,
struct dasd_information2_t * info)
.erp_action = dasd_eckd_erp_action,
.erp_postaction = dasd_eckd_erp_postaction,
.build_cp = dasd_eckd_build_cp,
+ .free_cp = dasd_eckd_free_cp,
.dump_sense = dasd_eckd_dump_sense,
.fill_info = dasd_eckd_fill_info,
};
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.34 $
+ * $Revision: 1.37 $
*/
#include <linux/config.h>
recid = first_rec;
rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
dst = page_address(bv->bv_page) + bv->bv_offset;
+ if (dasd_page_cache) {
+ char *copy = kmem_cache_alloc(dasd_page_cache,
+ SLAB_DMA | __GFP_NOWARN);
+ if (copy && rq_data_dir(req) == WRITE)
+ memcpy(copy + bv->bv_offset, dst, bv->bv_len);
+ if (copy)
+ dst = copy + bv->bv_offset;
+ }
for (off = 0; off < bv->bv_len; off += blksize) {
/* Locate record for stupid devices. */
if (private->rdc_data.mode.bits.data_chain == 0) {
return cqr;
}
+static int
+dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
+{
+ struct dasd_fba_private *private;
+ struct ccw1 *ccw;
+ struct bio *bio;
+ struct bio_vec *bv;
+ char *dst, *cda;
+ unsigned int blksize, off;
+ int i, status;
+
+ if (!dasd_page_cache)
+ goto out;
+ private = (struct dasd_fba_private *) cqr->device->private;
+ blksize = cqr->device->bp_block;
+ ccw = cqr->cpaddr;
+ /* Skip over define extent & locate record. */
+ ccw++;
+ if (private->rdc_data.mode.bits.data_chain != 0)
+ ccw++;
+ rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len; off += blksize) {
+ /* Skip locate record. */
+ if (private->rdc_data.mode.bits.data_chain == 0)
+ ccw++;
+ if (dst) {
+ if (ccw->flags & CCW_FLAG_IDA)
+ cda = *((char **)((addr_t) ccw->cda));
+ else
+ cda = (char *)((addr_t) ccw->cda);
+ if (dst != cda) {
+ if (rq_data_dir(req) == READ)
+ memcpy(dst, cda, bv->bv_len);
+ kmem_cache_free(dasd_page_cache,
+ (void *)((addr_t)cda & PAGE_MASK));
+ }
+ dst = NULL;
+ }
+ ccw++;
+ }
+ }
+out:
+ status = cqr->status == DASD_CQR_DONE;
+ dasd_sfree_request(cqr, cqr->device);
+ return status;
+}
+
static int
dasd_fba_fill_info(struct dasd_device * device,
struct dasd_information2_t * info)
.erp_action = dasd_fba_erp_action,
.erp_postaction = dasd_fba_erp_postaction,
.build_cp = dasd_fba_build_cp,
+ .free_cp = dasd_fba_free_cp,
.dump_sense = dasd_fba_dump_sense,
.fill_info = dasd_fba_fill_info,
};
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.60 $
+ * $Revision: 1.61 $
*/
#ifndef DASD_INT_H
int (*term_IO) (struct dasd_ccw_req *);
struct dasd_ccw_req *(*format_device) (struct dasd_device *,
struct format_data_t *);
-
+ int (*free_cp) (struct dasd_ccw_req *, struct request *);
/*
* Error recovery functions. examine_error() returns a value that
* indicates what to do for an error condition. If examine_error()
extern unsigned int dasd_profile_level;
extern struct block_device_operations dasd_device_operations;
+extern kmem_cache_t *dasd_page_cache;
+
struct dasd_ccw_req *
dasd_kmalloc_request(char *, int, int, struct dasd_device *);
struct dasd_ccw_req *