Blame view

drivers/block/ps3disk.c 13.5 KB
935912c53   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
2
3
4
5
6
  /*
   * PS3 Disk Storage Driver
   *
   * Copyright (C) 2007 Sony Computer Entertainment Inc.
   * Copyright 2007 Sony Corp.
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
7
8
9
   */
  
  #include <linux/ata.h>
fab1adcf9   Jens Axboe   ps3disk: convert ...
10
  #include <linux/blk-mq.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
0c8d44f23   Paul Gortmaker   block: Fix files ...
12
  #include <linux/module.h>
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  
  #include <asm/lv1call.h>
  #include <asm/ps3stor.h>
  #include <asm/firmware.h>
  
  
  #define DEVICE_NAME		"ps3disk"
  
  #define BOUNCE_SIZE		(64*1024)
  
  #define PS3DISK_MAX_DISKS	16
  #define PS3DISK_MINORS		16
  
  
  #define PS3DISK_NAME		"ps3d%c"
  
  
  struct ps3disk_private {
  	spinlock_t lock;		/* Request queue spinlock */
  	struct request_queue *queue;
fab1adcf9   Jens Axboe   ps3disk: convert ...
33
  	struct blk_mq_tag_set tag_set;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  	struct gendisk *gendisk;
  	unsigned int blocking_factor;
  	struct request *req;
  	u64 raw_capacity;
  	unsigned char model[ATA_ID_PROD_LEN+1];
  };
  
  
  #define LV1_STORAGE_SEND_ATA_COMMAND	(2)
  #define LV1_STORAGE_ATA_HDDOUT		(0x23)
  
  struct lv1_ata_cmnd_block {
  	u16	features;
  	u16	sector_count;
  	u16	LBA_low;
  	u16	LBA_mid;
  	u16	LBA_high;
  	u8	device;
  	u8	command;
  	u32	is_ext;
  	u32	proto;
  	u32	in_out;
  	u32	size;
  	u64	buffer;
  	u32	arglen;
  };
  
  enum lv1_ata_proto {
  	NON_DATA_PROTO     = 0,
  	PIO_DATA_IN_PROTO  = 1,
  	PIO_DATA_OUT_PROTO = 2,
  	DMA_PROTO = 3
  };
  
  enum lv1_ata_in_out {
  	DIR_WRITE = 0,			/* memory -> device */
  	DIR_READ = 1			/* device -> memory */
  };
  
  static int ps3disk_major;
83d5cde47   Alexey Dobriyan   const: make block...
74
  static const struct block_device_operations ps3disk_fops = {
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
75
76
77
78
79
80
81
82
  	.owner		= THIS_MODULE,
  };
  
  
  static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
  				   struct request *req, int gather)
  {
  	unsigned int offset = 0;
5705f7021   NeilBrown   Introduce rq_for_...
83
  	struct req_iterator iter;
7988613b0   Kent Overstreet   block: Convert bi...
84
  	struct bio_vec bvec;
5705f7021   NeilBrown   Introduce rq_for_...
85
  	unsigned int i = 0;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
86
87
  	size_t size;
  	void *buf;
5705f7021   NeilBrown   Introduce rq_for_...
88
89
  	rq_for_each_segment(bvec, req, iter) {
  		unsigned long flags;
72deb455b   Christoph Hellwig   block: remove CON...
90
91
  		dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u sectors from %llu
  ",
458b76ed2   Kent Overstreet   block: Kill bio_s...
92
93
  			__func__, __LINE__, i, bio_sectors(iter.bio),
  			iter.bio->bi_iter.bi_sector);
5705f7021   NeilBrown   Introduce rq_for_...
94

7988613b0   Kent Overstreet   block: Convert bi...
95
96
  		size = bvec.bv_len;
  		buf = bvec_kmap_irq(&bvec, &flags);
6c92e699b   Jens Axboe   Fixup rq_for_each...
97
98
99
100
101
  		if (gather)
  			memcpy(dev->bounce_buf+offset, buf, size);
  		else
  			memcpy(buf, dev->bounce_buf+offset, size);
  		offset += size;
7988613b0   Kent Overstreet   block: Convert bi...
102
  		flush_kernel_dcache_page(bvec.bv_page);
93055c310   Dan Carpenter   ps3disk: passing ...
103
  		bvec_kunmap_irq(buf, &flags);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
104
105
106
  		i++;
  	}
  }
