mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge branch 'for-4.12/block' of git://git.kernel.dk/linux-block
Pull block layer updates from Jens Axboe: - Add BFQ IO scheduler under the new blk-mq scheduling framework. BFQ was initially a fork of CFQ, but subsequently changed to implement fairness based on B-WF2Q+, a modified variant of WF2Q. BFQ is meant to be used on desktop type single drives, providing good fairness. From Paolo. - Add Kyber IO scheduler. This is a full multiqueue aware scheduler, using a scalable token based algorithm that throttles IO based on live completion IO stats, similary to blk-wbt. From Omar. - A series from Jan, moving users to separately allocated backing devices. This continues the work of separating backing device life times, solving various problems with hot removal. - A series of updates for lightnvm, mostly from Javier. Includes a 'pblk' target that exposes an open channel SSD as a physical block device. - A series of fixes and improvements for nbd from Josef. - A series from Omar, removing queue sharing between devices on mostly legacy drivers. This helps us clean up other bits, if we know that a queue only has a single device backing. This has been overdue for more than a decade. - Fixes for the blk-stats, and improvements to unify the stats and user windows. This both improves blk-wbt, and enables other users to register a need to receive IO stats for a device. From Omar. - blk-throttle improvements from Shaohua. This provides a scalable framework for implementing scalable priotization - particularly for blk-mq, but applicable to any type of block device. The interface is marked experimental for now. - Bucketized IO stats for IO polling from Stephen Bates. This improves efficiency of polled workloads in the presence of mixed block size IO. - A few fixes for opal, from Scott. - A few pulls for NVMe, including a lot of fixes for NVMe-over-fabrics. From a variety of folks, mostly Sagi and James Smart. - A series from Bart, improving our exposed info and capabilities from the blk-mq debugfs support. - A series from Christoph, cleaning up how handle WRITE_ZEROES. - A series from Christoph, cleaning up the block layer handling of how we track errors in a request. On top of being a nice cleanup, it also shrinks the size of struct request a bit. - Removal of mg_disk and hd (sorry Linus) by Christoph. The former was never used by platforms, and the latter has outlived it's usefulness. - Various little bug fixes and cleanups from a wide variety of folks. * 'for-4.12/block' of git://git.kernel.dk/linux-block: (329 commits) block: hide badblocks attribute by default blk-mq: unify hctx delay_work and run_work block: add kblock_mod_delayed_work_on() blk-mq: unify hctx delayed_run_work and run_work nbd: fix use after free on module unload MAINTAINERS: bfq: Add Paolo as maintainer for the BFQ I/O scheduler blk-mq-sched: alloate reserved tags out of normal pool mtip32xx: use runtime tag to initialize command header scsi: Implement blk_mq_ops.show_rq() blk-mq: Add blk_mq_ops.show_rq() blk-mq: Show operation, cmd_flags and rq_flags names blk-mq: Make blk_flags_show() callers append a newline character blk-mq: Move the "state" debugfs attribute one level down blk-mq: Unregister debugfs attributes earlier blk-mq: Only unregister hctxs for which registration succeeded blk-mq-debugfs: Rename functions for registering and unregistering the mq directory blk-mq: Let blk_mq_debugfs_register() look up the queue name blk-mq: Register <dev>/queue/mq after having registered <dev>/queue ide-pm: always pass 0 error to ide_complete_rq in ide_do_devset ide-pm: always pass 0 error to __blk_end_request_all ..
This commit is contained in:
commit
694752922b
255 changed files with 24643 additions and 6152 deletions
|
|
@ -312,22 +312,6 @@ config BLK_DEV_SKD
|
|||
|
||||
Use device /dev/skd$N amd /dev/skd$Np$M.
|
||||
|
||||
config BLK_DEV_OSD
|
||||
tristate "OSD object-as-blkdev support"
|
||||
depends on SCSI_OSD_ULD
|
||||
---help---
|
||||
Saying Y or M here will allow the exporting of a single SCSI
|
||||
OSD (object-based storage) object as a Linux block device.
|
||||
|
||||
For example, if you create a 2G object on an OSD device,
|
||||
you can then use this module to present that 2G object as
|
||||
a Linux block device.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called osdblk.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config BLK_DEV_SX8
|
||||
tristate "Promise SATA SX8 support"
|
||||
depends on PCI
|
||||
|
|
@ -434,23 +418,6 @@ config ATA_OVER_ETH
|
|||
This driver provides Support for ATA over Ethernet block
|
||||
devices like the Coraid EtherDrive (R) Storage Blade.
|
||||
|
||||
config MG_DISK
|
||||
tristate "mGine mflash, gflash support"
|
||||
depends on ARM && GPIOLIB
|
||||
help
|
||||
mGine mFlash(gFlash) block device driver
|
||||
|
||||
config MG_DISK_RES
|
||||
int "Size of reserved area before MBR"
|
||||
depends on MG_DISK
|
||||
default 0
|
||||
help
|
||||
Define size of reserved area that usually used for boot. Unit is KB.
|
||||
All of the block device operation will be taken this value as start
|
||||
offset
|
||||
Examples:
|
||||
1024 => 1 MB
|
||||
|
||||
config SUNVDC
|
||||
tristate "Sun Virtual Disk Client support"
|
||||
depends on SUN_LDOMS
|
||||
|
|
@ -512,19 +479,7 @@ config VIRTIO_BLK_SCSI
|
|||
Enable support for SCSI passthrough (e.g. the SG_IO ioctl) on
|
||||
virtio-blk devices. This is only supported for the legacy
|
||||
virtio protocol and not enabled by default by any hypervisor.
|
||||
Your probably want to virtio-scsi instead.
|
||||
|
||||
config BLK_DEV_HD
|
||||
bool "Very old hard disk (MFM/RLL/IDE) driver"
|
||||
depends on HAVE_IDE
|
||||
depends on !ARM || ARCH_RPC || BROKEN
|
||||
help
|
||||
This is a very old hard disk driver that lacks the enhanced
|
||||
functionality of the newer ones.
|
||||
|
||||
It is required for systems with ancient MFM/RLL/ESDI drives.
|
||||
|
||||
If unsure, say N.
|
||||
You probably want to use virtio-scsi instead.
|
||||
|
||||
config BLK_DEV_RBD
|
||||
tristate "Rados block device (RBD)"
|
||||
|
|
|
|||
|
|
@ -19,10 +19,8 @@ obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
|
|||
obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o
|
||||
obj-$(CONFIG_XILINX_SYSACE) += xsysace.o
|
||||
obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o
|
||||
obj-$(CONFIG_MG_DISK) += mg_disk.o
|
||||
obj-$(CONFIG_SUNVDC) += sunvdc.o
|
||||
obj-$(CONFIG_BLK_DEV_SKD) += skd.o
|
||||
obj-$(CONFIG_BLK_DEV_OSD) += osdblk.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_UMEM) += umem.o
|
||||
obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
|
||||
|
|
@ -30,7 +28,6 @@ obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
|
|||
obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
|
||||
obj-$(CONFIG_BLK_DEV_HD) += hd.o
|
||||
|
||||
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
|
||||
obj-$(CONFIG_XEN_BLKDEV_BACKEND) += xen-blkback/
|
||||
|
|
|
|||
|
|
@ -617,12 +617,12 @@ static void fd_error( void )
|
|||
if (!fd_request)
|
||||
return;
|
||||
|
||||
fd_request->errors++;
|
||||
if (fd_request->errors >= MAX_ERRORS) {
|
||||
fd_request->error_count++;
|
||||
if (fd_request->error_count >= MAX_ERRORS) {
|
||||
printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
|
||||
fd_end_request_cur(-EIO);
|
||||
}
|
||||
else if (fd_request->errors == RECALIBRATE_ERRORS) {
|
||||
else if (fd_request->error_count == RECALIBRATE_ERRORS) {
|
||||
printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );
|
||||
if (SelectedDrive != -1)
|
||||
SUD.track = -1;
|
||||
|
|
@ -1386,7 +1386,7 @@ static void setup_req_params( int drive )
|
|||
ReqData = ReqBuffer + 512 * ReqCnt;
|
||||
|
||||
if (UseTrackbuffer)
|
||||
read_track = (ReqCmd == READ && fd_request->errors == 0);
|
||||
read_track = (ReqCmd == READ && fd_request->error_count == 0);
|
||||
else
|
||||
read_track = 0;
|
||||
|
||||
|
|
@ -1409,8 +1409,10 @@ static struct request *set_next_request(void)
|
|||
fdc_queue = 0;
|
||||
if (q) {
|
||||
rq = blk_fetch_request(q);
|
||||
if (rq)
|
||||
if (rq) {
|
||||
rq->error_count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (fdc_queue != old_pos);
|
||||
|
||||
|
|
|
|||
|
|
@ -134,28 +134,6 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
|
|||
return page;
|
||||
}
|
||||
|
||||
static void brd_free_page(struct brd_device *brd, sector_t sector)
|
||||
{
|
||||
struct page *page;
|
||||
pgoff_t idx;
|
||||
|
||||
spin_lock(&brd->brd_lock);
|
||||
idx = sector >> PAGE_SECTORS_SHIFT;
|
||||
page = radix_tree_delete(&brd->brd_pages, idx);
|
||||
spin_unlock(&brd->brd_lock);
|
||||
if (page)
|
||||
__free_page(page);
|
||||
}
|
||||
|
||||
static void brd_zero_page(struct brd_device *brd, sector_t sector)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
page = brd_lookup_page(brd, sector);
|
||||
if (page)
|
||||
clear_highpage(page);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all backing store pages and radix tree. This must only be called when
|
||||
* there are no other users of the device.
|
||||
|
|
@ -212,24 +190,6 @@ static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void discard_from_brd(struct brd_device *brd,
|
||||
sector_t sector, size_t n)
|
||||
{
|
||||
while (n >= PAGE_SIZE) {
|
||||
/*
|
||||
* Don't want to actually discard pages here because
|
||||
* re-allocating the pages can result in writeback
|
||||
* deadlocks under heavy load.
|
||||
*/
|
||||
if (0)
|
||||
brd_free_page(brd, sector);
|
||||
else
|
||||
brd_zero_page(brd, sector);
|
||||
sector += PAGE_SIZE >> SECTOR_SHIFT;
|
||||
n -= PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy n bytes from src to the brd starting at sector. Does not sleep.
|
||||
*/
|
||||
|
|
@ -338,14 +298,6 @@ static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
|
|||
if (bio_end_sector(bio) > get_capacity(bdev->bd_disk))
|
||||
goto io_error;
|
||||
|
||||
if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
|
||||
if (sector & ((PAGE_SIZE >> SECTOR_SHIFT) - 1) ||
|
||||
bio->bi_iter.bi_size & ~PAGE_MASK)
|
||||
goto io_error;
|
||||
discard_from_brd(brd, sector, bio->bi_iter.bi_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
unsigned int len = bvec.bv_len;
|
||||
int err;
|
||||
|
|
@ -357,7 +309,6 @@ static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
|
|||
sector += len >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
out:
|
||||
bio_endio(bio);
|
||||
return BLK_QC_T_NONE;
|
||||
io_error:
|
||||
|
|
@ -464,11 +415,6 @@ static struct brd_device *brd_alloc(int i)
|
|||
* is harmless)
|
||||
*/
|
||||
blk_queue_physical_block_size(brd->brd_queue, PAGE_SIZE);
|
||||
|
||||
brd->brd_queue->limits.discard_granularity = PAGE_SIZE;
|
||||
blk_queue_max_discard_sectors(brd->brd_queue, UINT_MAX);
|
||||
brd->brd_queue->limits.discard_zeroes_data = 1;
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue);
|
||||
#ifdef CONFIG_BLK_DEV_RAM_DAX
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DAX, brd->brd_queue);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1864,8 +1864,7 @@ static void cciss_softirq_done(struct request *rq)
|
|||
/* set the residual count for pc requests */
|
||||
if (blk_rq_is_passthrough(rq))
|
||||
scsi_req(rq)->resid_len = c->err_info->ResidualCnt;
|
||||
|
||||
blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO);
|
||||
blk_end_request_all(rq, scsi_req(rq)->result ? -EIO : 0);
|
||||
|
||||
spin_lock_irqsave(&h->lock, flags);
|
||||
cmd_free(h, c);
|
||||
|
|
@ -3140,18 +3139,19 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
{
|
||||
int retry_cmd = 0;
|
||||
struct request *rq = cmd->rq;
|
||||
struct scsi_request *sreq = scsi_req(rq);
|
||||
|
||||
rq->errors = 0;
|
||||
sreq->result = 0;
|
||||
|
||||
if (timeout)
|
||||
rq->errors = make_status_bytes(0, 0, 0, DRIVER_TIMEOUT);
|
||||
sreq->result = make_status_bytes(0, 0, 0, DRIVER_TIMEOUT);
|
||||
|
||||
if (cmd->err_info->CommandStatus == 0) /* no error has occurred */
|
||||
goto after_error_processing;
|
||||
|
||||
switch (cmd->err_info->CommandStatus) {
|
||||
case CMD_TARGET_STATUS:
|
||||
rq->errors = evaluate_target_status(h, cmd, &retry_cmd);
|
||||
sreq->result = evaluate_target_status(h, cmd, &retry_cmd);
|
||||
break;
|
||||
case CMD_DATA_UNDERRUN:
|
||||
if (!blk_rq_is_passthrough(cmd->rq)) {
|
||||
|
|
@ -3169,7 +3169,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
case CMD_INVALID:
|
||||
dev_warn(&h->pdev->dev, "cciss: cmd %p is "
|
||||
"reported invalid\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ERROR);
|
||||
|
|
@ -3177,7 +3177,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
case CMD_PROTOCOL_ERR:
|
||||
dev_warn(&h->pdev->dev, "cciss: cmd %p has "
|
||||
"protocol error\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ERROR);
|
||||
|
|
@ -3185,7 +3185,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
case CMD_HARDWARE_ERR:
|
||||
dev_warn(&h->pdev->dev, "cciss: cmd %p had "
|
||||
" hardware error\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ERROR);
|
||||
|
|
@ -3193,7 +3193,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
case CMD_CONNECTION_LOST:
|
||||
dev_warn(&h->pdev->dev, "cciss: cmd %p had "
|
||||
"connection lost\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ERROR);
|
||||
|
|
@ -3201,7 +3201,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
case CMD_ABORTED:
|
||||
dev_warn(&h->pdev->dev, "cciss: cmd %p was "
|
||||
"aborted\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ABORT);
|
||||
|
|
@ -3209,7 +3209,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
case CMD_ABORT_FAILED:
|
||||
dev_warn(&h->pdev->dev, "cciss: cmd %p reports "
|
||||
"abort failed\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ERROR);
|
||||
|
|
@ -3224,21 +3224,21 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
} else
|
||||
dev_warn(&h->pdev->dev,
|
||||
"%p retried too many times\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ABORT);
|
||||
break;
|
||||
case CMD_TIMEOUT:
|
||||
dev_warn(&h->pdev->dev, "cmd %p timedout\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ERROR);
|
||||
break;
|
||||
case CMD_UNABORTABLE:
|
||||
dev_warn(&h->pdev->dev, "cmd %p unabortable\n", cmd);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ERROR);
|
||||
|
|
@ -3247,7 +3247,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
|
|||
dev_warn(&h->pdev->dev, "cmd %p returned "
|
||||
"unknown status %x\n", cmd,
|
||||
cmd->err_info->CommandStatus);
|
||||
rq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
sreq->result = make_status_bytes(SAM_STAT_GOOD,
|
||||
cmd->err_info->CommandStatus, DRIVER_OK,
|
||||
blk_rq_is_passthrough(cmd->rq) ?
|
||||
DID_PASSTHROUGH : DID_ERROR);
|
||||
|
|
@ -3380,9 +3380,9 @@ static void do_cciss_request(struct request_queue *q)
|
|||
if (dma_mapping_error(&h->pdev->dev, temp64.val)) {
|
||||
dev_warn(&h->pdev->dev,
|
||||
"%s: error mapping page for DMA\n", __func__);
|
||||
creq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
0, DRIVER_OK,
|
||||
DID_SOFT_ERROR);
|
||||
scsi_req(creq)->result =
|
||||
make_status_bytes(SAM_STAT_GOOD, 0, DRIVER_OK,
|
||||
DID_SOFT_ERROR);
|
||||
cmd_free(h, c);
|
||||
return;
|
||||
}
|
||||
|
|
@ -3395,9 +3395,9 @@ static void do_cciss_request(struct request_queue *q)
|
|||
if (cciss_map_sg_chain_block(h, c, h->cmd_sg_list[c->cmdindex],
|
||||
(seg - (h->max_cmd_sgentries - 1)) *
|
||||
sizeof(SGDescriptor_struct))) {
|
||||
creq->errors = make_status_bytes(SAM_STAT_GOOD,
|
||||
0, DRIVER_OK,
|
||||
DID_SOFT_ERROR);
|
||||
scsi_req(creq)->result =
|
||||
make_status_bytes(SAM_STAT_GOOD, 0, DRIVER_OK,
|
||||
DID_SOFT_ERROR);
|
||||
cmd_free(h, c);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,9 +236,6 @@ static void seq_print_peer_request_flags(struct seq_file *m, struct drbd_peer_re
|
|||
seq_print_rq_state_bit(m, f & EE_CALL_AL_COMPLETE_IO, &sep, "in-AL");
|
||||
seq_print_rq_state_bit(m, f & EE_SEND_WRITE_ACK, &sep, "C");
|
||||
seq_print_rq_state_bit(m, f & EE_MAY_SET_IN_SYNC, &sep, "set-in-sync");
|
||||
|
||||
if (f & EE_IS_TRIM)
|
||||
__seq_print_rq_state_bit(m, f & EE_IS_TRIM_USE_ZEROOUT, &sep, "zero-out", "trim");
|
||||
seq_print_rq_state_bit(m, f & EE_WRITE_SAME, &sep, "write-same");
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -437,9 +437,6 @@ enum {
|
|||
|
||||
/* is this a TRIM aka REQ_DISCARD? */
|
||||
__EE_IS_TRIM,
|
||||
/* our lower level cannot handle trim,
|
||||
* and we want to fall back to zeroout instead */
|
||||
__EE_IS_TRIM_USE_ZEROOUT,
|
||||
|
||||
/* In case a barrier failed,
|
||||
* we need to resubmit without the barrier flag. */
|
||||
|
|
@ -482,7 +479,6 @@ enum {
|
|||
#define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
|
||||
#define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC)
|
||||
#define EE_IS_TRIM (1<<__EE_IS_TRIM)
|
||||
#define EE_IS_TRIM_USE_ZEROOUT (1<<__EE_IS_TRIM_USE_ZEROOUT)
|
||||
#define EE_RESUBMITTED (1<<__EE_RESUBMITTED)
|
||||
#define EE_WAS_ERROR (1<<__EE_WAS_ERROR)
|
||||
#define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST)
|
||||
|
|
@ -1561,8 +1557,6 @@ extern void start_resync_timer_fn(unsigned long data);
|
|||
extern void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req);
|
||||
|
||||
/* drbd_receiver.c */
|
||||
extern int drbd_issue_discard_or_zero_out(struct drbd_device *device,
|
||||
sector_t start, unsigned int nr_sectors, bool discard);
|
||||
extern int drbd_receiver(struct drbd_thread *thi);
|
||||
extern int drbd_ack_receiver(struct drbd_thread *thi);
|
||||
extern void drbd_send_ping_wf(struct work_struct *ws);
|
||||
|
|
|
|||
|
|
@ -931,7 +931,6 @@ void assign_p_sizes_qlim(struct drbd_device *device, struct p_sizes *p, struct r
|
|||
p->qlim->io_min = cpu_to_be32(queue_io_min(q));
|
||||
p->qlim->io_opt = cpu_to_be32(queue_io_opt(q));
|
||||
p->qlim->discard_enabled = blk_queue_discard(q);
|
||||
p->qlim->discard_zeroes_data = queue_discard_zeroes_data(q);
|
||||
p->qlim->write_same_capable = !!q->limits.max_write_same_sectors;
|
||||
} else {
|
||||
q = device->rq_queue;
|
||||
|
|
@ -941,7 +940,6 @@ void assign_p_sizes_qlim(struct drbd_device *device, struct p_sizes *p, struct r
|
|||
p->qlim->io_min = cpu_to_be32(queue_io_min(q));
|
||||
p->qlim->io_opt = cpu_to_be32(queue_io_opt(q));
|
||||
p->qlim->discard_enabled = 0;
|
||||
p->qlim->discard_zeroes_data = 0;
|
||||
p->qlim->write_same_capable = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1668,7 +1666,8 @@ static u32 bio_flags_to_wire(struct drbd_connection *connection,
|
|||
(bio->bi_opf & REQ_FUA ? DP_FUA : 0) |
|
||||
(bio->bi_opf & REQ_PREFLUSH ? DP_FLUSH : 0) |
|
||||
(bio_op(bio) == REQ_OP_WRITE_SAME ? DP_WSAME : 0) |
|
||||
(bio_op(bio) == REQ_OP_DISCARD ? DP_DISCARD : 0);
|
||||
(bio_op(bio) == REQ_OP_DISCARD ? DP_DISCARD : 0) |
|
||||
(bio_op(bio) == REQ_OP_WRITE_ZEROES ? DP_DISCARD : 0);
|
||||
else
|
||||
return bio->bi_opf & REQ_SYNC ? DP_RW_SYNC : 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1199,10 +1199,6 @@ static void decide_on_discard_support(struct drbd_device *device,
|
|||
struct drbd_connection *connection = first_peer_device(device)->connection;
|
||||
bool can_do = b ? blk_queue_discard(b) : true;
|
||||
|
||||
if (can_do && b && !b->limits.discard_zeroes_data && !discard_zeroes_if_aligned) {
|
||||
can_do = false;
|
||||
drbd_info(device, "discard_zeroes_data=0 and discard_zeroes_if_aligned=no: disabling discards\n");
|
||||
}
|
||||
if (can_do && connection->cstate >= C_CONNECTED && !(connection->agreed_features & DRBD_FF_TRIM)) {
|
||||
can_do = false;
|
||||
drbd_info(connection, "peer DRBD too old, does not support TRIM: disabling discards\n");
|
||||
|
|
@ -1217,10 +1213,12 @@ static void decide_on_discard_support(struct drbd_device *device,
|
|||
blk_queue_discard_granularity(q, 512);
|
||||
q->limits.max_discard_sectors = drbd_max_discard_sectors(connection);
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
|
||||
q->limits.max_write_zeroes_sectors = drbd_max_discard_sectors(connection);
|
||||
} else {
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
|
||||
blk_queue_discard_granularity(q, 0);
|
||||
q->limits.max_discard_sectors = 0;
|
||||
q->limits.max_write_zeroes_sectors = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1482,8 +1480,7 @@ static void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *dis
|
|||
if (disk_conf->al_extents > drbd_al_extents_max(nbc))
|
||||
disk_conf->al_extents = drbd_al_extents_max(nbc);
|
||||
|
||||
if (!blk_queue_discard(q)
|
||||
|| (!q->limits.discard_zeroes_data && !disk_conf->discard_zeroes_if_aligned)) {
|
||||
if (!blk_queue_discard(q)) {
|
||||
if (disk_conf->rs_discard_granularity) {
|
||||
disk_conf->rs_discard_granularity = 0; /* disable feature */
|
||||
drbd_info(device, "rs_discard_granularity feature disabled\n");
|
||||
|
|
|
|||
|
|
@ -1448,105 +1448,14 @@ void drbd_bump_write_ordering(struct drbd_resource *resource, struct drbd_backin
|
|||
drbd_info(resource, "Method to ensure write ordering: %s\n", write_ordering_str[resource->write_ordering]);
|
||||
}
|
||||
|
||||
/*
|
||||
* We *may* ignore the discard-zeroes-data setting, if so configured.
|
||||
*
|
||||
* Assumption is that it "discard_zeroes_data=0" is only because the backend
|
||||
* may ignore partial unaligned discards.
|
||||
*
|
||||
* LVM/DM thin as of at least
|
||||
* LVM version: 2.02.115(2)-RHEL7 (2015-01-28)
|
||||
* Library version: 1.02.93-RHEL7 (2015-01-28)
|
||||
* Driver version: 4.29.0
|
||||
* still behaves this way.
|
||||
*
|
||||
* For unaligned (wrt. alignment and granularity) or too small discards,
|
||||
* we zero-out the initial (and/or) trailing unaligned partial chunks,
|
||||
* but discard all the aligned full chunks.
|
||||
*
|
||||
* At least for LVM/DM thin, the result is effectively "discard_zeroes_data=1".
|
||||
*/
|
||||
int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, unsigned int nr_sectors, bool discard)
|
||||
{
|
||||
struct block_device *bdev = device->ldev->backing_bdev;
|
||||
struct request_queue *q = bdev_get_queue(bdev);
|
||||
sector_t tmp, nr;
|
||||
unsigned int max_discard_sectors, granularity;
|
||||
int alignment;
|
||||
int err = 0;
|
||||
|
||||
if (!discard)
|
||||
goto zero_out;
|
||||
|
||||
/* Zero-sector (unknown) and one-sector granularities are the same. */
|
||||
granularity = max(q->limits.discard_granularity >> 9, 1U);
|
||||
alignment = (bdev_discard_alignment(bdev) >> 9) % granularity;
|
||||
|
||||
max_discard_sectors = min(q->limits.max_discard_sectors, (1U << 22));
|
||||
max_discard_sectors -= max_discard_sectors % granularity;
|
||||
if (unlikely(!max_discard_sectors))
|
||||
goto zero_out;
|
||||
|
||||
if (nr_sectors < granularity)
|
||||
goto zero_out;
|
||||
|
||||
tmp = start;
|
||||
if (sector_div(tmp, granularity) != alignment) {
|
||||
if (nr_sectors < 2*granularity)
|
||||
goto zero_out;
|
||||
/* start + gran - (start + gran - align) % gran */
|
||||
tmp = start + granularity - alignment;
|
||||
tmp = start + granularity - sector_div(tmp, granularity);
|
||||
|
||||
nr = tmp - start;
|
||||
err |= blkdev_issue_zeroout(bdev, start, nr, GFP_NOIO, 0);
|
||||
nr_sectors -= nr;
|
||||
start = tmp;
|
||||
}
|
||||
while (nr_sectors >= granularity) {
|
||||
nr = min_t(sector_t, nr_sectors, max_discard_sectors);
|
||||
err |= blkdev_issue_discard(bdev, start, nr, GFP_NOIO, 0);
|
||||
nr_sectors -= nr;
|
||||
start += nr;
|
||||
}
|
||||
zero_out:
|
||||
if (nr_sectors) {
|
||||
err |= blkdev_issue_zeroout(bdev, start, nr_sectors, GFP_NOIO, 0);
|
||||
}
|
||||
return err != 0;
|
||||
}
|
||||
|
||||
static bool can_do_reliable_discards(struct drbd_device *device)
|
||||
{
|
||||
struct request_queue *q = bdev_get_queue(device->ldev->backing_bdev);
|
||||
struct disk_conf *dc;
|
||||
bool can_do;
|
||||
|
||||
if (!blk_queue_discard(q))
|
||||
return false;
|
||||
|
||||
if (q->limits.discard_zeroes_data)
|
||||
return true;
|
||||
|
||||
rcu_read_lock();
|
||||
dc = rcu_dereference(device->ldev->disk_conf);
|
||||
can_do = dc->discard_zeroes_if_aligned;
|
||||
rcu_read_unlock();
|
||||
return can_do;
|
||||
}
|
||||
|
||||
static void drbd_issue_peer_discard(struct drbd_device *device, struct drbd_peer_request *peer_req)
|
||||
{
|
||||
/* If the backend cannot discard, or does not guarantee
|
||||
* read-back zeroes in discarded ranges, we fall back to
|
||||
* zero-out. Unless configuration specifically requested
|
||||
* otherwise. */
|
||||
if (!can_do_reliable_discards(device))
|
||||
peer_req->flags |= EE_IS_TRIM_USE_ZEROOUT;
|
||||
struct block_device *bdev = device->ldev->backing_bdev;
|
||||
|
||||
if (drbd_issue_discard_or_zero_out(device, peer_req->i.sector,
|
||||
peer_req->i.size >> 9, !(peer_req->flags & EE_IS_TRIM_USE_ZEROOUT)))
|
||||
if (blkdev_issue_zeroout(bdev, peer_req->i.sector, peer_req->i.size >> 9,
|
||||
GFP_NOIO, 0))
|
||||
peer_req->flags |= EE_WAS_ERROR;
|
||||
|
||||
drbd_endio_write_sec_final(peer_req);
|
||||
}
|
||||
|
||||
|
|
@ -2376,7 +2285,7 @@ static unsigned long wire_flags_to_bio_flags(u32 dpf)
|
|||
static unsigned long wire_flags_to_bio_op(u32 dpf)
|
||||
{
|
||||
if (dpf & DP_DISCARD)
|
||||
return REQ_OP_DISCARD;
|
||||
return REQ_OP_WRITE_ZEROES;
|
||||
else
|
||||
return REQ_OP_WRITE;
|
||||
}
|
||||
|
|
@ -2567,7 +2476,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
|
|||
op_flags = wire_flags_to_bio_flags(dp_flags);
|
||||
if (pi->cmd == P_TRIM) {
|
||||
D_ASSERT(peer_device, peer_req->i.size > 0);
|
||||
D_ASSERT(peer_device, op == REQ_OP_DISCARD);
|
||||
D_ASSERT(peer_device, op == REQ_OP_WRITE_ZEROES);
|
||||
D_ASSERT(peer_device, peer_req->pages == NULL);
|
||||
} else if (peer_req->pages == NULL) {
|
||||
D_ASSERT(device, peer_req->i.size == 0);
|
||||
|
|
@ -4880,7 +4789,7 @@ static int receive_rs_deallocated(struct drbd_connection *connection, struct pac
|
|||
|
||||
if (get_ldev(device)) {
|
||||
struct drbd_peer_request *peer_req;
|
||||
const int op = REQ_OP_DISCARD;
|
||||
const int op = REQ_OP_WRITE_ZEROES;
|
||||
|
||||
peer_req = drbd_alloc_peer_req(peer_device, ID_SYNCER, sector,
|
||||
size, 0, GFP_NOIO);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ static struct drbd_request *drbd_req_new(struct drbd_device *device, struct bio
|
|||
drbd_req_make_private_bio(req, bio_src);
|
||||
req->rq_state = (bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0)
|
||||
| (bio_op(bio_src) == REQ_OP_WRITE_SAME ? RQ_WSAME : 0)
|
||||
| (bio_op(bio_src) == REQ_OP_WRITE_ZEROES ? RQ_UNMAP : 0)
|
||||
| (bio_op(bio_src) == REQ_OP_DISCARD ? RQ_UNMAP : 0);
|
||||
req->device = device;
|
||||
req->master_bio = bio_src;
|
||||
|
|
@ -1148,10 +1149,10 @@ static int drbd_process_write_request(struct drbd_request *req)
|
|||
|
||||
static void drbd_process_discard_req(struct drbd_request *req)
|
||||
{
|
||||
int err = drbd_issue_discard_or_zero_out(req->device,
|
||||
req->i.sector, req->i.size >> 9, true);
|
||||
struct block_device *bdev = req->device->ldev->backing_bdev;
|
||||
|
||||
if (err)
|
||||
if (blkdev_issue_zeroout(bdev, req->i.sector, req->i.size >> 9,
|
||||
GFP_NOIO, 0))
|
||||
req->private_bio->bi_error = -EIO;
|
||||
bio_endio(req->private_bio);
|
||||
}
|
||||
|
|
@ -1180,7 +1181,8 @@ drbd_submit_req_private_bio(struct drbd_request *req)
|
|||
if (get_ldev(device)) {
|
||||
if (drbd_insert_fault(device, type))
|
||||
bio_io_error(bio);
|
||||
else if (bio_op(bio) == REQ_OP_DISCARD)
|
||||
else if (bio_op(bio) == REQ_OP_WRITE_ZEROES ||
|
||||
bio_op(bio) == REQ_OP_DISCARD)
|
||||
drbd_process_discard_req(req);
|
||||
else
|
||||
generic_make_request(bio);
|
||||
|
|
@ -1234,7 +1236,8 @@ drbd_request_prepare(struct drbd_device *device, struct bio *bio, unsigned long
|
|||
_drbd_start_io_acct(device, req);
|
||||
|
||||
/* process discards always from our submitter thread */
|
||||
if (bio_op(bio) & REQ_OP_DISCARD)
|
||||
if ((bio_op(bio) & REQ_OP_WRITE_ZEROES) ||
|
||||
(bio_op(bio) & REQ_OP_DISCARD))
|
||||
goto queue_for_submitter_thread;
|
||||
|
||||
if (rw == WRITE && req->private_bio && req->i.size
|
||||
|
|
|
|||
|
|
@ -174,7 +174,8 @@ void drbd_peer_request_endio(struct bio *bio)
|
|||
struct drbd_peer_request *peer_req = bio->bi_private;
|
||||
struct drbd_device *device = peer_req->peer_device->device;
|
||||
bool is_write = bio_data_dir(bio) == WRITE;
|
||||
bool is_discard = !!(bio_op(bio) == REQ_OP_DISCARD);
|
||||
bool is_discard = bio_op(bio) == REQ_OP_WRITE_ZEROES ||
|
||||
bio_op(bio) == REQ_OP_DISCARD;
|
||||
|
||||
if (bio->bi_error && __ratelimit(&drbd_ratelimit_state))
|
||||
drbd_warn(device, "%s: error=%d s=%llus\n",
|
||||
|
|
@ -249,6 +250,7 @@ void drbd_request_endio(struct bio *bio)
|
|||
/* to avoid recursion in __req_mod */
|
||||
if (unlikely(bio->bi_error)) {
|
||||
switch (bio_op(bio)) {
|
||||
case REQ_OP_WRITE_ZEROES:
|
||||
case REQ_OP_DISCARD:
|
||||
if (bio->bi_error == -EOPNOTSUPP)
|
||||
what = DISCARD_COMPLETED_NOTSUPP;
|
||||
|
|
|
|||
|
|
@ -2805,8 +2805,10 @@ static int set_next_request(void)
|
|||
fdc_queue = 0;
|
||||
if (q) {
|
||||
current_req = blk_fetch_request(q);
|
||||
if (current_req)
|
||||
if (current_req) {
|
||||
current_req->error_count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (fdc_queue != old_pos);
|
||||
|
||||
|
|
@ -2866,7 +2868,7 @@ do_request:
|
|||
_floppy = floppy_type + DP->autodetect[DRS->probed_format];
|
||||
} else
|
||||
probing = 0;
|
||||
errors = &(current_req->errors);
|
||||
errors = &(current_req->error_count);
|
||||
tmp = make_raw_rw_request();
|
||||
if (tmp < 2) {
|
||||
request_done(tmp);
|
||||
|
|
@ -4207,9 +4209,7 @@ static int __init do_floppy_init(void)
|
|||
disks[drive]->fops = &floppy_fops;
|
||||
sprintf(disks[drive]->disk_name, "fd%d", drive);
|
||||
|
||||
init_timer(&motor_off_timer[drive]);
|
||||
motor_off_timer[drive].data = drive;
|
||||
motor_off_timer[drive].function = motor_off_callback;
|
||||
setup_timer(&motor_off_timer[drive], motor_off_callback, drive);
|
||||
}
|
||||
|
||||
err = register_blkdev(FLOPPY_MAJOR, "fd");
|
||||
|
|
|
|||
|
|
@ -1,803 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*
|
||||
* This is the low-level hd interrupt support. It traverses the
|
||||
* request-list, using interrupts to jump between functions. As
|
||||
* all the functions are called within interrupts, we may not
|
||||
* sleep. Special care is recommended.
|
||||
*
|
||||
* modified by Drew Eckhardt to check nr of hd's from the CMOS.
|
||||
*
|
||||
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
|
||||
* in the early extended-partition checks and added DM partitions
|
||||
*
|
||||
* IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
|
||||
* and general streamlining by Mark Lord.
|
||||
*
|
||||
* Removed 99% of above. Use Mark's ide driver for those options.
|
||||
* This is now a lightweight ST-506 driver. (Paul Gortmaker)
|
||||
*
|
||||
* Modified 1995 Russell King for ARM processor.
|
||||
*
|
||||
* Bugfix: max_sectors must be <= 255 or the wheels tend to come
|
||||
* off in a hurry once you queue things up - Paul G. 02/2001
|
||||
*/
|
||||
|
||||
/* Uncomment the following if you want verbose error reports. */
|
||||
/* #define VERBOSE_ERRORS */
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/blkpg.h>
|
||||
#include <linux/ata.h>
|
||||
#include <linux/hdreg.h>
|
||||
|
||||
#define HD_IRQ 14
|
||||
|
||||
#define REALLY_SLOW_IO
|
||||
#include <asm/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#ifdef __arm__
|
||||
#undef HD_IRQ
|
||||
#endif
|
||||
#include <asm/irq.h>
|
||||
#ifdef __arm__
|
||||
#define HD_IRQ IRQ_HARDDISK
|
||||
#endif
|
||||
|
||||
/* Hd controller regster ports */
|
||||
|
||||
#define HD_DATA 0x1f0 /* _CTL when writing */
|
||||
#define HD_ERROR 0x1f1 /* see err-bits */
|
||||
#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */
|
||||
#define HD_SECTOR 0x1f3 /* starting sector */
|
||||
#define HD_LCYL 0x1f4 /* starting cylinder */
|
||||
#define HD_HCYL 0x1f5 /* high byte of starting cyl */
|
||||
#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */
|
||||
#define HD_STATUS 0x1f7 /* see status-bits */
|
||||
#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */
|
||||
#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
|
||||
#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
|
||||
|
||||
#define HD_CMD 0x3f6 /* used for resets */
|
||||
#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */
|
||||
|
||||
/* Bits of HD_STATUS */
|
||||
#define ERR_STAT 0x01
|
||||
#define INDEX_STAT 0x02
|
||||
#define ECC_STAT 0x04 /* Corrected error */
|
||||
#define DRQ_STAT 0x08
|
||||
#define SEEK_STAT 0x10
|
||||
#define SERVICE_STAT SEEK_STAT
|
||||
#define WRERR_STAT 0x20
|
||||
#define READY_STAT 0x40
|
||||
#define BUSY_STAT 0x80
|
||||
|
||||
/* Bits for HD_ERROR */
|
||||
#define MARK_ERR 0x01 /* Bad address mark */
|
||||
#define TRK0_ERR 0x02 /* couldn't find track 0 */
|
||||
#define ABRT_ERR 0x04 /* Command aborted */
|
||||
#define MCR_ERR 0x08 /* media change request */
|
||||
#define ID_ERR 0x10 /* ID field not found */
|
||||
#define MC_ERR 0x20 /* media changed */
|
||||
#define ECC_ERR 0x40 /* Uncorrectable ECC error */
|
||||
#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
|
||||
#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
|
||||
|
||||
static DEFINE_SPINLOCK(hd_lock);
|
||||
static struct request_queue *hd_queue;
|
||||
static struct request *hd_req;
|
||||
|
||||
#define TIMEOUT_VALUE (6*HZ)
|
||||
#define HD_DELAY 0
|
||||
|
||||
#define MAX_ERRORS 16 /* Max read/write errors/sector */
|
||||
#define RESET_FREQ 8 /* Reset controller every 8th retry */
|
||||
#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
|
||||
#define MAX_HD 2
|
||||
|
||||
#define STAT_OK (READY_STAT|SEEK_STAT)
|
||||
#define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
|
||||
|
||||
static void recal_intr(void);
|
||||
static void bad_rw_intr(void);
|
||||
|
||||
static int reset;
|
||||
static int hd_error;
|
||||
|
||||
/*
|
||||
* This struct defines the HD's and their types.
|
||||
*/
|
||||
struct hd_i_struct {
|
||||
unsigned int head, sect, cyl, wpcom, lzone, ctl;
|
||||
int unit;
|
||||
int recalibrate;
|
||||
int special_op;
|
||||
};
|
||||
|
||||
#ifdef HD_TYPE
|
||||
static struct hd_i_struct hd_info[] = { HD_TYPE };
|
||||
static int NR_HD = ARRAY_SIZE(hd_info);
|
||||
#else
|
||||
static struct hd_i_struct hd_info[MAX_HD];
|
||||
static int NR_HD;
|
||||
#endif
|
||||
|
||||
static struct gendisk *hd_gendisk[MAX_HD];
|
||||
|
||||
static struct timer_list device_timer;
|
||||
|
||||
#define TIMEOUT_VALUE (6*HZ)
|
||||
|
||||
#define SET_TIMER \
|
||||
do { \
|
||||
mod_timer(&device_timer, jiffies + TIMEOUT_VALUE); \
|
||||
} while (0)
|
||||
|
||||
static void (*do_hd)(void) = NULL;
|
||||
#define SET_HANDLER(x) \
|
||||
if ((do_hd = (x)) != NULL) \
|
||||
SET_TIMER; \
|
||||
else \
|
||||
del_timer(&device_timer);
|
||||
|
||||
|
||||
#if (HD_DELAY > 0)
|
||||
|
||||
#include <linux/i8253.h>
|
||||
|
||||
unsigned long last_req;
|
||||
|
||||
unsigned long read_timer(void)
|
||||
{
|
||||
unsigned long t, flags;
|
||||
int i;
|
||||
|
||||
raw_spin_lock_irqsave(&i8253_lock, flags);
|
||||
t = jiffies * 11932;
|
||||
outb_p(0, 0x43);
|
||||
i = inb_p(0x40);
|
||||
i |= inb(0x40) << 8;
|
||||
raw_spin_unlock_irqrestore(&i8253_lock, flags);
|
||||
return(t - i);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __init hd_setup(char *str, int *ints)
|
||||
{
|
||||
int hdind = 0;
|
||||
|
||||
if (ints[0] != 3)
|
||||
return;
|
||||
if (hd_info[0].head != 0)
|
||||
hdind = 1;
|
||||
hd_info[hdind].head = ints[2];
|
||||
hd_info[hdind].sect = ints[3];
|
||||
hd_info[hdind].cyl = ints[1];
|
||||
hd_info[hdind].wpcom = 0;
|
||||
hd_info[hdind].lzone = ints[1];
|
||||
hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
|
||||
NR_HD = hdind+1;
|
||||
}
|
||||
|
||||
static bool hd_end_request(int err, unsigned int bytes)
|
||||
{
|
||||
if (__blk_end_request(hd_req, err, bytes))
|
||||
return true;
|
||||
hd_req = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hd_end_request_cur(int err)
|
||||
{
|
||||
return hd_end_request(err, blk_rq_cur_bytes(hd_req));
|
||||
}
|
||||
|
||||
static void dump_status(const char *msg, unsigned int stat)
|
||||
{
|
||||
char *name = "hd?";
|
||||
if (hd_req)
|
||||
name = hd_req->rq_disk->disk_name;
|
||||
|
||||
#ifdef VERBOSE_ERRORS
|
||||
printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
|
||||
if (stat & BUSY_STAT) printk("Busy ");
|
||||
if (stat & READY_STAT) printk("DriveReady ");
|
||||
if (stat & WRERR_STAT) printk("WriteFault ");
|
||||
if (stat & SEEK_STAT) printk("SeekComplete ");
|
||||
if (stat & DRQ_STAT) printk("DataRequest ");
|
||||
if (stat & ECC_STAT) printk("CorrectedError ");
|
||||
if (stat & INDEX_STAT) printk("Index ");
|
||||
if (stat & ERR_STAT) printk("Error ");
|
||||
printk("}\n");
|
||||
if ((stat & ERR_STAT) == 0) {
|
||||
hd_error = 0;
|
||||
} else {
|
||||
hd_error = inb(HD_ERROR);
|
||||
printk("%s: %s: error=0x%02x { ", name, msg, hd_error & 0xff);
|
||||
if (hd_error & BBD_ERR) printk("BadSector ");
|
||||
if (hd_error & ECC_ERR) printk("UncorrectableError ");
|
||||
if (hd_error & ID_ERR) printk("SectorIdNotFound ");
|
||||
if (hd_error & ABRT_ERR) printk("DriveStatusError ");
|
||||
if (hd_error & TRK0_ERR) printk("TrackZeroNotFound ");
|
||||
if (hd_error & MARK_ERR) printk("AddrMarkNotFound ");
|
||||
printk("}");
|
||||
if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
|
||||
printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
|
||||
inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
|
||||
if (hd_req)
|
||||
printk(", sector=%ld", blk_rq_pos(hd_req));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
#else
|
||||
printk("%s: %s: status=0x%02x.\n", name, msg, stat & 0xff);
|
||||
if ((stat & ERR_STAT) == 0) {
|
||||
hd_error = 0;
|
||||
} else {
|
||||
hd_error = inb(HD_ERROR);
|
||||
printk("%s: %s: error=0x%02x.\n", name, msg, hd_error & 0xff);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void check_status(void)
|
||||
{
|
||||
int i = inb_p(HD_STATUS);
|
||||
|
||||
if (!OK_STATUS(i)) {
|
||||
dump_status("check_status", i);
|
||||
bad_rw_intr();
|
||||
}
|
||||
}
|
||||
|
||||
static int controller_busy(void)
|
||||
{
|
||||
int retries = 100000;
|
||||
unsigned char status;
|
||||
|
||||
do {
|
||||
status = inb_p(HD_STATUS);
|
||||
} while ((status & BUSY_STAT) && --retries);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int status_ok(void)
|
||||
{
|
||||
unsigned char status = inb_p(HD_STATUS);
|
||||
|
||||
if (status & BUSY_STAT)
|
||||
return 1; /* Ancient, but does it make sense??? */
|
||||
if (status & WRERR_STAT)
|
||||
return 0;
|
||||
if (!(status & READY_STAT))
|
||||
return 0;
|
||||
if (!(status & SEEK_STAT))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int controller_ready(unsigned int drive, unsigned int head)
|
||||
{
|
||||
int retry = 100;
|
||||
|
||||
do {
|
||||
if (controller_busy() & BUSY_STAT)
|
||||
return 0;
|
||||
outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
|
||||
if (status_ok())
|
||||
return 1;
|
||||
} while (--retry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hd_out(struct hd_i_struct *disk,
|
||||
unsigned int nsect,
|
||||
unsigned int sect,
|
||||
unsigned int head,
|
||||
unsigned int cyl,
|
||||
unsigned int cmd,
|
||||
void (*intr_addr)(void))
|
||||
{
|
||||
unsigned short port;
|
||||
|
||||
#if (HD_DELAY > 0)
|
||||
while (read_timer() - last_req < HD_DELAY)
|
||||
/* nothing */;
|
||||
#endif
|
||||
if (reset)
|
||||
return;
|
||||
if (!controller_ready(disk->unit, head)) {
|
||||
reset = 1;
|
||||
return;
|
||||
}
|
||||
SET_HANDLER(intr_addr);
|
||||
outb_p(disk->ctl, HD_CMD);
|
||||
port = HD_DATA;
|
||||
outb_p(disk->wpcom >> 2, ++port);
|
||||
outb_p(nsect, ++port);
|
||||
outb_p(sect, ++port);
|
||||
outb_p(cyl, ++port);
|
||||
outb_p(cyl >> 8, ++port);
|
||||
outb_p(0xA0 | (disk->unit << 4) | head, ++port);
|
||||
outb_p(cmd, ++port);
|
||||
}
|
||||
|
||||
static void hd_request (void);
|
||||
|
||||
static int drive_busy(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned char c;
|
||||
|
||||
for (i = 0; i < 500000 ; i++) {
|
||||
c = inb_p(HD_STATUS);
|
||||
if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
|
||||
return 0;
|
||||
}
|
||||
dump_status("reset timed out", c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void reset_controller(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
outb_p(4, HD_CMD);
|
||||
for (i = 0; i < 1000; i++) barrier();
|
||||
outb_p(hd_info[0].ctl & 0x0f, HD_CMD);
|
||||
for (i = 0; i < 1000; i++) barrier();
|
||||
if (drive_busy())
|
||||
printk("hd: controller still busy\n");
|
||||
else if ((hd_error = inb(HD_ERROR)) != 1)
|
||||
printk("hd: controller reset failed: %02x\n", hd_error);
|
||||
}
|
||||
|
||||
static void reset_hd(void)
|
||||
{
|
||||
static int i;
|
||||
|
||||
repeat:
|
||||
if (reset) {
|
||||
reset = 0;
|
||||
i = -1;
|
||||
reset_controller();
|
||||
} else {
|
||||
check_status();
|
||||
if (reset)
|
||||
goto repeat;
|
||||
}
|
||||
if (++i < NR_HD) {
|
||||
struct hd_i_struct *disk = &hd_info[i];
|
||||
disk->special_op = disk->recalibrate = 1;
|
||||
hd_out(disk, disk->sect, disk->sect, disk->head-1,
|
||||
disk->cyl, ATA_CMD_INIT_DEV_PARAMS, &reset_hd);
|
||||
if (reset)
|
||||
goto repeat;
|
||||
} else
|
||||
hd_request();
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, don't know what to do with the unexpected interrupts: on some machines
|
||||
* doing a reset and a retry seems to result in an eternal loop. Right now I
|
||||
* ignore it, and just set the timeout.
|
||||
*
|
||||
* On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
|
||||
* drive enters "idle", "standby", or "sleep" mode, so if the status looks
|
||||
* "good", we just ignore the interrupt completely.
|
||||
*/
|
||||
static void unexpected_hd_interrupt(void)
|
||||
{
|
||||
unsigned int stat = inb_p(HD_STATUS);
|
||||
|
||||
if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
|
||||
dump_status("unexpected interrupt", stat);
|
||||
SET_TIMER;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* bad_rw_intr() now tries to be a bit smarter and does things
|
||||
* according to the error returned by the controller.
|
||||
* -Mika Liljeberg (liljeber@cs.Helsinki.FI)
|
||||
*/
|
||||
static void bad_rw_intr(void)
|
||||
{
|
||||
struct request *req = hd_req;
|
||||
|
||||
if (req != NULL) {
|
||||
struct hd_i_struct *disk = req->rq_disk->private_data;
|
||||
if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
|
||||
hd_end_request_cur(-EIO);
|
||||
disk->special_op = disk->recalibrate = 1;
|
||||
} else if (req->errors % RESET_FREQ == 0)
|
||||
reset = 1;
|
||||
else if ((hd_error & TRK0_ERR) || req->errors % RECAL_FREQ == 0)
|
||||
disk->special_op = disk->recalibrate = 1;
|
||||
/* Otherwise just retry */
|
||||
}
|
||||
}
|
||||
|
||||
static inline int wait_DRQ(void)
|
||||
{
|
||||
int retries;
|
||||
int stat;
|
||||
|
||||
for (retries = 0; retries < 100000; retries++) {
|
||||
stat = inb_p(HD_STATUS);
|
||||
if (stat & DRQ_STAT)
|
||||
return 0;
|
||||
}
|
||||
dump_status("wait_DRQ", stat);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void read_intr(void)
|
||||
{
|
||||
struct request *req;
|
||||
int i, retries = 100000;
|
||||
|
||||
do {
|
||||
i = (unsigned) inb_p(HD_STATUS);
|
||||
if (i & BUSY_STAT)
|
||||
continue;
|
||||
if (!OK_STATUS(i))
|
||||
break;
|
||||
if (i & DRQ_STAT)
|
||||
goto ok_to_read;
|
||||
} while (--retries > 0);
|
||||
dump_status("read_intr", i);
|
||||
bad_rw_intr();
|
||||
hd_request();
|
||||
return;
|
||||
|
||||
ok_to_read:
|
||||
req = hd_req;
|
||||
insw(HD_DATA, bio_data(req->bio), 256);
|
||||
#ifdef DEBUG
|
||||
printk("%s: read: sector %ld, remaining = %u, buffer=%p\n",
|
||||
req->rq_disk->disk_name, blk_rq_pos(req) + 1,
|
||||
blk_rq_sectors(req) - 1, bio_data(req->bio)+512);
|
||||
#endif
|
||||
if (hd_end_request(0, 512)) {
|
||||
SET_HANDLER(&read_intr);
|
||||
return;
|
||||
}
|
||||
|
||||
(void) inb_p(HD_STATUS);
|
||||
#if (HD_DELAY > 0)
|
||||
last_req = read_timer();
|
||||
#endif
|
||||
hd_request();
|
||||
}
|
||||
|
||||
static void write_intr(void)
|
||||
{
|
||||
struct request *req = hd_req;
|
||||
int i;
|
||||
int retries = 100000;
|
||||
|
||||
do {
|
||||
i = (unsigned) inb_p(HD_STATUS);
|
||||
if (i & BUSY_STAT)
|
||||
continue;
|
||||
if (!OK_STATUS(i))
|
||||
break;
|
||||
if ((blk_rq_sectors(req) <= 1) || (i & DRQ_STAT))
|
||||
goto ok_to_write;
|
||||
} while (--retries > 0);
|
||||
dump_status("write_intr", i);
|
||||
bad_rw_intr();
|
||||
hd_request();
|
||||
return;
|
||||
|
||||
ok_to_write:
|
||||
if (hd_end_request(0, 512)) {
|
||||
SET_HANDLER(&write_intr);
|
||||
outsw(HD_DATA, bio_data(req->bio), 256);
|
||||
return;
|
||||
}
|
||||
|
||||
#if (HD_DELAY > 0)
|
||||
last_req = read_timer();
|
||||
#endif
|
||||
hd_request();
|
||||
}
|
||||
|
||||
static void recal_intr(void)
|
||||
{
|
||||
check_status();
|
||||
#if (HD_DELAY > 0)
|
||||
last_req = read_timer();
|
||||
#endif
|
||||
hd_request();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is another of the error-routines I don't know what to do with. The
|
||||
* best idea seems to just set reset, and start all over again.
|
||||
*/
|
||||
static void hd_times_out(unsigned long dummy)
|
||||
{
|
||||
char *name;
|
||||
|
||||
do_hd = NULL;
|
||||
|
||||
if (!hd_req)
|
||||
return;
|
||||
|
||||
spin_lock_irq(hd_queue->queue_lock);
|
||||
reset = 1;
|
||||
name = hd_req->rq_disk->disk_name;
|
||||
printk("%s: timeout\n", name);
|
||||
if (++hd_req->errors >= MAX_ERRORS) {
|
||||
#ifdef DEBUG
|
||||
printk("%s: too many errors\n", name);
|
||||
#endif
|
||||
hd_end_request_cur(-EIO);
|
||||
}
|
||||
hd_request();
|
||||
spin_unlock_irq(hd_queue->queue_lock);
|
||||
}
|
||||
|
||||
static int do_special_op(struct hd_i_struct *disk, struct request *req)
|
||||
{
|
||||
if (disk->recalibrate) {
|
||||
disk->recalibrate = 0;
|
||||
hd_out(disk, disk->sect, 0, 0, 0, ATA_CMD_RESTORE, &recal_intr);
|
||||
return reset;
|
||||
}
|
||||
if (disk->head > 16) {
|
||||
printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name);
|
||||
hd_end_request_cur(-EIO);
|
||||
}
|
||||
disk->special_op = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The driver enables interrupts as much as possible. In order to do this,
|
||||
* (a) the device-interrupt is disabled before entering hd_request(),
|
||||
* and (b) the timeout-interrupt is disabled before the sti().
|
||||
*
|
||||
* Interrupts are still masked (by default) whenever we are exchanging
|
||||
* data/cmds with a drive, because some drives seem to have very poor
|
||||
* tolerance for latency during I/O. The IDE driver has support to unmask
|
||||
* interrupts for non-broken hardware, so use that driver if required.
|
||||
*/
|
||||
static void hd_request(void)
|
||||
{
|
||||
unsigned int block, nsect, sec, track, head, cyl;
|
||||
struct hd_i_struct *disk;
|
||||
struct request *req;
|
||||
|
||||
if (do_hd)
|
||||
return;
|
||||
repeat:
|
||||
del_timer(&device_timer);
|
||||
|
||||
if (!hd_req) {
|
||||
hd_req = blk_fetch_request(hd_queue);
|
||||
if (!hd_req) {
|
||||
do_hd = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
req = hd_req;
|
||||
|
||||
if (reset) {
|
||||
reset_hd();
|
||||
return;
|
||||
}
|
||||
disk = req->rq_disk->private_data;
|
||||
block = blk_rq_pos(req);
|
||||
nsect = blk_rq_sectors(req);
|
||||
if (block >= get_capacity(req->rq_disk) ||
|
||||
((block+nsect) > get_capacity(req->rq_disk))) {
|
||||
printk("%s: bad access: block=%d, count=%d\n",
|
||||
req->rq_disk->disk_name, block, nsect);
|
||||
hd_end_request_cur(-EIO);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
if (disk->special_op) {
|
||||
if (do_special_op(disk, req))
|
||||
goto repeat;
|
||||
return;
|
||||
}
|
||||
sec = block % disk->sect + 1;
|
||||
track = block / disk->sect;
|
||||
head = track % disk->head;
|
||||
cyl = track / disk->head;
|
||||
#ifdef DEBUG
|
||||
printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n",
|
||||
req->rq_disk->disk_name,
|
||||
req_data_dir(req) == READ ? "read" : "writ",
|
||||
cyl, head, sec, nsect, bio_data(req->bio));
|
||||
#endif
|
||||
|
||||
switch (req_op(req)) {
|
||||
case REQ_OP_READ:
|
||||
hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ,
|
||||
&read_intr);
|
||||
if (reset)
|
||||
goto repeat;
|
||||
break;
|
||||
case REQ_OP_WRITE:
|
||||
hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE,
|
||||
&write_intr);
|
||||
if (reset)
|
||||
goto repeat;
|
||||
if (wait_DRQ()) {
|
||||
bad_rw_intr();
|
||||
goto repeat;
|
||||
}
|
||||
outsw(HD_DATA, bio_data(req->bio), 256);
|
||||
break;
|
||||
default:
|
||||
printk("unknown hd-command\n");
|
||||
hd_end_request_cur(-EIO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_hd_request(struct request_queue *q)
|
||||
{
|
||||
hd_request();
|
||||
}
|
||||
|
||||
static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
||||
{
|
||||
struct hd_i_struct *disk = bdev->bd_disk->private_data;
|
||||
|
||||
geo->heads = disk->head;
|
||||
geo->sectors = disk->sect;
|
||||
geo->cylinders = disk->cyl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Releasing a block device means we sync() it, so that it can safely
|
||||
* be forgotten about...
|
||||
*/
|
||||
|
||||
static irqreturn_t hd_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
void (*handler)(void) = do_hd;
|
||||
|
||||
spin_lock(hd_queue->queue_lock);
|
||||
|
||||
do_hd = NULL;
|
||||
del_timer(&device_timer);
|
||||
if (!handler)
|
||||
handler = unexpected_hd_interrupt;
|
||||
handler();
|
||||
|
||||
spin_unlock(hd_queue->queue_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct block_device_operations hd_fops = {
|
||||
.getgeo = hd_getgeo,
|
||||
};
|
||||
|
||||
static int __init hd_init(void)
|
||||
{
|
||||
int drive;
|
||||
|
||||
if (register_blkdev(HD_MAJOR, "hd"))
|
||||
return -1;
|
||||
|
||||
hd_queue = blk_init_queue(do_hd_request, &hd_lock);
|
||||
if (!hd_queue) {
|
||||
unregister_blkdev(HD_MAJOR, "hd");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
blk_queue_max_hw_sectors(hd_queue, 255);
|
||||
init_timer(&device_timer);
|
||||
device_timer.function = hd_times_out;
|
||||
blk_queue_logical_block_size(hd_queue, 512);
|
||||
|
||||
if (!NR_HD) {
|
||||
/*
|
||||
* We don't know anything about the drive. This means
|
||||
* that you *MUST* specify the drive parameters to the
|
||||
* kernel yourself.
|
||||
*
|
||||
* If we were on an i386, we used to read this info from
|
||||
* the BIOS or CMOS. This doesn't work all that well,
|
||||
* since this assumes that this is a primary or secondary
|
||||
* drive, and if we're using this legacy driver, it's
|
||||
* probably an auxiliary controller added to recover
|
||||
* legacy data off an ST-506 drive. Either way, it's
|
||||
* definitely safest to have the user explicitly specify
|
||||
* the information.
|
||||
*/
|
||||
printk("hd: no drives specified - use hd=cyl,head,sectors"
|
||||
" on kernel command line\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (drive = 0 ; drive < NR_HD ; drive++) {
|
||||
struct gendisk *disk = alloc_disk(64);
|
||||
struct hd_i_struct *p = &hd_info[drive];
|
||||
if (!disk)
|
||||
goto Enomem;
|
||||
disk->major = HD_MAJOR;
|
||||
disk->first_minor = drive << 6;
|
||||
disk->fops = &hd_fops;
|
||||
sprintf(disk->disk_name, "hd%c", 'a'+drive);
|
||||
disk->private_data = p;
|
||||
set_capacity(disk, p->head * p->sect * p->cyl);
|
||||
disk->queue = hd_queue;
|
||||
p->unit = drive;
|
||||
hd_gendisk[drive] = disk;
|
||||
printk("%s: %luMB, CHS=%d/%d/%d\n",
|
||||
disk->disk_name, (unsigned long)get_capacity(disk)/2048,
|
||||
p->cyl, p->head, p->sect);
|
||||
}
|
||||
|
||||
if (request_irq(HD_IRQ, hd_interrupt, 0, "hd", NULL)) {
|
||||
printk("hd: unable to get IRQ%d for the hard disk driver\n",
|
||||
HD_IRQ);
|
||||
goto out1;
|
||||
}
|
||||
if (!request_region(HD_DATA, 8, "hd")) {
|
||||
printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
|
||||
goto out2;
|
||||
}
|
||||
if (!request_region(HD_CMD, 1, "hd(cmd)")) {
|
||||
printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD);
|
||||
goto out3;
|
||||
}
|
||||
|
||||
/* Let them fly */
|
||||
for (drive = 0; drive < NR_HD; drive++)
|
||||
add_disk(hd_gendisk[drive]);
|
||||
|
||||
return 0;
|
||||
|
||||
out3:
|
||||
release_region(HD_DATA, 8);
|
||||
out2:
|
||||
free_irq(HD_IRQ, NULL);
|
||||
out1:
|
||||
for (drive = 0; drive < NR_HD; drive++)
|
||||
put_disk(hd_gendisk[drive]);
|
||||
NR_HD = 0;
|
||||
out:
|
||||
del_timer(&device_timer);
|
||||
unregister_blkdev(HD_MAJOR, "hd");
|
||||
blk_cleanup_queue(hd_queue);
|
||||
return -1;
|
||||
Enomem:
|
||||
while (drive--)
|
||||
put_disk(hd_gendisk[drive]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int __init parse_hd_setup(char *line)
|
||||
{
|
||||
int ints[6];
|
||||
|
||||
(void) get_options(line, ARRAY_SIZE(ints), ints);
|
||||
hd_setup(NULL, ints);
|
||||
|
||||
return 1;
|
||||
}
|
||||
__setup("hd=", parse_hd_setup);
|
||||
|
||||
late_initcall(hd_init);
|
||||
|
|
@ -445,32 +445,27 @@ static int lo_req_flush(struct loop_device *lo, struct request *rq)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline void handle_partial_read(struct loop_cmd *cmd, long bytes)
|
||||
static void lo_complete_rq(struct request *rq)
|
||||
{
|
||||
if (bytes < 0 || op_is_write(req_op(cmd->rq)))
|
||||
return;
|
||||
struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
|
||||
|
||||
if (unlikely(bytes < blk_rq_bytes(cmd->rq))) {
|
||||
if (unlikely(req_op(cmd->rq) == REQ_OP_READ && cmd->use_aio &&
|
||||
cmd->ret >= 0 && cmd->ret < blk_rq_bytes(cmd->rq))) {
|
||||
struct bio *bio = cmd->rq->bio;
|
||||
|
||||
bio_advance(bio, bytes);
|
||||
bio_advance(bio, cmd->ret);
|
||||
zero_fill_bio(bio);
|
||||
}
|
||||
|
||||
blk_mq_end_request(rq, cmd->ret < 0 ? -EIO : 0);
|
||||
}
|
||||
|
||||
static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2)
|
||||
{
|
||||
struct loop_cmd *cmd = container_of(iocb, struct loop_cmd, iocb);
|
||||
struct request *rq = cmd->rq;
|
||||
|
||||
handle_partial_read(cmd, ret);
|
||||
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
else if (ret < 0)
|
||||
ret = -EIO;
|
||||
|
||||
blk_mq_complete_request(rq, ret);
|
||||
cmd->ret = ret;
|
||||
blk_mq_complete_request(cmd->rq);
|
||||
}
|
||||
|
||||
static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
|
||||
|
|
@ -528,6 +523,7 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq)
|
|||
case REQ_OP_FLUSH:
|
||||
return lo_req_flush(lo, rq);
|
||||
case REQ_OP_DISCARD:
|
||||
case REQ_OP_WRITE_ZEROES:
|
||||
return lo_discard(lo, rq, pos);
|
||||
case REQ_OP_WRITE:
|
||||
if (lo->transfer)
|
||||
|
|
@ -826,7 +822,7 @@ static void loop_config_discard(struct loop_device *lo)
|
|||
q->limits.discard_granularity = 0;
|
||||
q->limits.discard_alignment = 0;
|
||||
blk_queue_max_discard_sectors(q, 0);
|
||||
q->limits.discard_zeroes_data = 0;
|
||||
blk_queue_max_write_zeroes_sectors(q, 0);
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
|
||||
return;
|
||||
}
|
||||
|
|
@ -834,7 +830,7 @@ static void loop_config_discard(struct loop_device *lo)
|
|||
q->limits.discard_granularity = inode->i_sb->s_blocksize;
|
||||
q->limits.discard_alignment = 0;
|
||||
blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
|
||||
q->limits.discard_zeroes_data = 1;
|
||||
blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
|
||||
}
|
||||
|
||||
|
|
@ -1660,6 +1656,7 @@ static int loop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
switch (req_op(cmd->rq)) {
|
||||
case REQ_OP_FLUSH:
|
||||
case REQ_OP_DISCARD:
|
||||
case REQ_OP_WRITE_ZEROES:
|
||||
cmd->use_aio = false;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1686,8 +1683,10 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
|
|||
ret = do_req_filebacked(lo, cmd->rq);
|
||||
failed:
|
||||
/* complete non-aio request */
|
||||
if (!cmd->use_aio || ret)
|
||||
blk_mq_complete_request(cmd->rq, ret ? -EIO : 0);
|
||||
if (!cmd->use_aio || ret) {
|
||||
cmd->ret = ret ? -EIO : 0;
|
||||
blk_mq_complete_request(cmd->rq);
|
||||
}
|
||||
}
|
||||
|
||||
static void loop_queue_work(struct kthread_work *work)
|
||||
|
|
@ -1710,9 +1709,10 @@ static int loop_init_request(void *data, struct request *rq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct blk_mq_ops loop_mq_ops = {
|
||||
static const struct blk_mq_ops loop_mq_ops = {
|
||||
.queue_rq = loop_queue_rq,
|
||||
.init_request = loop_init_request,
|
||||
.complete = lo_complete_rq,
|
||||
};
|
||||
|
||||
static int loop_add(struct loop_device **l, int i)
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ struct loop_cmd {
|
|||
struct request *rq;
|
||||
struct list_head list;
|
||||
bool use_aio; /* use AIO interface to handle I/O */
|
||||
long ret;
|
||||
struct kiocb iocb;
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -169,6 +169,25 @@ static bool mtip_check_surprise_removal(struct pci_dev *pdev)
|
|||
return false; /* device present */
|
||||
}
|
||||
|
||||
/* we have to use runtime tag to setup command header */
|
||||
static void mtip_init_cmd_header(struct request *rq)
|
||||
{
|
||||
struct driver_data *dd = rq->q->queuedata;
|
||||
struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
|
||||
u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64;
|
||||
|
||||
/* Point the command headers at the command tables. */
|
||||
cmd->command_header = dd->port->command_list +
|
||||
(sizeof(struct mtip_cmd_hdr) * rq->tag);
|
||||
cmd->command_header_dma = dd->port->command_list_dma +
|
||||
(sizeof(struct mtip_cmd_hdr) * rq->tag);
|
||||
|
||||
if (host_cap_64)
|
||||
cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16);
|
||||
|
||||
cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd)
|
||||
{
|
||||
struct request *rq;
|
||||
|
|
@ -180,6 +199,9 @@ static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd)
|
|||
if (IS_ERR(rq))
|
||||
return NULL;
|
||||
|
||||
/* Internal cmd isn't submitted via .queue_rq */
|
||||
mtip_init_cmd_header(rq);
|
||||
|
||||
return blk_mq_rq_to_pdu(rq);
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +263,8 @@ static void mtip_async_complete(struct mtip_port *port,
|
|||
|
||||
rq = mtip_rq_from_tag(dd, tag);
|
||||
|
||||
blk_mq_complete_request(rq, status);
|
||||
cmd->status = status;
|
||||
blk_mq_complete_request(rq);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2910,18 +2933,19 @@ static void mtip_softirq_done_fn(struct request *rq)
|
|||
if (unlikely(cmd->unaligned))
|
||||
up(&dd->port->cmd_slot_unal);
|
||||
|
||||
blk_mq_end_request(rq, rq->errors);
|
||||
blk_mq_end_request(rq, cmd->status);
|
||||
}
|
||||
|
||||
static void mtip_abort_cmd(struct request *req, void *data,
|
||||
bool reserved)
|
||||
{
|
||||
struct mtip_cmd *cmd = blk_mq_rq_to_pdu(req);
|
||||
struct driver_data *dd = data;
|
||||
|
||||
dbg_printk(MTIP_DRV_NAME " Aborting request, tag = %d\n", req->tag);
|
||||
|
||||
clear_bit(req->tag, dd->port->cmds_to_issue);
|
||||
req->errors = -EIO;
|
||||
cmd->status = -EIO;
|
||||
mtip_softirq_done_fn(req);
|
||||
}
|
||||
|
||||
|
|
@ -3807,6 +3831,8 @@ static int mtip_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
struct request *rq = bd->rq;
|
||||
int ret;
|
||||
|
||||
mtip_init_cmd_header(rq);
|
||||
|
||||
if (unlikely(mtip_check_unal_depth(hctx, rq)))
|
||||
return BLK_MQ_RQ_QUEUE_BUSY;
|
||||
|
||||
|
|
@ -3816,7 +3842,6 @@ static int mtip_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
if (likely(!ret))
|
||||
return BLK_MQ_RQ_QUEUE_OK;
|
||||
|
||||
rq->errors = ret;
|
||||
return BLK_MQ_RQ_QUEUE_ERROR;
|
||||
}
|
||||
|
||||
|
|
@ -3838,7 +3863,6 @@ static int mtip_init_cmd(void *data, struct request *rq, unsigned int hctx_idx,
|
|||
{
|
||||
struct driver_data *dd = data;
|
||||
struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
|
||||
u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64;
|
||||
|
||||
/*
|
||||
* For flush requests, request_idx starts at the end of the
|
||||
|
|
@ -3855,17 +3879,6 @@ static int mtip_init_cmd(void *data, struct request *rq, unsigned int hctx_idx,
|
|||
|
||||
memset(cmd->command, 0, CMD_DMA_ALLOC_SZ);
|
||||
|
||||
/* Point the command headers at the command tables. */
|
||||
cmd->command_header = dd->port->command_list +
|
||||
(sizeof(struct mtip_cmd_hdr) * request_idx);
|
||||
cmd->command_header_dma = dd->port->command_list_dma +
|
||||
(sizeof(struct mtip_cmd_hdr) * request_idx);
|
||||
|
||||
if (host_cap_64)
|
||||
cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16);
|
||||
|
||||
cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF);
|
||||
|
||||
sg_init_table(cmd->sg, MTIP_MAX_SG);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3889,7 +3902,7 @@ exit_handler:
|
|||
return BLK_EH_RESET_TIMER;
|
||||
}
|
||||
|
||||
static struct blk_mq_ops mtip_mq_ops = {
|
||||
static const struct blk_mq_ops mtip_mq_ops = {
|
||||
.queue_rq = mtip_queue_rq,
|
||||
.init_request = mtip_init_cmd,
|
||||
.exit_request = mtip_free_cmd,
|
||||
|
|
@ -4025,7 +4038,6 @@ skip_create_disk:
|
|||
dd->queue->limits.discard_granularity = 4096;
|
||||
blk_queue_max_discard_sectors(dd->queue,
|
||||
MTIP_MAX_TRIM_ENTRY_LEN * MTIP_MAX_TRIM_ENTRIES);
|
||||
dd->queue->limits.discard_zeroes_data = 0;
|
||||
}
|
||||
|
||||
/* Set the capacity of the device in 512 byte sectors. */
|
||||
|
|
@ -4107,9 +4119,11 @@ static void mtip_no_dev_cleanup(struct request *rq, void *data, bool reserv)
|
|||
struct driver_data *dd = (struct driver_data *)data;
|
||||
struct mtip_cmd *cmd;
|
||||
|
||||
if (likely(!reserv))
|
||||
blk_mq_complete_request(rq, -ENODEV);
|
||||
else if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &dd->port->flags)) {
|
||||
if (likely(!reserv)) {
|
||||
cmd = blk_mq_rq_to_pdu(rq);
|
||||
cmd->status = -ENODEV;
|
||||
blk_mq_complete_request(rq);
|
||||
} else if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &dd->port->flags)) {
|
||||
|
||||
cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL);
|
||||
if (cmd->comp_func)
|
||||
|
|
@ -4162,7 +4176,7 @@ static int mtip_block_remove(struct driver_data *dd)
|
|||
dev_info(&dd->pdev->dev, "device %s surprise removal\n",
|
||||
dd->disk->disk_name);
|
||||
|
||||
blk_mq_freeze_queue_start(dd->queue);
|
||||
blk_freeze_queue_start(dd->queue);
|
||||
blk_mq_stop_hw_queues(dd->queue);
|
||||
blk_mq_tagset_busy_iter(&dd->tags, mtip_no_dev_cleanup, dd);
|
||||
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ struct mtip_cmd {
|
|||
int retries; /* The number of retries left for this command. */
|
||||
|
||||
int direction; /* Data transfer direction */
|
||||
int status;
|
||||
};
|
||||
|
||||
/* Structure used to describe a port. */
|
||||
|
|
|
|||
1429
drivers/block/nbd.c
1429
drivers/block/nbd.c
File diff suppressed because it is too large
Load diff
|
|
@ -117,6 +117,10 @@ static bool use_lightnvm;
|
|||
module_param(use_lightnvm, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_lightnvm, "Register as a LightNVM device");
|
||||
|
||||
static bool blocking;
|
||||
module_param(blocking, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(blocking, "Register as a blocking blk-mq driver device");
|
||||
|
||||
static int irqmode = NULL_IRQ_SOFTIRQ;
|
||||
|
||||
static int null_set_irqmode(const char *str, const struct kernel_param *kp)
|
||||
|
|
@ -277,7 +281,7 @@ static inline void null_handle_cmd(struct nullb_cmd *cmd)
|
|||
case NULL_IRQ_SOFTIRQ:
|
||||
switch (queue_mode) {
|
||||
case NULL_Q_MQ:
|
||||
blk_mq_complete_request(cmd->rq, cmd->rq->errors);
|
||||
blk_mq_complete_request(cmd->rq);
|
||||
break;
|
||||
case NULL_Q_RQ:
|
||||
blk_complete_request(cmd->rq);
|
||||
|
|
@ -357,6 +361,8 @@ static int null_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
{
|
||||
struct nullb_cmd *cmd = blk_mq_rq_to_pdu(bd->rq);
|
||||
|
||||
might_sleep_if(hctx->flags & BLK_MQ_F_BLOCKING);
|
||||
|
||||
if (irqmode == NULL_IRQ_TIMER) {
|
||||
hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
cmd->timer.function = null_cmd_timer_expired;
|
||||
|
|
@ -392,7 +398,7 @@ static int null_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct blk_mq_ops null_mq_ops = {
|
||||
static const struct blk_mq_ops null_mq_ops = {
|
||||
.queue_rq = null_queue_rq,
|
||||
.init_hctx = null_init_hctx,
|
||||
.complete = null_softirq_done_fn,
|
||||
|
|
@ -437,14 +443,7 @@ static int null_lnvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
|
|||
if (IS_ERR(rq))
|
||||
return -ENOMEM;
|
||||
|
||||
rq->__sector = bio->bi_iter.bi_sector;
|
||||
rq->ioprio = bio_prio(bio);
|
||||
|
||||
if (bio_has_data(bio))
|
||||
rq->nr_phys_segments = bio_phys_segments(q, bio);
|
||||
|
||||
rq->__data_len = bio->bi_iter.bi_size;
|
||||
rq->bio = rq->biotail = bio;
|
||||
blk_init_request_from_bio(rq, bio);
|
||||
|
||||
rq->end_io_data = rqd;
|
||||
|
||||
|
|
@ -724,6 +723,9 @@ static int null_add_dev(void)
|
|||
nullb->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
|
||||
nullb->tag_set.driver_data = nullb;
|
||||
|
||||
if (blocking)
|
||||
nullb->tag_set.flags |= BLK_MQ_F_BLOCKING;
|
||||
|
||||
rv = blk_mq_alloc_tag_set(&nullb->tag_set);
|
||||
if (rv)
|
||||
goto out_cleanup_queues;
|
||||
|
|
|
|||
|
|
@ -1,693 +0,0 @@
|
|||
|
||||
/*
|
||||
osdblk.c -- Export a single SCSI OSD object as a Linux block device
|
||||
|
||||
|
||||
Copyright 2009 Red Hat, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
|
||||
Instructions for use
|
||||
--------------------
|
||||
|
||||
1) Map a Linux block device to an existing OSD object.
|
||||
|
||||
In this example, we will use partition id 1234, object id 5678,
|
||||
OSD device /dev/osd1.
|
||||
|
||||
$ echo "1234 5678 /dev/osd1" > /sys/class/osdblk/add
|
||||
|
||||
|
||||
2) List all active blkdev<->object mappings.
|
||||
|
||||
In this example, we have performed step #1 twice, creating two blkdevs,
|
||||
mapped to two separate OSD objects.
|
||||
|
||||
$ cat /sys/class/osdblk/list
|
||||
0 174 1234 5678 /dev/osd1
|
||||
1 179 1994 897123 /dev/osd0
|
||||
|
||||
The columns, in order, are:
|
||||
- blkdev unique id
|
||||
- blkdev assigned major
|
||||
- OSD object partition id
|
||||
- OSD object id
|
||||
- OSD device
|
||||
|
||||
|
||||
3) Remove an active blkdev<->object mapping.
|
||||
|
||||
In this example, we remove the mapping with blkdev unique id 1.
|
||||
|
||||
$ echo 1 > /sys/class/osdblk/remove
|
||||
|
||||
|
||||
NOTE: The actual creation and deletion of OSD objects is outside the scope
|
||||
of this driver.
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <scsi/osd_initiator.h>
|
||||
#include <scsi/osd_attributes.h>
|
||||
#include <scsi/osd_sec.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
|
||||
#define DRV_NAME "osdblk"
|
||||
#define PFX DRV_NAME ": "
|
||||
|
||||
/* #define _OSDBLK_DEBUG */
|
||||
#ifdef _OSDBLK_DEBUG
|
||||
#define OSDBLK_DEBUG(fmt, a...) \
|
||||
printk(KERN_NOTICE "osdblk @%s:%d: " fmt, __func__, __LINE__, ##a)
|
||||
#else
|
||||
#define OSDBLK_DEBUG(fmt, a...) \
|
||||
do { if (0) printk(fmt, ##a); } while (0)
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Jeff Garzik <[email protected]>");
|
||||
MODULE_DESCRIPTION("block device inside an OSD object osdblk.ko");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct osdblk_device;
|
||||
|
||||
enum {
|
||||
OSDBLK_MINORS_PER_MAJOR = 256, /* max minors per blkdev */
|
||||
OSDBLK_MAX_REQ = 32, /* max parallel requests */
|
||||
OSDBLK_OP_TIMEOUT = 4 * 60, /* sync OSD req timeout */
|
||||
};
|
||||
|
||||
struct osdblk_request {
|
||||
struct request *rq; /* blk layer request */
|
||||
struct bio *bio; /* cloned bio */
|
||||
struct osdblk_device *osdev; /* associated blkdev */
|
||||
};
|
||||
|
||||
struct osdblk_device {
|
||||
int id; /* blkdev unique id */
|
||||
|
||||
int major; /* blkdev assigned major */
|
||||
struct gendisk *disk; /* blkdev's gendisk and rq */
|
||||
struct request_queue *q;
|
||||
|
||||
struct osd_dev *osd; /* associated OSD */
|
||||
|
||||
char name[32]; /* blkdev name, e.g. osdblk34 */
|
||||
|
||||
spinlock_t lock; /* queue lock */
|
||||
|
||||
struct osd_obj_id obj; /* OSD partition, obj id */
|
||||
uint8_t obj_cred[OSD_CAP_LEN]; /* OSD cred */
|
||||
|
||||
struct osdblk_request req[OSDBLK_MAX_REQ]; /* request table */
|
||||
|
||||
struct list_head node;
|
||||
|
||||
char osd_path[0]; /* OSD device path */
|
||||
};
|
||||
|
||||
static struct class *class_osdblk; /* /sys/class/osdblk */
|
||||
static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */
|
||||
static LIST_HEAD(osdblkdev_list);
|
||||
|
||||
static const struct block_device_operations osdblk_bd_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct osd_attr g_attr_logical_length = ATTR_DEF(
|
||||
OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
|
||||
|
||||
static void osdblk_make_credential(u8 cred_a[OSD_CAP_LEN],
|
||||
const struct osd_obj_id *obj)
|
||||
{
|
||||
osd_sec_init_nosec_doall_caps(cred_a, obj, false, true);
|
||||
}
|
||||
|
||||
/* copied from exofs; move to libosd? */
|
||||
/*
|
||||
* Perform a synchronous OSD operation. copied from exofs; move to libosd?
|
||||
*/
|
||||
static int osd_sync_op(struct osd_request *or, int timeout, uint8_t *credential)
|
||||
{
|
||||
int ret;
|
||||
|
||||
or->timeout = timeout;
|
||||
ret = osd_finalize_request(or, 0, credential, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = osd_execute_request(or);
|
||||
|
||||
/* osd_req_decode_sense(or, ret); */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform an asynchronous OSD operation. copied from exofs; move to libosd?
|
||||
*/
|
||||
static int osd_async_op(struct osd_request *or, osd_req_done_fn *async_done,
|
||||
void *caller_context, u8 *cred)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = osd_finalize_request(or, 0, cred, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = osd_execute_request_async(or, async_done, caller_context);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* copied from exofs; move to libosd? */
|
||||
static int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr)
|
||||
{
|
||||
struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
|
||||
void *iter = NULL;
|
||||
int nelem;
|
||||
|
||||
do {
|
||||
nelem = 1;
|
||||
osd_req_decode_get_attr_list(or, &cur_attr, &nelem, &iter);
|
||||
if ((cur_attr.attr_page == attr->attr_page) &&
|
||||
(cur_attr.attr_id == attr->attr_id)) {
|
||||
attr->len = cur_attr.len;
|
||||
attr->val_ptr = cur_attr.val_ptr;
|
||||
return 0;
|
||||
}
|
||||
} while (iter);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int osdblk_get_obj_size(struct osdblk_device *osdev, u64 *size_out)
|
||||
{
|
||||
struct osd_request *or;
|
||||
struct osd_attr attr;
|
||||
int ret;
|
||||
|
||||
/* start request */
|
||||
or = osd_start_request(osdev->osd, GFP_KERNEL);
|
||||
if (!or)
|
||||
return -ENOMEM;
|
||||
|
||||
/* create a get-attributes(length) request */
|
||||
osd_req_get_attributes(or, &osdev->obj);
|
||||
|
||||
osd_req_add_get_attr_list(or, &g_attr_logical_length, 1);
|
||||
|
||||
/* execute op synchronously */
|
||||
ret = osd_sync_op(or, OSDBLK_OP_TIMEOUT, osdev->obj_cred);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* extract length from returned attribute info */
|
||||
attr = g_attr_logical_length;
|
||||
ret = extract_attr_from_req(or, &attr);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
*size_out = get_unaligned_be64(attr.val_ptr);
|
||||
|
||||
out:
|
||||
osd_end_request(or);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void osdblk_osd_complete(struct osd_request *or, void *private)
|
||||
{
|
||||
struct osdblk_request *orq = private;
|
||||
struct osd_sense_info osi;
|
||||
int ret = osd_req_decode_sense(or, &osi);
|
||||
|
||||
if (ret) {
|
||||
ret = -EIO;
|
||||
OSDBLK_DEBUG("osdblk_osd_complete with err=%d\n", ret);
|
||||
}
|
||||
|
||||
/* complete OSD request */
|
||||
osd_end_request(or);
|
||||
|
||||
/* complete request passed to osdblk by block layer */
|
||||
__blk_end_request_all(orq->rq, ret);
|
||||
}
|
||||
|
||||
static void bio_chain_put(struct bio *chain)
|
||||
{
|
||||
struct bio *tmp;
|
||||
|
||||
while (chain) {
|
||||
tmp = chain;
|
||||
chain = chain->bi_next;
|
||||
|
||||
bio_put(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bio *bio_chain_clone(struct bio *old_chain, gfp_t gfpmask)
|
||||
{
|
||||
struct bio *tmp, *new_chain = NULL, *tail = NULL;
|
||||
|
||||
while (old_chain) {
|
||||
tmp = bio_clone_kmalloc(old_chain, gfpmask);
|
||||
if (!tmp)
|
||||
goto err_out;
|
||||
|
||||
tmp->bi_bdev = NULL;
|
||||
gfpmask &= ~__GFP_DIRECT_RECLAIM;
|
||||
tmp->bi_next = NULL;
|
||||
|
||||
if (!new_chain)
|
||||
new_chain = tail = tmp;
|
||||
else {
|
||||
tail->bi_next = tmp;
|
||||
tail = tmp;
|
||||
}
|
||||
|
||||
old_chain = old_chain->bi_next;
|
||||
}
|
||||
|
||||
return new_chain;
|
||||
|
||||
err_out:
|
||||
OSDBLK_DEBUG("bio_chain_clone with err\n");
|
||||
bio_chain_put(new_chain);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void osdblk_rq_fn(struct request_queue *q)
|
||||
{
|
||||
struct osdblk_device *osdev = q->queuedata;
|
||||
|
||||
while (1) {
|
||||
struct request *rq;
|
||||
struct osdblk_request *orq;
|
||||
struct osd_request *or;
|
||||
struct bio *bio;
|
||||
bool do_write, do_flush;
|
||||
|
||||
/* peek at request from block layer */
|
||||
rq = blk_fetch_request(q);
|
||||
if (!rq)
|
||||
break;
|
||||
|
||||
/* deduce our operation (read, write, flush) */
|
||||
/* I wish the block layer simplified cmd_type/cmd_flags/cmd[]
|
||||
* into a clearly defined set of RPC commands:
|
||||
* read, write, flush, scsi command, power mgmt req,
|
||||
* driver-specific, etc.
|
||||
*/
|
||||
|
||||
do_flush = (req_op(rq) == REQ_OP_FLUSH);
|
||||
do_write = (rq_data_dir(rq) == WRITE);
|
||||
|
||||
if (!do_flush) { /* osd_flush does not use a bio */
|
||||
/* a bio clone to be passed down to OSD request */
|
||||
bio = bio_chain_clone(rq->bio, GFP_ATOMIC);
|
||||
if (!bio)
|
||||
break;
|
||||
} else
|
||||
bio = NULL;
|
||||
|
||||
/* alloc internal OSD request, for OSD command execution */
|
||||
or = osd_start_request(osdev->osd, GFP_ATOMIC);
|
||||
if (!or) {
|
||||
bio_chain_put(bio);
|
||||
OSDBLK_DEBUG("osd_start_request with err\n");
|
||||
break;
|
||||
}
|
||||
|
||||
orq = &osdev->req[rq->tag];
|
||||
orq->rq = rq;
|
||||
orq->bio = bio;
|
||||
orq->osdev = osdev;
|
||||
|
||||
/* init OSD command: flush, write or read */
|
||||
if (do_flush)
|
||||
osd_req_flush_object(or, &osdev->obj,
|
||||
OSD_CDB_FLUSH_ALL, 0, 0);
|
||||
else if (do_write)
|
||||
osd_req_write(or, &osdev->obj, blk_rq_pos(rq) * 512ULL,
|
||||
bio, blk_rq_bytes(rq));
|
||||
else
|
||||
osd_req_read(or, &osdev->obj, blk_rq_pos(rq) * 512ULL,
|
||||
bio, blk_rq_bytes(rq));
|
||||
|
||||
OSDBLK_DEBUG("%s 0x%x bytes at 0x%llx\n",
|
||||
do_flush ? "flush" : do_write ?
|
||||
"write" : "read", blk_rq_bytes(rq),
|
||||
blk_rq_pos(rq) * 512ULL);
|
||||
|
||||
/* begin OSD command execution */
|
||||
if (osd_async_op(or, osdblk_osd_complete, orq,
|
||||
osdev->obj_cred)) {
|
||||
osd_end_request(or);
|
||||
blk_requeue_request(q, rq);
|
||||
bio_chain_put(bio);
|
||||
OSDBLK_DEBUG("osd_execute_request_async with err\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* remove the special 'flush' marker, now that the command
|
||||
* is executing
|
||||
*/
|
||||
rq->special = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void osdblk_free_disk(struct osdblk_device *osdev)
|
||||
{
|
||||
struct gendisk *disk = osdev->disk;
|
||||
|
||||
if (!disk)
|
||||
return;
|
||||
|
||||
if (disk->flags & GENHD_FL_UP)
|
||||
del_gendisk(disk);
|
||||
if (disk->queue)
|
||||
blk_cleanup_queue(disk->queue);
|
||||
put_disk(disk);
|
||||
}
|
||||
|
||||
static int osdblk_init_disk(struct osdblk_device *osdev)
|
||||
{
|
||||
struct gendisk *disk;
|
||||
struct request_queue *q;
|
||||
int rc;
|
||||
u64 obj_size = 0;
|
||||
|
||||
/* contact OSD, request size info about the object being mapped */
|
||||
rc = osdblk_get_obj_size(osdev, &obj_size);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* create gendisk info */
|
||||
disk = alloc_disk(OSDBLK_MINORS_PER_MAJOR);
|
||||
if (!disk)
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(disk->disk_name, DRV_NAME "%d", osdev->id);
|
||||
disk->major = osdev->major;
|
||||
disk->first_minor = 0;
|
||||
disk->fops = &osdblk_bd_ops;
|
||||
disk->private_data = osdev;
|
||||
|
||||
/* init rq */
|
||||
q = blk_init_queue(osdblk_rq_fn, &osdev->lock);
|
||||
if (!q) {
|
||||
put_disk(disk);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* switch queue to TCQ mode; allocate tag map */
|
||||
rc = blk_queue_init_tags(q, OSDBLK_MAX_REQ, NULL, BLK_TAG_ALLOC_FIFO);
|
||||
if (rc) {
|
||||
blk_cleanup_queue(q);
|
||||
put_disk(disk);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Set our limits to the lower device limits, because osdblk cannot
|
||||
* sleep when allocating a lower-request and therefore cannot be
|
||||
* bouncing.
|
||||
*/
|
||||
blk_queue_stack_limits(q, osd_request_queue(osdev->osd));
|
||||
|
||||
blk_queue_prep_rq(q, blk_queue_start_tag);
|
||||
blk_queue_write_cache(q, true, false);
|
||||
|
||||
disk->queue = q;
|
||||
|
||||
q->queuedata = osdev;
|
||||
|
||||
osdev->disk = disk;
|
||||
osdev->q = q;
|
||||
|
||||
/* finally, announce the disk to the world */
|
||||
set_capacity(disk, obj_size / 512ULL);
|
||||
add_disk(disk);
|
||||
|
||||
printk(KERN_INFO "%s: Added of size 0x%llx\n",
|
||||
disk->disk_name, (unsigned long long)obj_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* /sys/class/osdblk/
|
||||
* add map OSD object to blkdev
|
||||
* remove unmap OSD object
|
||||
* list show mappings
|
||||
*******************************************************************/
|
||||
|
||||
static void class_osdblk_release(struct class *cls)
|
||||
{
|
||||
kfree(cls);
|
||||
}
|
||||
|
||||
static ssize_t class_osdblk_list(struct class *c,
|
||||
struct class_attribute *attr,
|
||||
char *data)
|
||||
{
|
||||
int n = 0;
|
||||
struct list_head *tmp;
|
||||
|
||||
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
|
||||
|
||||
list_for_each(tmp, &osdblkdev_list) {
|
||||
struct osdblk_device *osdev;
|
||||
|
||||
osdev = list_entry(tmp, struct osdblk_device, node);
|
||||
|
||||
n += sprintf(data+n, "%d %d %llu %llu %s\n",
|
||||
osdev->id,
|
||||
osdev->major,
|
||||
osdev->obj.partition,
|
||||
osdev->obj.id,
|
||||
osdev->osd_path);
|
||||
}
|
||||
|
||||
mutex_unlock(&ctl_mutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
static ssize_t class_osdblk_add(struct class *c,
|
||||
struct class_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct osdblk_device *osdev;
|
||||
ssize_t rc;
|
||||
int irc, new_id = 0;
|
||||
struct list_head *tmp;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return -ENODEV;
|
||||
|
||||
/* new osdblk_device object */
|
||||
osdev = kzalloc(sizeof(*osdev) + strlen(buf) + 1, GFP_KERNEL);
|
||||
if (!osdev) {
|
||||
rc = -ENOMEM;
|
||||
goto err_out_mod;
|
||||
}
|
||||
|
||||
/* static osdblk_device initialization */
|
||||
spin_lock_init(&osdev->lock);
|
||||
INIT_LIST_HEAD(&osdev->node);
|
||||
|
||||
/* generate unique id: find highest unique id, add one */
|
||||
|
||||
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
|
||||
|
||||
list_for_each(tmp, &osdblkdev_list) {
|
||||
struct osdblk_device *osdev;
|
||||
|
||||
osdev = list_entry(tmp, struct osdblk_device, node);
|
||||
if (osdev->id > new_id)
|
||||
new_id = osdev->id + 1;
|
||||
}
|
||||
|
||||
osdev->id = new_id;
|
||||
|
||||
/* add to global list */
|
||||
list_add_tail(&osdev->node, &osdblkdev_list);
|
||||
|
||||
mutex_unlock(&ctl_mutex);
|
||||
|
||||
/* parse add command */
|
||||
if (sscanf(buf, "%llu %llu %s", &osdev->obj.partition, &osdev->obj.id,
|
||||
osdev->osd_path) != 3) {
|
||||
rc = -EINVAL;
|
||||
goto err_out_slot;
|
||||
}
|
||||
|
||||
/* initialize rest of new object */
|
||||
sprintf(osdev->name, DRV_NAME "%d", osdev->id);
|
||||
|
||||
/* contact requested OSD */
|
||||
osdev->osd = osduld_path_lookup(osdev->osd_path);
|
||||
if (IS_ERR(osdev->osd)) {
|
||||
rc = PTR_ERR(osdev->osd);
|
||||
goto err_out_slot;
|
||||
}
|
||||
|
||||
/* build OSD credential */
|
||||
osdblk_make_credential(osdev->obj_cred, &osdev->obj);
|
||||
|
||||
/* register our block device */
|
||||
irc = register_blkdev(0, osdev->name);
|
||||
if (irc < 0) {
|
||||
rc = irc;
|
||||
goto err_out_osd;
|
||||
}
|
||||
|
||||
osdev->major = irc;
|
||||
|
||||
/* set up and announce blkdev mapping */
|
||||
rc = osdblk_init_disk(osdev);
|
||||
if (rc)
|
||||
goto err_out_blkdev;
|
||||
|
||||
return count;
|
||||
|
||||
err_out_blkdev:
|
||||
unregister_blkdev(osdev->major, osdev->name);
|
||||
err_out_osd:
|
||||
osduld_put_device(osdev->osd);
|
||||
err_out_slot:
|
||||
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
|
||||
list_del_init(&osdev->node);
|
||||
mutex_unlock(&ctl_mutex);
|
||||
|
||||
kfree(osdev);
|
||||
err_out_mod:
|
||||
OSDBLK_DEBUG("Error adding device %s\n", buf);
|
||||
module_put(THIS_MODULE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t class_osdblk_remove(struct class *c,
|
||||
struct class_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct osdblk_device *osdev = NULL;
|
||||
int target_id, rc;
|
||||
unsigned long ul;
|
||||
struct list_head *tmp;
|
||||
|
||||
rc = kstrtoul(buf, 10, &ul);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* convert to int; abort if we lost anything in the conversion */
|
||||
target_id = (int) ul;
|
||||
if (target_id != ul)
|
||||
return -EINVAL;
|
||||
|
||||
/* remove object from list immediately */
|
||||
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
|
||||
|
||||
list_for_each(tmp, &osdblkdev_list) {
|
||||
osdev = list_entry(tmp, struct osdblk_device, node);
|
||||
if (osdev->id == target_id) {
|
||||
list_del_init(&osdev->node);
|
||||
break;
|
||||
}
|
||||
osdev = NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&ctl_mutex);
|
||||
|
||||
if (!osdev)
|
||||
return -ENOENT;
|
||||
|
||||
/* clean up and free blkdev and associated OSD connection */
|
||||
osdblk_free_disk(osdev);
|
||||
unregister_blkdev(osdev->major, osdev->name);
|
||||
osduld_put_device(osdev->osd);
|
||||
kfree(osdev);
|
||||
|
||||
/* release module ref */
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct class_attribute class_osdblk_attrs[] = {
|
||||
__ATTR(add, 0200, NULL, class_osdblk_add),
|
||||
__ATTR(remove, 0200, NULL, class_osdblk_remove),
|
||||
__ATTR(list, 0444, class_osdblk_list, NULL),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static int osdblk_sysfs_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* create control files in sysfs
|
||||
* /sys/class/osdblk/...
|
||||
*/
|
||||
class_osdblk = kzalloc(sizeof(*class_osdblk), GFP_KERNEL);
|
||||
if (!class_osdblk)
|
||||
return -ENOMEM;
|
||||
|
||||
class_osdblk->name = DRV_NAME;
|
||||
class_osdblk->owner = THIS_MODULE;
|
||||
class_osdblk->class_release = class_osdblk_release;
|
||||
class_osdblk->class_attrs = class_osdblk_attrs;
|
||||
|
||||
ret = class_register(class_osdblk);
|
||||
if (ret) {
|
||||
kfree(class_osdblk);
|
||||
class_osdblk = NULL;
|
||||
printk(PFX "failed to create class osdblk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void osdblk_sysfs_cleanup(void)
|
||||
{
|
||||
if (class_osdblk)
|
||||
class_destroy(class_osdblk);
|
||||
class_osdblk = NULL;
|
||||
}
|
||||
|
||||
static int __init osdblk_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = osdblk_sysfs_init();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit osdblk_exit(void)
|
||||
{
|
||||
osdblk_sysfs_cleanup();
|
||||
}
|
||||
|
||||
module_init(osdblk_init);
|
||||
module_exit(osdblk_exit);
|
||||
|
||||
|
|
@ -300,6 +300,11 @@ static void pcd_init_units(void)
|
|||
struct gendisk *disk = alloc_disk(1);
|
||||
if (!disk)
|
||||
continue;
|
||||
disk->queue = blk_init_queue(do_pcd_request, &pcd_lock);
|
||||
if (!disk->queue) {
|
||||
put_disk(disk);
|
||||
continue;
|
||||
}
|
||||
cd->disk = disk;
|
||||
cd->pi = &cd->pia;
|
||||
cd->present = 0;
|
||||
|
|
@ -735,18 +740,36 @@ static int pcd_detect(void)
|
|||
}
|
||||
|
||||
/* I/O request processing */
|
||||
static struct request_queue *pcd_queue;
|
||||
static int pcd_queue;
|
||||
|
||||
static void do_pcd_request(struct request_queue * q)
|
||||
static int set_next_request(void)
|
||||
{
|
||||
struct pcd_unit *cd;
|
||||
struct request_queue *q;
|
||||
int old_pos = pcd_queue;
|
||||
|
||||
do {
|
||||
cd = &pcd[pcd_queue];
|
||||
q = cd->present ? cd->disk->queue : NULL;
|
||||
if (++pcd_queue == PCD_UNITS)
|
||||
pcd_queue = 0;
|
||||
if (q) {
|
||||
pcd_req = blk_fetch_request(q);
|
||||
if (pcd_req)
|
||||
break;
|
||||
}
|
||||
} while (pcd_queue != old_pos);
|
||||
|
||||
return pcd_req != NULL;
|
||||
}
|
||||
|
||||
static void pcd_request(void)
|
||||
{
|
||||
if (pcd_busy)
|
||||
return;
|
||||
while (1) {
|
||||
if (!pcd_req) {
|
||||
pcd_req = blk_fetch_request(q);
|
||||
if (!pcd_req)
|
||||
return;
|
||||
}
|
||||
if (!pcd_req && !set_next_request())
|
||||
return;
|
||||
|
||||
if (rq_data_dir(pcd_req) == READ) {
|
||||
struct pcd_unit *cd = pcd_req->rq_disk->private_data;
|
||||
|
|
@ -766,6 +789,11 @@ static void do_pcd_request(struct request_queue * q)
|
|||
}
|
||||
}
|
||||
|
||||
static void do_pcd_request(struct request_queue *q)
|
||||
{
|
||||
pcd_request();
|
||||
}
|
||||
|
||||
static inline void next_request(int err)
|
||||
{
|
||||
unsigned long saved_flags;
|
||||
|
|
@ -774,7 +802,7 @@ static inline void next_request(int err)
|
|||
if (!__blk_end_request_cur(pcd_req, err))
|
||||
pcd_req = NULL;
|
||||
pcd_busy = 0;
|
||||
do_pcd_request(pcd_queue);
|
||||
pcd_request();
|
||||
spin_unlock_irqrestore(&pcd_lock, saved_flags);
|
||||
}
|
||||
|
||||
|
|
@ -849,7 +877,7 @@ static void do_pcd_read_drq(void)
|
|||
|
||||
do_pcd_read();
|
||||
spin_lock_irqsave(&pcd_lock, saved_flags);
|
||||
do_pcd_request(pcd_queue);
|
||||
pcd_request();
|
||||
spin_unlock_irqrestore(&pcd_lock, saved_flags);
|
||||
}
|
||||
|
||||
|
|
@ -957,19 +985,10 @@ static int __init pcd_init(void)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
pcd_queue = blk_init_queue(do_pcd_request, &pcd_lock);
|
||||
if (!pcd_queue) {
|
||||
unregister_blkdev(major, name);
|
||||
for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
|
||||
put_disk(cd->disk);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
|
||||
if (cd->present) {
|
||||
register_cdrom(&cd->info);
|
||||
cd->disk->private_data = cd;
|
||||
cd->disk->queue = pcd_queue;
|
||||
add_disk(cd->disk);
|
||||
}
|
||||
}
|
||||
|
|
@ -988,9 +1007,9 @@ static void __exit pcd_exit(void)
|
|||
pi_release(cd->pi);
|
||||
unregister_cdrom(&cd->info);
|
||||
}
|
||||
blk_cleanup_queue(cd->disk->queue);
|
||||
put_disk(cd->disk);
|
||||
}
|
||||
blk_cleanup_queue(pcd_queue);
|
||||
unregister_blkdev(major, name);
|
||||
pi_unregister_driver(par_drv);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -381,12 +381,33 @@ static enum action do_pd_write_start(void);
|
|||
static enum action do_pd_read_drq(void);
|
||||
static enum action do_pd_write_done(void);
|
||||
|
||||
static struct request_queue *pd_queue;
|
||||
static int pd_queue;
|
||||
static int pd_claimed;
|
||||
|
||||
static struct pd_unit *pd_current; /* current request's drive */
|
||||
static PIA *pi_current; /* current request's PIA */
|
||||
|
||||
static int set_next_request(void)
|
||||
{
|
||||
struct gendisk *disk;
|
||||
struct request_queue *q;
|
||||
int old_pos = pd_queue;
|
||||
|
||||
do {
|
||||
disk = pd[pd_queue].gd;
|
||||
q = disk ? disk->queue : NULL;
|
||||
if (++pd_queue == PD_UNITS)
|
||||
pd_queue = 0;
|
||||
if (q) {
|
||||
pd_req = blk_fetch_request(q);
|
||||
if (pd_req)
|
||||
break;
|
||||
}
|
||||
} while (pd_queue != old_pos);
|
||||
|
||||
return pd_req != NULL;
|
||||
}
|
||||
|
||||
static void run_fsm(void)
|
||||
{
|
||||
while (1) {
|
||||
|
|
@ -418,8 +439,7 @@ static void run_fsm(void)
|
|||
spin_lock_irqsave(&pd_lock, saved_flags);
|
||||
if (!__blk_end_request_cur(pd_req,
|
||||
res == Ok ? 0 : -EIO)) {
|
||||
pd_req = blk_fetch_request(pd_queue);
|
||||
if (!pd_req)
|
||||
if (!set_next_request())
|
||||
stop = 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&pd_lock, saved_flags);
|
||||
|
|
@ -719,18 +739,15 @@ static int pd_special_command(struct pd_unit *disk,
|
|||
enum action (*func)(struct pd_unit *disk))
|
||||
{
|
||||
struct request *rq;
|
||||
int err = 0;
|
||||
|
||||
rq = blk_get_request(disk->gd->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
rq->special = func;
|
||||
|
||||
err = blk_execute_rq(disk->gd->queue, disk->gd, rq, 0);
|
||||
|
||||
blk_execute_rq(disk->gd->queue, disk->gd, rq, 0);
|
||||
blk_put_request(rq);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* kernel glue structures */
|
||||
|
|
@ -839,7 +856,13 @@ static void pd_probe_drive(struct pd_unit *disk)
|
|||
p->first_minor = (disk - pd) << PD_BITS;
|
||||
disk->gd = p;
|
||||
p->private_data = disk;
|
||||
p->queue = pd_queue;
|
||||
p->queue = blk_init_queue(do_pd_request, &pd_lock);
|
||||
if (!p->queue) {
|
||||
disk->gd = NULL;
|
||||
put_disk(p);
|
||||
return;
|
||||
}
|
||||
blk_queue_max_hw_sectors(p->queue, cluster);
|
||||
|
||||
if (disk->drive == -1) {
|
||||
for (disk->drive = 0; disk->drive <= 1; disk->drive++)
|
||||
|
|
@ -919,26 +942,18 @@ static int __init pd_init(void)
|
|||
if (disable)
|
||||
goto out1;
|
||||
|
||||
pd_queue = blk_init_queue(do_pd_request, &pd_lock);
|
||||
if (!pd_queue)
|
||||
goto out1;
|
||||
|
||||
blk_queue_max_hw_sectors(pd_queue, cluster);
|
||||
|
||||
if (register_blkdev(major, name))
|
||||
goto out2;
|
||||
goto out1;
|
||||
|
||||
printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
|
||||
name, name, PD_VERSION, major, cluster, nice);
|
||||
if (!pd_detect())
|
||||
goto out3;
|
||||
goto out2;
|
||||
|
||||
return 0;
|
||||
|
||||
out3:
|
||||
unregister_blkdev(major, name);
|
||||
out2:
|
||||
blk_cleanup_queue(pd_queue);
|
||||
unregister_blkdev(major, name);
|
||||
out1:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -953,11 +968,11 @@ static void __exit pd_exit(void)
|
|||
if (p) {
|
||||
disk->gd = NULL;
|
||||
del_gendisk(p);
|
||||
blk_cleanup_queue(p->queue);
|
||||
put_disk(p);
|
||||
pi_release(disk->pi);
|
||||
}
|
||||
}
|
||||
blk_cleanup_queue(pd_queue);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -287,6 +287,12 @@ static void __init pf_init_units(void)
|
|||
struct gendisk *disk = alloc_disk(1);
|
||||
if (!disk)
|
||||
continue;
|
||||
disk->queue = blk_init_queue(do_pf_request, &pf_spin_lock);
|
||||
if (!disk->queue) {
|
||||
put_disk(disk);
|
||||
return;
|
||||
}
|
||||
blk_queue_max_segments(disk->queue, cluster);
|
||||
pf->disk = disk;
|
||||
pf->pi = &pf->pia;
|
||||
pf->media_status = PF_NM;
|
||||
|
|
@ -772,7 +778,28 @@ static int pf_ready(void)
|
|||
return (((status_reg(pf_current) & (STAT_BUSY | pf_mask)) == pf_mask));
|
||||
}
|
||||
|
||||
static struct request_queue *pf_queue;
|
||||
static int pf_queue;
|
||||
|
||||
static int set_next_request(void)
|
||||
{
|
||||
struct pf_unit *pf;
|
||||
struct request_queue *q;
|
||||
int old_pos = pf_queue;
|
||||
|
||||
do {
|
||||
pf = &units[pf_queue];
|
||||
q = pf->present ? pf->disk->queue : NULL;
|
||||
if (++pf_queue == PF_UNITS)
|
||||
pf_queue = 0;
|
||||
if (q) {
|
||||
pf_req = blk_fetch_request(q);
|
||||
if (pf_req)
|
||||
break;
|
||||
}
|
||||
} while (pf_queue != old_pos);
|
||||
|
||||
return pf_req != NULL;
|
||||
}
|
||||
|
||||
static void pf_end_request(int err)
|
||||
{
|
||||
|
|
@ -780,16 +807,13 @@ static void pf_end_request(int err)
|
|||
pf_req = NULL;
|
||||
}
|
||||
|
||||
static void do_pf_request(struct request_queue * q)
|
||||
static void pf_request(void)
|
||||
{
|
||||
if (pf_busy)
|
||||
return;
|
||||
repeat:
|
||||
if (!pf_req) {
|
||||
pf_req = blk_fetch_request(q);
|
||||
if (!pf_req)
|
||||
return;
|
||||
}
|
||||
if (!pf_req && !set_next_request())
|
||||
return;
|
||||
|
||||
pf_current = pf_req->rq_disk->private_data;
|
||||
pf_block = blk_rq_pos(pf_req);
|
||||
|
|
@ -817,6 +841,11 @@ repeat:
|
|||
}
|
||||
}
|
||||
|
||||
static void do_pf_request(struct request_queue *q)
|
||||
{
|
||||
pf_request();
|
||||
}
|
||||
|
||||
static int pf_next_buf(void)
|
||||
{
|
||||
unsigned long saved_flags;
|
||||
|
|
@ -846,7 +875,7 @@ static inline void next_request(int err)
|
|||
spin_lock_irqsave(&pf_spin_lock, saved_flags);
|
||||
pf_end_request(err);
|
||||
pf_busy = 0;
|
||||
do_pf_request(pf_queue);
|
||||
pf_request();
|
||||
spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
|
||||
}
|
||||
|
||||
|
|
@ -972,15 +1001,6 @@ static int __init pf_init(void)
|
|||
put_disk(pf->disk);
|
||||
return -EBUSY;
|
||||
}
|
||||
pf_queue = blk_init_queue(do_pf_request, &pf_spin_lock);
|
||||
if (!pf_queue) {
|
||||
unregister_blkdev(major, name);
|
||||
for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++)
|
||||
put_disk(pf->disk);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
blk_queue_max_segments(pf_queue, cluster);
|
||||
|
||||
for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) {
|
||||
struct gendisk *disk = pf->disk;
|
||||
|
|
@ -988,7 +1008,6 @@ static int __init pf_init(void)
|
|||
if (!pf->present)
|
||||
continue;
|
||||
disk->private_data = pf;
|
||||
disk->queue = pf_queue;
|
||||
add_disk(disk);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1003,10 +1022,10 @@ static void __exit pf_exit(void)
|
|||
if (!pf->present)
|
||||
continue;
|
||||
del_gendisk(pf->disk);
|
||||
blk_cleanup_queue(pf->disk->queue);
|
||||
put_disk(pf->disk);
|
||||
pi_release(pf->pi);
|
||||
}
|
||||
blk_cleanup_queue(pf_queue);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -724,7 +724,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
|
|||
rq->rq_flags |= RQF_QUIET;
|
||||
|
||||
blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
|
||||
if (rq->errors)
|
||||
if (scsi_req(rq)->result)
|
||||
ret = -EIO;
|
||||
out:
|
||||
blk_put_request(rq);
|
||||
|
|
|
|||
|
|
@ -4317,7 +4317,7 @@ static int rbd_init_request(void *data, struct request *rq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct blk_mq_ops rbd_mq_ops = {
|
||||
static const struct blk_mq_ops rbd_mq_ops = {
|
||||
.queue_rq = rbd_queue_rq,
|
||||
.init_request = rbd_init_request,
|
||||
};
|
||||
|
|
@ -4380,7 +4380,6 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
|
|||
q->limits.discard_granularity = segment_size;
|
||||
q->limits.discard_alignment = segment_size;
|
||||
blk_queue_max_discard_sectors(q, segment_size / SECTOR_SIZE);
|
||||
q->limits.discard_zeroes_data = 1;
|
||||
|
||||
if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
|
||||
q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
|
||||
|
|
|
|||
|
|
@ -300,7 +300,6 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card)
|
|||
RSXX_HW_BLK_SIZE >> 9);
|
||||
card->queue->limits.discard_granularity = RSXX_HW_BLK_SIZE;
|
||||
card->queue->limits.discard_alignment = RSXX_HW_BLK_SIZE;
|
||||
card->queue->limits.discard_zeroes_data = 1;
|
||||
}
|
||||
|
||||
card->queue->queuedata = card;
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ enum head {
|
|||
struct swim_priv {
|
||||
struct swim __iomem *base;
|
||||
spinlock_t lock;
|
||||
struct request_queue *queue;
|
||||
int fdc_queue;
|
||||
int floppy_count;
|
||||
struct floppy_state unit[FD_MAX_UNIT];
|
||||
};
|
||||
|
|
@ -525,12 +525,33 @@ static int floppy_read_sectors(struct floppy_state *fs,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void redo_fd_request(struct request_queue *q)
|
||||
static struct request *swim_next_request(struct swim_priv *swd)
|
||||
{
|
||||
struct request_queue *q;
|
||||
struct request *rq;
|
||||
int old_pos = swd->fdc_queue;
|
||||
|
||||
do {
|
||||
q = swd->unit[swd->fdc_queue].disk->queue;
|
||||
if (++swd->fdc_queue == swd->floppy_count)
|
||||
swd->fdc_queue = 0;
|
||||
if (q) {
|
||||
rq = blk_fetch_request(q);
|
||||
if (rq)
|
||||
return rq;
|
||||
}
|
||||
} while (swd->fdc_queue != old_pos);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void do_fd_request(struct request_queue *q)
|
||||
{
|
||||
struct swim_priv *swd = q->queuedata;
|
||||
struct request *req;
|
||||
struct floppy_state *fs;
|
||||
|
||||
req = blk_fetch_request(q);
|
||||
req = swim_next_request(swd);
|
||||
while (req) {
|
||||
int err = -EIO;
|
||||
|
||||
|
|
@ -554,15 +575,10 @@ static void redo_fd_request(struct request_queue *q)
|
|||
}
|
||||
done:
|
||||
if (!__blk_end_request_cur(req, err))
|
||||
req = blk_fetch_request(q);
|
||||
req = swim_next_request(swd);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_fd_request(struct request_queue *q)
|
||||
{
|
||||
redo_fd_request(q);
|
||||
}
|
||||
|
||||
static struct floppy_struct floppy_type[4] = {
|
||||
{ 0, 0, 0, 0, 0, 0x00, 0x00, 0x00, 0x00, NULL }, /* no testing */
|
||||
{ 720, 9, 1, 80, 0, 0x2A, 0x02, 0xDF, 0x50, NULL }, /* 360KB SS 3.5"*/
|
||||
|
|
@ -833,22 +849,25 @@ static int swim_floppy_init(struct swim_priv *swd)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
spin_lock_init(&swd->lock);
|
||||
|
||||
for (drive = 0; drive < swd->floppy_count; drive++) {
|
||||
swd->unit[drive].disk = alloc_disk(1);
|
||||
if (swd->unit[drive].disk == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto exit_put_disks;
|
||||
}
|
||||
swd->unit[drive].disk->queue = blk_init_queue(do_fd_request,
|
||||
&swd->lock);
|
||||
if (!swd->unit[drive].disk->queue) {
|
||||
err = -ENOMEM;
|
||||
put_disk(swd->unit[drive].disk);
|
||||
goto exit_put_disks;
|
||||
}
|
||||
swd->unit[drive].disk->queue->queuedata = swd;
|
||||
swd->unit[drive].swd = swd;
|
||||
}
|
||||
|
||||
spin_lock_init(&swd->lock);
|
||||
swd->queue = blk_init_queue(do_fd_request, &swd->lock);
|
||||
if (!swd->queue) {
|
||||
err = -ENOMEM;
|
||||
goto exit_put_disks;
|
||||
}
|
||||
|
||||
for (drive = 0; drive < swd->floppy_count; drive++) {
|
||||
swd->unit[drive].disk->flags = GENHD_FL_REMOVABLE;
|
||||
swd->unit[drive].disk->major = FLOPPY_MAJOR;
|
||||
|
|
@ -856,7 +875,6 @@ static int swim_floppy_init(struct swim_priv *swd)
|
|||
sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive);
|
||||
swd->unit[drive].disk->fops = &floppy_fops;
|
||||
swd->unit[drive].disk->private_data = &swd->unit[drive];
|
||||
swd->unit[drive].disk->queue = swd->queue;
|
||||
set_capacity(swd->unit[drive].disk, 2880);
|
||||
add_disk(swd->unit[drive].disk);
|
||||
}
|
||||
|
|
@ -943,13 +961,12 @@ static int swim_remove(struct platform_device *dev)
|
|||
|
||||
for (drive = 0; drive < swd->floppy_count; drive++) {
|
||||
del_gendisk(swd->unit[drive].disk);
|
||||
blk_cleanup_queue(swd->unit[drive].disk->queue);
|
||||
put_disk(swd->unit[drive].disk);
|
||||
}
|
||||
|
||||
unregister_blkdev(FLOPPY_MAJOR, "fd");
|
||||
|
||||
blk_cleanup_queue(swd->queue);
|
||||
|
||||
/* eject floppies */
|
||||
|
||||
for (drive = 0; drive < swd->floppy_count; drive++)
|
||||
|
|
|
|||
|
|
@ -343,8 +343,8 @@ static void start_request(struct floppy_state *fs)
|
|||
req->rq_disk->disk_name, req->cmd,
|
||||
(long)blk_rq_pos(req), blk_rq_sectors(req),
|
||||
bio_data(req->bio));
|
||||
swim3_dbg(" errors=%d current_nr_sectors=%u\n",
|
||||
req->errors, blk_rq_cur_sectors(req));
|
||||
swim3_dbg(" current_nr_sectors=%u\n",
|
||||
blk_rq_cur_sectors(req));
|
||||
#endif
|
||||
|
||||
if (blk_rq_pos(req) >= fs->total_secs) {
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ static int virtblk_add_req_scsi(struct virtqueue *vq, struct virtblk_req *vbr,
|
|||
return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static inline void virtblk_scsi_reques_done(struct request *req)
|
||||
static inline void virtblk_scsi_request_done(struct request *req)
|
||||
{
|
||||
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
|
||||
struct virtio_blk *vblk = req->q->queuedata;
|
||||
|
|
@ -119,7 +119,7 @@ static inline void virtblk_scsi_reques_done(struct request *req)
|
|||
|
||||
sreq->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual);
|
||||
sreq->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len);
|
||||
req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors);
|
||||
sreq->result = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors);
|
||||
}
|
||||
|
||||
static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
|
|
@ -144,7 +144,7 @@ static inline int virtblk_add_req_scsi(struct virtqueue *vq,
|
|||
{
|
||||
return -EIO;
|
||||
}
|
||||
static inline void virtblk_scsi_reques_done(struct request *req)
|
||||
static inline void virtblk_scsi_request_done(struct request *req)
|
||||
{
|
||||
}
|
||||
#define virtblk_ioctl NULL
|
||||
|
|
@ -175,19 +175,15 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr,
|
|||
static inline void virtblk_request_done(struct request *req)
|
||||
{
|
||||
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
|
||||
int error = virtblk_result(vbr);
|
||||
|
||||
switch (req_op(req)) {
|
||||
case REQ_OP_SCSI_IN:
|
||||
case REQ_OP_SCSI_OUT:
|
||||
virtblk_scsi_reques_done(req);
|
||||
break;
|
||||
case REQ_OP_DRV_IN:
|
||||
req->errors = (error != 0);
|
||||
virtblk_scsi_request_done(req);
|
||||
break;
|
||||
}
|
||||
|
||||
blk_mq_end_request(req, error);
|
||||
blk_mq_end_request(req, virtblk_result(vbr));
|
||||
}
|
||||
|
||||
static void virtblk_done(struct virtqueue *vq)
|
||||
|
|
@ -205,7 +201,7 @@ static void virtblk_done(struct virtqueue *vq)
|
|||
while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) {
|
||||
struct request *req = blk_mq_rq_from_pdu(vbr);
|
||||
|
||||
blk_mq_complete_request(req, req->errors);
|
||||
blk_mq_complete_request(req);
|
||||
req_done = true;
|
||||
}
|
||||
if (unlikely(virtqueue_is_broken(vq)))
|
||||
|
|
@ -310,7 +306,8 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
err = blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
|
||||
blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
|
||||
err = virtblk_result(blk_mq_rq_to_pdu(req));
|
||||
out:
|
||||
blk_put_request(req);
|
||||
return err;
|
||||
|
|
@ -597,7 +594,7 @@ static int virtblk_map_queues(struct blk_mq_tag_set *set)
|
|||
return blk_mq_virtio_map_queues(set, vblk->vdev, 0);
|
||||
}
|
||||
|
||||
static struct blk_mq_ops virtio_mq_ops = {
|
||||
static const struct blk_mq_ops virtio_mq_ops = {
|
||||
.queue_rq = virtio_queue_rq,
|
||||
.complete = virtblk_request_done,
|
||||
.init_request = virtblk_init_request,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,15 @@ struct split_bio {
|
|||
atomic_t pending;
|
||||
};
|
||||
|
||||
struct blkif_req {
|
||||
int error;
|
||||
};
|
||||
|
||||
static inline struct blkif_req *blkif_req(struct request *rq)
|
||||
{
|
||||
return blk_mq_rq_to_pdu(rq);
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(blkfront_mutex);
|
||||
static const struct block_device_operations xlvbd_block_fops;
|
||||
|
||||
|
|
@ -907,8 +916,14 @@ out_busy:
|
|||
return BLK_MQ_RQ_QUEUE_BUSY;
|
||||
}
|
||||
|
||||
static struct blk_mq_ops blkfront_mq_ops = {
|
||||
static void blkif_complete_rq(struct request *rq)
|
||||
{
|
||||
blk_mq_end_request(rq, blkif_req(rq)->error);
|
||||
}
|
||||
|
||||
static const struct blk_mq_ops blkfront_mq_ops = {
|
||||
.queue_rq = blkif_queue_rq,
|
||||
.complete = blkif_complete_rq,
|
||||
};
|
||||
|
||||
static void blkif_set_queue_limits(struct blkfront_info *info)
|
||||
|
|
@ -969,7 +984,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size,
|
|||
info->tag_set.queue_depth = BLK_RING_SIZE(info);
|
||||
info->tag_set.numa_node = NUMA_NO_NODE;
|
||||
info->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE;
|
||||
info->tag_set.cmd_size = 0;
|
||||
info->tag_set.cmd_size = sizeof(struct blkif_req);
|
||||
info->tag_set.driver_data = info;
|
||||
|
||||
if (blk_mq_alloc_tag_set(&info->tag_set))
|
||||
|
|
@ -1543,7 +1558,6 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
|||
unsigned long flags;
|
||||
struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id;
|
||||
struct blkfront_info *info = rinfo->dev_info;
|
||||
int error;
|
||||
|
||||
if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -1587,37 +1601,36 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
|||
continue;
|
||||
}
|
||||
|
||||
error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
|
||||
blkif_req(req)->error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
|
||||
switch (bret->operation) {
|
||||
case BLKIF_OP_DISCARD:
|
||||
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
|
||||
struct request_queue *rq = info->rq;
|
||||
printk(KERN_WARNING "blkfront: %s: %s op failed\n",
|
||||
info->gd->disk_name, op_name(bret->operation));
|
||||
error = -EOPNOTSUPP;
|
||||
blkif_req(req)->error = -EOPNOTSUPP;
|
||||
info->feature_discard = 0;
|
||||
info->feature_secdiscard = 0;
|
||||
queue_flag_clear(QUEUE_FLAG_DISCARD, rq);
|
||||
queue_flag_clear(QUEUE_FLAG_SECERASE, rq);
|
||||
}
|
||||
blk_mq_complete_request(req, error);
|
||||
break;
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
case BLKIF_OP_WRITE_BARRIER:
|
||||
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
|
||||
printk(KERN_WARNING "blkfront: %s: %s op failed\n",
|
||||
info->gd->disk_name, op_name(bret->operation));
|
||||
error = -EOPNOTSUPP;
|
||||
blkif_req(req)->error = -EOPNOTSUPP;
|
||||
}
|
||||
if (unlikely(bret->status == BLKIF_RSP_ERROR &&
|
||||
rinfo->shadow[id].req.u.rw.nr_segments == 0)) {
|
||||
printk(KERN_WARNING "blkfront: %s: empty %s op failed\n",
|
||||
info->gd->disk_name, op_name(bret->operation));
|
||||
error = -EOPNOTSUPP;
|
||||
blkif_req(req)->error = -EOPNOTSUPP;
|
||||
}
|
||||
if (unlikely(error)) {
|
||||
if (error == -EOPNOTSUPP)
|
||||
error = 0;
|
||||
if (unlikely(blkif_req(req)->error)) {
|
||||
if (blkif_req(req)->error == -EOPNOTSUPP)
|
||||
blkif_req(req)->error = 0;
|
||||
info->feature_fua = 0;
|
||||
info->feature_flush = 0;
|
||||
xlvbd_flush(info);
|
||||
|
|
@ -1629,11 +1642,12 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
|||
dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
|
||||
"request: %x\n", bret->status);
|
||||
|
||||
blk_mq_complete_request(req, error);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
blk_mq_complete_request(req);
|
||||
}
|
||||
|
||||
rinfo->ring.rsp_cons = i;
|
||||
|
|
@ -2345,6 +2359,7 @@ static void blkfront_connect(struct blkfront_info *info)
|
|||
unsigned long sector_size;
|
||||
unsigned int physical_sector_size;
|
||||
unsigned int binfo;
|
||||
char *envp[] = { "RESIZE=1", NULL };
|
||||
int err, i;
|
||||
|
||||
switch (info->connected) {
|
||||
|
|
@ -2361,6 +2376,8 @@ static void blkfront_connect(struct blkfront_info *info)
|
|||
sectors);
|
||||
set_capacity(info->gd, sectors);
|
||||
revalidate_disk(info->gd);
|
||||
kobject_uevent_env(&disk_to_dev(info->gd)->kobj,
|
||||
KOBJ_CHANGE, envp);
|
||||
|
||||
return;
|
||||
case BLKIF_STATE_SUSPENDED:
|
||||
|
|
|
|||
|
|
@ -829,10 +829,14 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
|
|||
offset = (bio->bi_iter.bi_sector &
|
||||
(SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT;
|
||||
|
||||
if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
|
||||
switch (bio_op(bio)) {
|
||||
case REQ_OP_DISCARD:
|
||||
case REQ_OP_WRITE_ZEROES:
|
||||
zram_bio_discard(zram, index, offset, bio);
|
||||
bio_endio(bio);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
|
|
@ -1192,6 +1196,8 @@ static int zram_add(void)
|
|||
zram->disk->queue->limits.max_sectors = SECTORS_PER_PAGE;
|
||||
zram->disk->queue->limits.chunk_sectors = 0;
|
||||
blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX);
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue);
|
||||
|
||||
/*
|
||||
* zram_bio_discard() will clear all logical blocks if logical block
|
||||
* size is identical with physical block size(PAGE_SIZE). But if it is
|
||||
|
|
@ -1201,10 +1207,7 @@ static int zram_add(void)
|
|||
* zeroed.
|
||||
*/
|
||||
if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE)
|
||||
zram->disk->queue->limits.discard_zeroes_data = 1;
|
||||
else
|
||||
zram->disk->queue->limits.discard_zeroes_data = 0;
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue);
|
||||
blk_queue_max_write_zeroes_sectors(zram->disk->queue, UINT_MAX);
|
||||
|
||||
add_disk(zram->disk);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue