Blame view

block/bsg-lib.c 7.46 KB
aa387cc89   Mike Christie   block: add bsg he...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  /*
   *  BSG helper library
   *
   *  Copyright (C) 2008   James Smart, Emulex Corporation
   *  Copyright (C) 2011   Red Hat, Inc.  All rights reserved.
   *  Copyright (C) 2011   Mike Christie
   *
   *  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; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  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; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   *
   */
  #include <linux/slab.h>
  #include <linux/blkdev.h>
  #include <linux/delay.h>
  #include <linux/scatterlist.h>
  #include <linux/bsg-lib.h>
6adb1236b   Paul Gortmaker   block: Change mod...
28
  #include <linux/export.h>
aa387cc89   Mike Christie   block: add bsg he...
29
30
31
  #include <scsi/scsi_cmnd.h>
  
  /**
50b4d4855   Benjamin Block   bsg-lib: fix kern...
32
   * bsg_teardown_job - routine to teardown a bsg job
aa387cc89   Mike Christie   block: add bsg he...
33
34
   * @job: bsg_job that is to be torn down
   */
50b4d4855   Benjamin Block   bsg-lib: fix kern...
35
  static void bsg_teardown_job(struct kref *kref)
aa387cc89   Mike Christie   block: add bsg he...
36
  {
bf0f2d380   Johannes Thumshirn   block: add refere...
37
  	struct bsg_job *job = container_of(kref, struct bsg_job, kref);
c00da4c90   Johannes Thumshirn   scsi: fc: Use bsg...
38
  	struct request *rq = job->req;
aa387cc89   Mike Christie   block: add bsg he...
39
40
41
42
  	put_device(job->dev);	/* release reference for the request */
  
  	kfree(job->request_payload.sg_list);
  	kfree(job->reply_payload.sg_list);
50b4d4855   Benjamin Block   bsg-lib: fix kern...
43
44
  
  	blk_end_request_all(rq, BLK_STS_OK);
aa387cc89   Mike Christie   block: add bsg he...
45
  }
fb6f7c8d8   Johannes Thumshirn   block: add bsg_jo...
46
47
  void bsg_job_put(struct bsg_job *job)
  {
50b4d4855   Benjamin Block   bsg-lib: fix kern...
48
  	kref_put(&job->kref, bsg_teardown_job);
fb6f7c8d8   Johannes Thumshirn   block: add bsg_jo...
49
50
51
52
53
54
55
56
  }
  EXPORT_SYMBOL_GPL(bsg_job_put);
  
  int bsg_job_get(struct bsg_job *job)
  {
  	return kref_get_unless_zero(&job->kref);
  }
  EXPORT_SYMBOL_GPL(bsg_job_get);