fab1adcf9   Jens Axboe   ps3disk: convert ...
107
108
  static blk_status_t ps3disk_submit_request_sg(struct ps3_storage_device *dev,
  					      struct request *req)
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
109
  {
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
110
  	struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
111
112
113
114
115
116
117
  	int write = rq_data_dir(req), res;
  	const char *op = write ? "write" : "read";
  	u64 start_sector, sectors;
  	unsigned int region_id = dev->regions[dev->region_idx].id;
  
  #ifdef DEBUG
  	unsigned int n = 0;
7988613b0   Kent Overstreet   block: Convert bi...
118
  	struct bio_vec bv;
5705f7021   NeilBrown   Introduce rq_for_...
119
  	struct req_iterator iter;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
120

5705f7021   NeilBrown   Introduce rq_for_...
121
  	rq_for_each_segment(bv, req, iter)
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
122
123
  		n++;
  	dev_dbg(&dev->sbd.core,
83096ebf1   Tejun Heo   block: convert to...
124
125
126
  		"%s:%u: %s req has %u bvecs for %u sectors
  ",
  		__func__, __LINE__, op, n, blk_rq_sectors(req));
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
127
  #endif
83096ebf1   Tejun Heo   block: convert to...
128
129
  	start_sector = blk_rq_pos(req) * priv->blocking_factor;
  	sectors = blk_rq_sectors(req) * priv->blocking_factor;
e377c6e24   Stephen Rothwell   powerpc/ps3: Prin...
130
131
  	dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu
  ",
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  		__func__, __LINE__, op, sectors, start_sector);
  
  	if (write) {
  		ps3disk_scatter_gather(dev, req, 1);
  
  		res = lv1_storage_write(dev->sbd.dev_id, region_id,
  					start_sector, sectors, 0,
  					dev->bounce_lpar, &dev->tag);
  	} else {
  		res = lv1_storage_read(dev->sbd.dev_id, region_id,
  				       start_sector, sectors, 0,
  				       dev->bounce_lpar, &dev->tag);
  	}
  	if (res) {
  		dev_err(&dev->sbd.core, "%s:%u: %s failed %d
  ", __func__,
  			__LINE__, op, res);
fab1adcf9   Jens Axboe   ps3disk: convert ...
149
  		return BLK_STS_IOERR;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
150
151
152
  	}
  
  	priv->req = req;
fab1adcf9   Jens Axboe   ps3disk: convert ...
153
  	return BLK_STS_OK;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
154
  }
fab1adcf9   Jens Axboe   ps3disk: convert ...
155
156
  static blk_status_t ps3disk_submit_flush_request(struct ps3_storage_device *dev,
  						 struct request *req)
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
157
  {
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
158
  	struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
159
160
161
162
163
164
165
166
167
  	u64 res;
  
  	dev_dbg(&dev->sbd.core, "%s:%u: flush request
  ", __func__, __LINE__);
  
  	res = lv1_storage_send_device_command(dev->sbd.dev_id,
  					      LV1_STORAGE_ATA_HDDOUT, 0, 0, 0,
  					      0, &dev->tag);
  	if (res) {
e377c6e24   Stephen Rothwell   powerpc/ps3: Prin...
168
169
  		dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx
  ",
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
170
  			__func__, __LINE__, res);
fab1adcf9   Jens Axboe   ps3disk: convert ...
171
  		return BLK_STS_IOERR;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
172
173
174
  	}
  
  	priv->req = req;
fab1adcf9   Jens Axboe   ps3disk: convert ...
175
  	return BLK_STS_OK;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
176
  }
