diff options
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r-- | drivers/scsi/sg.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 661f9f21650a..487c7776cc4e 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
@@ -137,6 +137,7 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ | |||
137 | char orphan; /* 1 -> drop on sight, 0 -> normal */ | 137 | char orphan; /* 1 -> drop on sight, 0 -> normal */ |
138 | char sg_io_owned; /* 1 -> packet belongs to SG_IO */ | 138 | char sg_io_owned; /* 1 -> packet belongs to SG_IO */ |
139 | volatile char done; /* 0->before bh, 1->before read, 2->read */ | 139 | volatile char done; /* 0->before bh, 1->before read, 2->read */ |
140 | struct request *rq; | ||
140 | } Sg_request; | 141 | } Sg_request; |
141 | 142 | ||
142 | typedef struct sg_fd { /* holds the state of a file descriptor */ | 143 | typedef struct sg_fd { /* holds the state of a file descriptor */ |
@@ -176,7 +177,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ | |||
176 | static int sg_fasync(int fd, struct file *filp, int mode); | 177 | static int sg_fasync(int fd, struct file *filp, int mode); |
177 | /* tasklet or soft irq callback */ | 178 | /* tasklet or soft irq callback */ |
178 | static void sg_cmd_done(void *data, char *sense, int result, int resid); | 179 | static void sg_cmd_done(void *data, char *sense, int result, int resid); |
179 | static int sg_start_req(Sg_request * srp); | 180 | static int sg_start_req(Sg_request *srp, unsigned char *cmd); |
180 | static void sg_finish_rem_req(Sg_request * srp); | 181 | static void sg_finish_rem_req(Sg_request * srp); |
181 | static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); | 182 | static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); |
182 | static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, | 183 | static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, |
@@ -229,6 +230,11 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd) | |||
229 | cmd, filp->f_mode & FMODE_WRITE); | 230 | cmd, filp->f_mode & FMODE_WRITE); |
230 | } | 231 | } |
231 | 232 | ||
233 | static void sg_rq_end_io(struct request *rq, int uptodate) | ||
234 | { | ||
235 | sg_cmd_done(rq->end_io_data, rq->sense, rq->errors, rq->data_len); | ||
236 | } | ||
237 | |||
232 | static int | 238 | static int |
233 | sg_open(struct inode *inode, struct file *filp) | 239 | sg_open(struct inode *inode, struct file *filp) |
234 | { | 240 | { |
@@ -732,7 +738,8 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, | |||
732 | SCSI_LOG_TIMEOUT(4, printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", | 738 | SCSI_LOG_TIMEOUT(4, printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", |
733 | (int) cmnd[0], (int) hp->cmd_len)); | 739 | (int) cmnd[0], (int) hp->cmd_len)); |
734 | 740 | ||
735 | if ((k = sg_start_req(srp))) { | 741 | k = sg_start_req(srp, cmnd); |
742 | if (k) { | ||
736 | SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k)); | 743 | SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k)); |
737 | sg_finish_rem_req(srp); | 744 | sg_finish_rem_req(srp); |
738 | return k; /* probably out of space --> ENOMEM */ | 745 | return k; /* probably out of space --> ENOMEM */ |
@@ -765,6 +772,12 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, | |||
765 | hp->duration = jiffies_to_msecs(jiffies); | 772 | hp->duration = jiffies_to_msecs(jiffies); |
766 | /* Now send everything of to mid-level. The next time we hear about this | 773 | /* Now send everything of to mid-level. The next time we hear about this |
767 | packet is when sg_cmd_done() is called (i.e. a callback). */ | 774 | packet is when sg_cmd_done() is called (i.e. a callback). */ |
775 | if (srp->rq) { | ||
776 | srp->rq->timeout = timeout; | ||
777 | blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk, | ||
778 | srp->rq, 1, sg_rq_end_io); | ||
779 | return 0; | ||
780 | } | ||
768 | if (scsi_execute_async(sdp->device, cmnd, hp->cmd_len, data_dir, srp->data.buffer, | 781 | if (scsi_execute_async(sdp->device, cmnd, hp->cmd_len, data_dir, srp->data.buffer, |
769 | hp->dxfer_len, srp->data.k_use_sg, timeout, | 782 | hp->dxfer_len, srp->data.k_use_sg, timeout, |
770 | SG_DEFAULT_RETRIES, srp, sg_cmd_done, | 783 | SG_DEFAULT_RETRIES, srp, sg_cmd_done, |
@@ -1634,8 +1647,32 @@ exit_sg(void) | |||
1634 | idr_destroy(&sg_index_idr); | 1647 | idr_destroy(&sg_index_idr); |
1635 | } | 1648 | } |
1636 | 1649 | ||
1637 | static int | 1650 | static int __sg_start_req(struct sg_request *srp, struct sg_io_hdr *hp, |
1638 | sg_start_req(Sg_request * srp) | 1651 | unsigned char *cmd) |
1652 | { | ||
1653 | struct sg_fd *sfp = srp->parentfp; | ||
1654 | struct request_queue *q = sfp->parentdp->device->request_queue; | ||
1655 | struct request *rq; | ||
1656 | int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ; | ||
1657 | |||
1658 | rq = blk_get_request(q, rw, GFP_ATOMIC); | ||
1659 | if (!rq) | ||
1660 | return -ENOMEM; | ||
1661 | |||
1662 | memcpy(rq->cmd, cmd, hp->cmd_len); | ||
1663 | |||
1664 | rq->cmd_len = hp->cmd_len; | ||
1665 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
1666 | |||
1667 | srp->rq = rq; | ||
1668 | rq->end_io_data = srp; | ||
1669 | rq->sense = srp->sense_b; | ||
1670 | rq->retries = SG_DEFAULT_RETRIES; | ||
1671 | |||
1672 | return 0; | ||
1673 | } | ||
1674 | |||
1675 | static int sg_start_req(Sg_request *srp, unsigned char *cmd) | ||
1639 | { | 1676 | { |
1640 | int res; | 1677 | int res; |
1641 | Sg_fd *sfp = srp->parentfp; | 1678 | Sg_fd *sfp = srp->parentfp; |
@@ -1646,8 +1683,10 @@ sg_start_req(Sg_request * srp) | |||
1646 | Sg_scatter_hold *rsv_schp = &sfp->reserve; | 1683 | Sg_scatter_hold *rsv_schp = &sfp->reserve; |
1647 | 1684 | ||
1648 | SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len)); | 1685 | SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len)); |
1686 | |||
1649 | if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE)) | 1687 | if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE)) |
1650 | return 0; | 1688 | return __sg_start_req(srp, hp, cmd); |
1689 | |||
1651 | if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) && | 1690 | if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) && |
1652 | (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) && | 1691 | (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) && |
1653 | (!sfp->parentdp->device->host->unchecked_isa_dma)) { | 1692 | (!sfp->parentdp->device->host->unchecked_isa_dma)) { |
@@ -1678,6 +1717,10 @@ sg_finish_rem_req(Sg_request * srp) | |||
1678 | sg_unlink_reserve(sfp, srp); | 1717 | sg_unlink_reserve(sfp, srp); |
1679 | else | 1718 | else |
1680 | sg_remove_scat(req_schp); | 1719 | sg_remove_scat(req_schp); |
1720 | |||
1721 | if (srp->rq) | ||
1722 | blk_put_request(srp->rq); | ||
1723 | |||
1681 | sg_remove_request(sfp, srp); | 1724 | sg_remove_request(sfp, srp); |
1682 | } | 1725 | } |
1683 | 1726 | ||