aa387cc89   Mike Christie   block: add bsg he...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  
  /**
   * bsg_job_done - completion routine for bsg requests
   * @job: bsg_job that is complete
   * @result: job reply result
   * @reply_payload_rcv_len: length of payload recvd
   *
   * The LLD should call this when the bsg job has completed.
   */
  void bsg_job_done(struct bsg_job *job, int result,
  		  unsigned int reply_payload_rcv_len)
  {
  	struct request *req = job->req;
  	struct request *rsp = req->next_rq;
82ed4db49   Christoph Hellwig   block: split scsi...
71
  	struct scsi_request *rq = scsi_req(req);
aa387cc89   Mike Christie   block: add bsg he...
72
  	int err;
17d5363b8   Christoph Hellwig   scsi: introduce a...
73
  	err = scsi_req(job->req)->result = result;
aa387cc89   Mike Christie   block: add bsg he...
74
75
  	if (err < 0)
  		/* we're only returning the result field in the reply */
82ed4db49   Christoph Hellwig   block: split scsi...
76
  		rq->sense_len = sizeof(u32);
aa387cc89   Mike Christie   block: add bsg he...
77
  	else
82ed4db49   Christoph Hellwig   block: split scsi...
78
  		rq->sense_len = job->reply_len;
aa387cc89   Mike Christie   block: add bsg he...
79
  	/* we assume all request payload was transferred, residual == 0 */
82ed4db49   Christoph Hellwig   block: split scsi...
80
  	rq->resid_len = 0;
aa387cc89   Mike Christie   block: add bsg he...
81
82
  
  	if (rsp) {
82ed4db49   Christoph Hellwig   block: split scsi...
83
  		WARN_ON(reply_payload_rcv_len > scsi_req(rsp)->resid_len);
aa387cc89   Mike Christie   block: add bsg he...
84
85
  
  		/* set reply (bidi) residual */
82ed4db49   Christoph Hellwig   block: split scsi...
86
87
  		scsi_req(rsp)->resid_len -=
  			min(reply_payload_rcv_len, scsi_req(rsp)->resid_len);
aa387cc89   Mike Christie   block: add bsg he...
88
89
90
91
92
93
94
95
96
97
98
  	}
  	blk_complete_request(req);
  }
  EXPORT_SYMBOL_GPL(bsg_job_done);
  
  /**
   * bsg_softirq_done - softirq done routine for destroying the bsg requests
   * @rq: BSG request that holds the job to be destroyed
   */
  static void bsg_softirq_done(struct request *rq)
  {
50b4d4855   Benjamin Block   bsg-lib: fix kern...
99
  	struct bsg_job *job = blk_mq_rq_to_pdu(rq);
aa387cc89   Mike Christie   block: add bsg he...
100

fb6f7c8d8   Johannes Thumshirn   block: add bsg_jo...
101
  	bsg_job_put(job);
aa387cc89   Mike Christie   block: add bsg he...
102
103
104
105
106
107
108
109
110
111
112
113
  }
  
  static int bsg_map_buffer(struct bsg_buffer *buf, struct request *req)
  {
  	size_t sz = (sizeof(struct scatterlist) * req->nr_phys_segments);
  
  	BUG_ON(!req->nr_phys_segments);
  
  	buf->sg_list = kzalloc(sz, GFP_KERNEL);
  	if (!buf->sg_list)
  		return -ENOMEM;
  	sg_init_table(buf->sg_list, req->nr_phys_segments);
82ed4db49   Christoph Hellwig   block: split scsi...
114
  	scsi_req(req)->resid_len = blk_rq_bytes(req);
aa387cc89   Mike Christie   block: add bsg he...
115
116
117
118
119
120
  	buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list);
  	buf->payload_len = blk_rq_bytes(req);
  	return 0;
  }
  
  /**
50b4d4855   Benjamin Block   bsg-lib: fix kern...
121
   * bsg_prepare_job - create the bsg_job structure for the bsg request
aa387cc89   Mike Christie   block: add bsg he...
122
123
124
   * @dev: device that is being sent the bsg request
   * @req: BSG request that needs a job structure
   */
50b4d4855   Benjamin Block   bsg-lib: fix kern...
125
  static int bsg_prepare_job(struct device *dev, struct request *req)
aa387cc89   Mike Christie   block: add bsg he...
126
127
  {
  	struct request *rsp = req->next_rq;
82ed4db49   Christoph Hellwig   block: split scsi...
128
  	struct scsi_request *rq = scsi_req(req);
50b4d4855   Benjamin Block   bsg-lib: fix kern...
129
  	struct bsg_job *job = blk_mq_rq_to_pdu(req);
aa387cc89   Mike Christie   block: add bsg he...
130
  	int ret;
82ed4db49   Christoph Hellwig   block: split scsi...
131
132
  	job->request = rq->cmd;
  	job->request_len = rq->cmd_len;
50b4d4855   Benjamin Block   bsg-lib: fix kern...
133

aa387cc89   Mike Christie   block: add bsg he...
134
135
136
137
138
139
140
141
142
143
144
145
146
  	if (req->bio) {
  		ret = bsg_map_buffer(&job->request_payload, req);
  		if (ret)
  			goto failjob_rls_job;
  	}
  	if (rsp && rsp->bio) {
  		ret = bsg_map_buffer(&job->reply_payload, rsp);
  		if (ret)
  			goto failjob_rls_rqst_payload;
  	}
  	job->dev = dev;
  	/* take a reference for the request */
  	get_device(job->dev);
bf0f2d380   Johannes Thumshirn   block: add refere...
147
  	kref_init(&job->kref);
aa387cc89   Mike Christie   block: add bsg he...
148
149
150
151
152
  	return 0;
  
  failjob_rls_rqst_payload:
  	kfree(job->request_payload.sg_list);
  failjob_rls_job:
aa387cc89   Mike Christie   block: add bsg he...
153
154
  	return -ENOMEM;
  }