fab1adcf9   Jens Axboe   ps3disk: convert ...
177
178
  static blk_status_t ps3disk_do_request(struct ps3_storage_device *dev,
  				       struct request *req)
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
179
  {
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
180
181
  	dev_dbg(&dev->sbd.core, "%s:%u
  ", __func__, __LINE__);
fab1adcf9   Jens Axboe   ps3disk: convert ...
182
183
184
185
186
187
188
189
190
  	switch (req_op(req)) {
  	case REQ_OP_FLUSH:
  		return ps3disk_submit_flush_request(dev, req);
  	case REQ_OP_READ:
  	case REQ_OP_WRITE:
  		return ps3disk_submit_request_sg(dev, req);
  	default:
  		blk_dump_rq_flags(req, DEVICE_NAME " bad request");
  		return BLK_STS_IOERR;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
191
192
  	}
  }
fab1adcf9   Jens Axboe   ps3disk: convert ...
193
194
  static blk_status_t ps3disk_queue_rq(struct blk_mq_hw_ctx *hctx,
  				     const struct blk_mq_queue_data *bd)
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
195
  {
fab1adcf9   Jens Axboe   ps3disk: convert ...
196
  	struct request_queue *q = hctx->queue;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
197
  	struct ps3_storage_device *dev = q->queuedata;
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
198
  	struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
fab1adcf9   Jens Axboe   ps3disk: convert ...
199
  	blk_status_t ret;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
200

fab1adcf9   Jens Axboe   ps3disk: convert ...
201
202
203
204
205
  	blk_mq_start_request(bd->rq);
  
  	spin_lock_irq(&priv->lock);
  	ret = ps3disk_do_request(dev, bd->rq);
  	spin_unlock_irq(&priv->lock);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
206

fab1adcf9   Jens Axboe   ps3disk: convert ...
207
  	return ret;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
208
209
210
211
212
213
214
  }
  
  static irqreturn_t ps3disk_interrupt(int irq, void *data)
  {
  	struct ps3_storage_device *dev = data;
  	struct ps3disk_private *priv;
  	struct request *req;
2a842acab   Christoph Hellwig   block: introduce ...
215
216
  	int res, read;
  	blk_status_t error;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
217
  	u64 tag, status;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
218
219
220
221
222
223
  	const char *op;
  
  	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
  
  	if (tag != dev->tag)
  		dev_err(&dev->sbd.core,
e377c6e24   Stephen Rothwell   powerpc/ps3: Prin...
224
225
  			"%s:%u: tag mismatch, got %llx, expected %llx
  ",
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
226
227
228
  			__func__, __LINE__, tag, dev->tag);
  
  	if (res) {
e377c6e24   Stephen Rothwell   powerpc/ps3: Prin...
229
230
  		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx
  ",
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
231
232
233
  			__func__, __LINE__, res, status);
  		return IRQ_HANDLED;
  	}
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
234
  	priv = ps3_system_bus_get_drvdata(&dev->sbd);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
235
236
237
238
239
240
241
242
243
244
  	req = priv->req;
  	if (!req) {
  		dev_dbg(&dev->sbd.core,
  			"%s:%u non-block layer request completed
  ", __func__,
  			__LINE__);
  		dev->lv1_status = status;
  		complete(&dev->done);
  		return IRQ_HANDLED;
  	}
3a5e02ced   Mike Christie   block, drivers: a...
245
  	if (req_op(req) == REQ_OP_FLUSH) {
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
246
  		read = 0;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
247
248
249
  		op = "flush";
  	} else {
  		read = !rq_data_dir(req);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
250
251
252
  		op = read ? "read" : "write";
  	}
  	if (status) {
e377c6e24   Stephen Rothwell   powerpc/ps3: Prin...
253
254
  		dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx
  ", __func__,
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
255
  			__LINE__, op, status);
2a842acab   Christoph Hellwig   block: introduce ...
256
  		error = BLK_STS_IOERR;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
257
258
259
260
  	} else {
  		dev_dbg(&dev->sbd.core, "%s:%u: %s completed
  ", __func__,
  			__LINE__, op);
f01ab252c   Kiyoshi Ueda   blk_end_request: ...
261
  		error = 0;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
262
263
264
265
266
  		if (read)
  			ps3disk_scatter_gather(dev, req, 0);
  	}
  
  	spin_lock(&priv->lock);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
267
  	priv->req = NULL;
fab1adcf9   Jens Axboe   ps3disk: convert ...
268
  	blk_mq_end_request(req, error);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
269
  	spin_unlock(&priv->lock);
fab1adcf9   Jens Axboe   ps3disk: convert ...
270
  	blk_mq_run_hw_queues(priv->queue, true);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
271
272
273
274
275
276
277
278
279
280
281
282
  	return IRQ_HANDLED;
  }
  
  static int ps3disk_sync_cache(struct ps3_storage_device *dev)
  {
  	u64 res;
  
  	dev_dbg(&dev->sbd.core, "%s:%u: sync cache
  ", __func__, __LINE__);
  
  	res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0);
  	if (res) {
e377c6e24   Stephen Rothwell   powerpc/ps3: Prin...
283
284
  		dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx
  ",
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  			__func__, __LINE__, res);
  		return -EIO;
  	}
  	return 0;
  }
  
  
  /* ATA helpers copied from drivers/ata/libata-core.c */
  
  static void swap_buf_le16(u16 *buf, unsigned int buf_words)
  {
  #ifdef __BIG_ENDIAN
  	unsigned int i;
  
  	for (i = 0; i < buf_words; i++)
  		buf[i] = le16_to_cpu(buf[i]);
  #endif /* __BIG_ENDIAN */
  }
  
  static u64 ata_id_n_sectors(const u16 *id)
  {
  	if (ata_id_has_lba(id)) {
  		if (ata_id_has_lba48(id))
  			return ata_id_u64(id, 100);
  		else
  			return ata_id_u32(id, 60);
  	} else {
  		if (ata_id_current_chs_valid(id))
  			return ata_id_u32(id, 57);
  		else
  			return id[1] * id[3] * id[6];
  	}
  }
  
  static void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs,
  			  unsigned int len)
  {
  	unsigned int c;
  
  	while (len > 0) {
  		c = id[ofs] >> 8;
  		*s = c;
  		s++;
  
  		c = id[ofs] & 0xff;
  		*s = c;
  		s++;
  
  		ofs++;
  		len -= 2;
  	}
  }
  
  static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
  			    unsigned int len)
  {
  	unsigned char *p;
  
  	WARN_ON(!(len & 1));
  
  	ata_id_string(id, s, ofs, len - 1);
  
  	p = s + strnlen(s, len - 1);
  	while (p > s && p[-1] == ' ')
  		p--;
  	*p = '\0';
  }
  
  static int ps3disk_identify(struct ps3_storage_device *dev)
  {
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
355
  	struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  	struct lv1_ata_cmnd_block ata_cmnd;
  	u16 *id = dev->bounce_buf;
  	u64 res;
  
  	dev_dbg(&dev->sbd.core, "%s:%u: identify disk
  ", __func__, __LINE__);
  
  	memset(&ata_cmnd, 0, sizeof(struct lv1_ata_cmnd_block));
  	ata_cmnd.command = ATA_CMD_ID_ATA;
  	ata_cmnd.sector_count = 1;
  	ata_cmnd.size = ata_cmnd.arglen = ATA_ID_WORDS * 2;
  	ata_cmnd.buffer = dev->bounce_lpar;
  	ata_cmnd.proto = PIO_DATA_IN_PROTO;
  	ata_cmnd.in_out = DIR_READ;
  
  	res = ps3stor_send_command(dev, LV1_STORAGE_SEND_ATA_COMMAND,
  				   ps3_mm_phys_to_lpar(__pa(&ata_cmnd)),
  				   sizeof(ata_cmnd), ata_cmnd.buffer,
  				   ata_cmnd.arglen);
  	if (res) {
e377c6e24   Stephen Rothwell   powerpc/ps3: Prin...
376
377
  		dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%llx
  ",
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
378
379
380
381
382
383
384
385
386
387
388
  			__func__, __LINE__, res);
  		return -EIO;
  	}
  
  	swap_buf_le16(id, ATA_ID_WORDS);
  
  	/* All we're interested in are raw capacity and model name */
  	priv->raw_capacity = ata_id_n_sectors(id);
  	ata_id_c_string(id, priv->model, ATA_ID_PROD, sizeof(priv->model));
  	return 0;
  }
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
389
390
391
  static unsigned long ps3disk_mask;
  
  static DEFINE_MUTEX(ps3disk_mask_mutex);