aa387cc89   Mike Christie   block: add bsg he...
155
156
157
158
159
  /**
   * bsg_request_fn - generic handler for bsg requests
   * @q: request queue to manage
   *
   * On error the create_bsg_job function should return a -Exyz error value
17d5363b8   Christoph Hellwig   scsi: introduce a...
160
   * that will be set to ->result.
aa387cc89   Mike Christie   block: add bsg he...
161
162
163
   *
   * Drivers/subsys should pass this to the queue init function.
   */
8ae94eb65   Christoph Hellwig   block/bsg: move q...
164
  static void bsg_request_fn(struct request_queue *q)
dbb3ab035   Bart Van Assche   bsg: Add sparse a...
165
166
  	__releases(q->queue_lock)
  	__acquires(q->queue_lock)
aa387cc89   Mike Christie   block: add bsg he...
167
168
169
  {
  	struct device *dev = q->queuedata;
  	struct request *req;
aa387cc89   Mike Christie   block: add bsg he...
170
171
172
173
174
175
176
177
178
179
  	int ret;
  
  	if (!get_device(dev))
  		return;
  
  	while (1) {
  		req = blk_fetch_request(q);
  		if (!req)
  			break;
  		spin_unlock_irq(q->queue_lock);
50b4d4855   Benjamin Block   bsg-lib: fix kern...
180
  		ret = bsg_prepare_job(dev, req);
aa387cc89   Mike Christie   block: add bsg he...
181
  		if (ret) {
17d5363b8   Christoph Hellwig   scsi: introduce a...
182
  			scsi_req(req)->result = ret;
2a842acab   Christoph Hellwig   block: introduce ...
183
  			blk_end_request_all(req, BLK_STS_OK);
aa387cc89   Mike Christie   block: add bsg he...
184
185
186
  			spin_lock_irq(q->queue_lock);
  			continue;
  		}
50b4d4855   Benjamin Block   bsg-lib: fix kern...
187
  		ret = q->bsg_job_fn(blk_mq_rq_to_pdu(req));
aa387cc89   Mike Christie   block: add bsg he...
188
189
190
191
192
193
194
195
196
  		spin_lock_irq(q->queue_lock);
  		if (ret)
  			break;
  	}
  
  	spin_unlock_irq(q->queue_lock);
  	put_device(dev);
  	spin_lock_irq(q->queue_lock);
  }
aa387cc89   Mike Christie   block: add bsg he...
197

50b4d4855   Benjamin Block   bsg-lib: fix kern...
198
199
200
201
  static int bsg_init_rq(struct request_queue *q, struct request *req, gfp_t gfp)
  {
  	struct bsg_job *job = blk_mq_rq_to_pdu(req);
  	struct scsi_request *sreq = &job->sreq;
eab40cf33   Benjamin Block   bsg-lib: fix use-...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  	/* called right after the request is allocated for the request_queue */
  
  	sreq->sense = kzalloc(SCSI_SENSE_BUFFERSIZE, gfp);
  	if (!sreq->sense)
  		return -ENOMEM;
  
  	return 0;
  }
  
  static void bsg_initialize_rq(struct request *req)
  {
  	struct bsg_job *job = blk_mq_rq_to_pdu(req);
  	struct scsi_request *sreq = &job->sreq;
  	void *sense = sreq->sense;
  
  	/* called right before the request is given to the request_queue user */
50b4d4855   Benjamin Block   bsg-lib: fix kern...
218
219
220
  	memset(job, 0, sizeof(*job));
  
  	scsi_req_init(sreq);
eab40cf33   Benjamin Block   bsg-lib: fix use-...
221
222
  
  	sreq->sense = sense;
50b4d4855   Benjamin Block   bsg-lib: fix kern...
223
  	sreq->sense_len = SCSI_SENSE_BUFFERSIZE;
50b4d4855   Benjamin Block   bsg-lib: fix kern...
224
225
  
  	job->req = req;
eab40cf33   Benjamin Block   bsg-lib: fix use-...
226
  	job->reply = sense;
50b4d4855   Benjamin Block   bsg-lib: fix kern...
227
228
  	job->reply_len = sreq->sense_len;
  	job->dd_data = job + 1;
50b4d4855   Benjamin Block   bsg-lib: fix kern...
229
230
231
232
233
234
235
236
237
  }
  
  static void bsg_exit_rq(struct request_queue *q, struct request *req)
  {
  	struct bsg_job *job = blk_mq_rq_to_pdu(req);
  	struct scsi_request *sreq = &job->sreq;
  
  	kfree(sreq->sense);
  }