fab1adcf9   Jens Axboe   ps3disk: convert ...
392
393
394
  static const struct blk_mq_ops ps3disk_mq_ops = {
  	.queue_rq	= ps3disk_queue_rq,
  };
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
395
  static int ps3disk_probe(struct ps3_system_bus_device *_dev)
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
396
397
398
399
400
401
402
403
404
405
  {
  	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
  	struct ps3disk_private *priv;
  	int error;
  	unsigned int devidx;
  	struct request_queue *queue;
  	struct gendisk *gendisk;
  
  	if (dev->blk_size < 512) {
  		dev_err(&dev->sbd.core,
e377c6e24   Stephen Rothwell   powerpc/ps3: Prin...
406
407
  			"%s:%u: cannot handle block size %llu
  ", __func__,
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  			__LINE__, dev->blk_size);
  		return -EINVAL;
  	}
  
  	BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG);
  	mutex_lock(&ps3disk_mask_mutex);
  	devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS);
  	if (devidx >= PS3DISK_MAX_DISKS) {
  		dev_err(&dev->sbd.core, "%s:%u: Too many disks
  ", __func__,
  			__LINE__);
  		mutex_unlock(&ps3disk_mask_mutex);
  		return -ENOSPC;
  	}
  	__set_bit(devidx, &ps3disk_mask);
  	mutex_unlock(&ps3disk_mask_mutex);
  
  	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  	if (!priv) {
  		error = -ENOMEM;
  		goto fail;
  	}
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
430
  	ps3_system_bus_set_drvdata(_dev, priv);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  	spin_lock_init(&priv->lock);
  
  	dev->bounce_size = BOUNCE_SIZE;
  	dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
  	if (!dev->bounce_buf) {
  		error = -ENOMEM;
  		goto fail_free_priv;
  	}
  
  	error = ps3stor_setup(dev, ps3disk_interrupt);
  	if (error)
  		goto fail_free_bounce;
  
  	ps3disk_identify(dev);
fab1adcf9   Jens Axboe   ps3disk: convert ...
445
446
447
448
449
  	queue = blk_mq_init_sq_queue(&priv->tag_set, &ps3disk_mq_ops, 1,
  					BLK_MQ_F_SHOULD_MERGE);
  	if (IS_ERR(queue)) {
  		dev_err(&dev->sbd.core, "%s:%u: blk_mq_init_queue failed
  ",
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
450
  			__func__, __LINE__);
fab1adcf9   Jens Axboe   ps3disk: convert ...
451
  		error = PTR_ERR(queue);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
452
453
454
455
456
  		goto fail_teardown;
  	}
  
  	priv->queue = queue;
  	queue->queuedata = dev;
086fa5ff0   Martin K. Petersen   block: Rename blk...
457
  	blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
458
  	blk_queue_dma_alignment(queue, dev->blk_size-1);
e1defc4ff   Martin K. Petersen   block: Do away wi...
459
  	blk_queue_logical_block_size(queue, dev->blk_size);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
460

12c95f137   Jens Axboe   ps3disk: switch t...
461
  	blk_queue_write_cache(queue, true, false);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
462

8a78362c4   Martin K. Petersen   block: Consolidat...
463
  	blk_queue_max_segments(queue, -1);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  	blk_queue_max_segment_size(queue, dev->bounce_size);
  
  	gendisk = alloc_disk(PS3DISK_MINORS);
  	if (!gendisk) {
  		dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed
  ", __func__,
  			__LINE__);
  		error = -ENOMEM;
  		goto fail_cleanup_queue;
  	}
  
  	priv->gendisk = gendisk;
  	gendisk->major = ps3disk_major;
  	gendisk->first_minor = devidx * PS3DISK_MINORS;
  	gendisk->fops = &ps3disk_fops;
  	gendisk->queue = queue;
  	gendisk->private_data = dev;
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
481
482
483
484
485
486
487
  	snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME,
  		 devidx+'a');
  	priv->blocking_factor = dev->blk_size >> 9;
  	set_capacity(gendisk,
  		     dev->regions[dev->region_idx].size*priv->blocking_factor);
  
  	dev_info(&dev->sbd.core,
72deb455b   Christoph Hellwig   block: remove CON...
488
489
  		 "%s is a %s (%llu MiB total, %llu MiB for OtherOS)
  ",
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
490
491
  		 gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
  		 get_capacity(gendisk) >> 11);