aa387cc89   Mike Christie   block: add bsg he...
238
239
240
  /**
   * bsg_setup_queue - Create and add the bsg hooks so we can receive requests
   * @dev: device to attach bsg device to
aa387cc89   Mike Christie   block: add bsg he...
241
242
243
   * @name: device to give bsg device
   * @job_fn: bsg job handler
   * @dd_job_size: size of LLD data needed for each job
aa387cc89   Mike Christie   block: add bsg he...
244
   */
c1225f01a   Christoph Hellwig   scsi: bsg-lib: pa...
245
246
247
  struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
  		bsg_job_fn *job_fn, int dd_job_size,
  		void (*release)(struct device *))
aa387cc89   Mike Christie   block: add bsg he...
248
  {
8ae94eb65   Christoph Hellwig   block/bsg: move q...
249
  	struct request_queue *q;
aa387cc89   Mike Christie   block: add bsg he...
250
  	int ret;
82ed4db49   Christoph Hellwig   block: split scsi...
251
  	q = blk_alloc_queue(GFP_KERNEL);
8ae94eb65   Christoph Hellwig   block/bsg: move q...
252
253
  	if (!q)
  		return ERR_PTR(-ENOMEM);
50b4d4855   Benjamin Block   bsg-lib: fix kern...
254
255
256
  	q->cmd_size = sizeof(struct bsg_job) + dd_job_size;
  	q->init_rq_fn = bsg_init_rq;
  	q->exit_rq_fn = bsg_exit_rq;
eab40cf33   Benjamin Block   bsg-lib: fix use-...
257
  	q->initialize_rq_fn = bsg_initialize_rq;
82ed4db49   Christoph Hellwig   block: split scsi...
258
259
260
261
262
  	q->request_fn = bsg_request_fn;
  
  	ret = blk_init_allocated_queue(q);
  	if (ret)
  		goto out_cleanup_queue;
8ae94eb65   Christoph Hellwig   block/bsg: move q...
263

aa387cc89   Mike Christie   block: add bsg he...
264
  	q->queuedata = dev;
aa387cc89   Mike Christie   block: add bsg he...
265
266
  	q->bsg_job_fn = job_fn;
  	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
9efc160f4   Bart Van Assche   block: Introduce ...
267
  	queue_flag_set_unlocked(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
aa387cc89   Mike Christie   block: add bsg he...
268
269
  	blk_queue_softirq_done(q, bsg_softirq_done);
  	blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
c1225f01a   Christoph Hellwig   scsi: bsg-lib: pa...
270
  	ret = bsg_register_queue(q, dev, name, release);
aa387cc89   Mike Christie   block: add bsg he...
271
272
273
274
  	if (ret) {
  		printk(KERN_ERR "%s: bsg interface failed to "
  		       "initialize - register queue
  ", dev->kobj.name);
82ed4db49   Christoph Hellwig   block: split scsi...
275
  		goto out_cleanup_queue;
aa387cc89   Mike Christie   block: add bsg he...
276
  	}
8ae94eb65   Christoph Hellwig   block/bsg: move q...
277
  	return q;
82ed4db49   Christoph Hellwig   block: split scsi...
278
279
280
  out_cleanup_queue:
  	blk_cleanup_queue(q);
  	return ERR_PTR(ret);
aa387cc89   Mike Christie   block: add bsg he...
281
282
  }
  EXPORT_SYMBOL_GPL(bsg_setup_queue);