fef912bf8   Hannes Reinecke   block: genhd: add...
492
  	device_add_disk(&dev->sbd.core, gendisk, NULL);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
493
494
495
496
  	return 0;
  
  fail_cleanup_queue:
  	blk_cleanup_queue(queue);
fab1adcf9   Jens Axboe   ps3disk: convert ...
497
  	blk_mq_free_tag_set(&priv->tag_set);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
498
499
500
501
502
503
  fail_teardown:
  	ps3stor_teardown(dev);
  fail_free_bounce:
  	kfree(dev->bounce_buf);
  fail_free_priv:
  	kfree(priv);
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
504
  	ps3_system_bus_set_drvdata(_dev, NULL);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
505
506
507
508
509
510
511
512
513
514
  fail:
  	mutex_lock(&ps3disk_mask_mutex);
  	__clear_bit(devidx, &ps3disk_mask);
  	mutex_unlock(&ps3disk_mask_mutex);
  	return error;
  }
  
  static int ps3disk_remove(struct ps3_system_bus_device *_dev)
  {
  	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
515
  	struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
516
517
  
  	mutex_lock(&ps3disk_mask_mutex);
f331c0296   Tejun Heo   block: don't depe...
518
  	__clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
519
520
521
522
  		    &ps3disk_mask);
  	mutex_unlock(&ps3disk_mask_mutex);
  	del_gendisk(priv->gendisk);
  	blk_cleanup_queue(priv->queue);
fab1adcf9   Jens Axboe   ps3disk: convert ...
523
  	blk_mq_free_tag_set(&priv->tag_set);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
524
525
526
527
528
529
530
  	put_disk(priv->gendisk);
  	dev_notice(&dev->sbd.core, "Synchronizing disk cache
  ");
  	ps3disk_sync_cache(dev);
  	ps3stor_teardown(dev);
  	kfree(dev->bounce_buf);
  	kfree(priv);
03fa68c24   Geert Uytterhoeven   ps3: shorten ps3_...
531
  	ps3_system_bus_set_drvdata(_dev, NULL);
c6131fa52   Geert Uytterhoeven   ps3: Disk Storage...
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
  	return 0;
  }
  
  static struct ps3_system_bus_driver ps3disk = {
  	.match_id	= PS3_MATCH_ID_STOR_DISK,
  	.core.name	= DEVICE_NAME,
  	.core.owner	= THIS_MODULE,
  	.probe		= ps3disk_probe,
  	.remove		= ps3disk_remove,
  	.shutdown	= ps3disk_remove,
  };
  
  
  static int __init ps3disk_init(void)
  {
  	int error;
  
  	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
  		return -ENODEV;
  
  	error = register_blkdev(0, DEVICE_NAME);
  	if (error <= 0) {
  		printk(KERN_ERR "%s:%u: register_blkdev failed %d
  ", __func__,
  		       __LINE__, error);
  		return error;
  	}
  	ps3disk_major = error;
  
  	pr_info("%s:%u: registered block device major %d
  ", __func__,
  		__LINE__, ps3disk_major);
  
  	error = ps3_system_bus_driver_register(&ps3disk);
  	if (error)
  		unregister_blkdev(ps3disk_major, DEVICE_NAME);
  
  	return error;
  }
  
  static void __exit ps3disk_exit(void)
  {
  	ps3_system_bus_driver_unregister(&ps3disk);
  	unregister_blkdev(ps3disk_major, DEVICE_NAME);
  }
  
  module_init(ps3disk_init);
  module_exit(ps3disk_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("PS3 Disk Storage Driver");
  MODULE_AUTHOR("Sony Corporation");
  MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_DISK);