diff options
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 256 |
1 files changed, 157 insertions, 99 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 9715be3f2487..55bd35c0f082 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/blkpg.h> | 33 | #include <linux/blkpg.h> |
34 | #include <linux/timer.h> | 34 | #include <linux/timer.h> |
35 | #include <linux/proc_fs.h> | 35 | #include <linux/proc_fs.h> |
36 | #include <linux/seq_file.h> | ||
36 | #include <linux/init.h> | 37 | #include <linux/init.h> |
37 | #include <linux/hdreg.h> | 38 | #include <linux/hdreg.h> |
38 | #include <linux/spinlock.h> | 39 | #include <linux/spinlock.h> |
@@ -131,7 +132,6 @@ static struct board_type products[] = { | |||
131 | /*define how many times we will try a command because of bus resets */ | 132 | /*define how many times we will try a command because of bus resets */ |
132 | #define MAX_CMD_RETRIES 3 | 133 | #define MAX_CMD_RETRIES 3 |
133 | 134 | ||
134 | #define READ_AHEAD 1024 | ||
135 | #define MAX_CTLR 32 | 135 | #define MAX_CTLR 32 |
136 | 136 | ||
137 | /* Originally cciss driver only supports 8 major numbers */ | 137 | /* Originally cciss driver only supports 8 major numbers */ |
@@ -174,8 +174,6 @@ static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, | |||
174 | static void fail_all_cmds(unsigned long ctlr); | 174 | static void fail_all_cmds(unsigned long ctlr); |
175 | 175 | ||
176 | #ifdef CONFIG_PROC_FS | 176 | #ifdef CONFIG_PROC_FS |
177 | static int cciss_proc_get_info(char *buffer, char **start, off_t offset, | ||
178 | int length, int *eof, void *data); | ||
179 | static void cciss_procinit(int i); | 177 | static void cciss_procinit(int i); |
180 | #else | 178 | #else |
181 | static void cciss_procinit(int i) | 179 | static void cciss_procinit(int i) |
@@ -240,24 +238,46 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, | |||
240 | */ | 238 | */ |
241 | #define ENG_GIG 1000000000 | 239 | #define ENG_GIG 1000000000 |
242 | #define ENG_GIG_FACTOR (ENG_GIG/512) | 240 | #define ENG_GIG_FACTOR (ENG_GIG/512) |
241 | #define ENGAGE_SCSI "engage scsi" | ||
243 | static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", | 242 | static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", |
244 | "UNKNOWN" | 243 | "UNKNOWN" |
245 | }; | 244 | }; |
246 | 245 | ||
247 | static struct proc_dir_entry *proc_cciss; | 246 | static struct proc_dir_entry *proc_cciss; |
248 | 247 | ||
249 | static int cciss_proc_get_info(char *buffer, char **start, off_t offset, | 248 | static void cciss_seq_show_header(struct seq_file *seq) |
250 | int length, int *eof, void *data) | ||
251 | { | 249 | { |
252 | off_t pos = 0; | 250 | ctlr_info_t *h = seq->private; |
253 | off_t len = 0; | 251 | |
254 | int size, i, ctlr; | 252 | seq_printf(seq, "%s: HP %s Controller\n" |
255 | ctlr_info_t *h = (ctlr_info_t *) data; | 253 | "Board ID: 0x%08lx\n" |
256 | drive_info_struct *drv; | 254 | "Firmware Version: %c%c%c%c\n" |
257 | unsigned long flags; | 255 | "IRQ: %d\n" |
258 | sector_t vol_sz, vol_sz_frac; | 256 | "Logical drives: %d\n" |
257 | "Current Q depth: %d\n" | ||
258 | "Current # commands on controller: %d\n" | ||
259 | "Max Q depth since init: %d\n" | ||
260 | "Max # commands on controller since init: %d\n" | ||
261 | "Max SG entries since init: %d\n", | ||
262 | h->devname, | ||
263 | h->product_name, | ||
264 | (unsigned long)h->board_id, | ||
265 | h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], | ||
266 | h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT], | ||
267 | h->num_luns, | ||
268 | h->Qdepth, h->commands_outstanding, | ||
269 | h->maxQsinceinit, h->max_outstanding, h->maxSG); | ||
259 | 270 | ||
260 | ctlr = h->ctlr; | 271 | #ifdef CONFIG_CISS_SCSI_TAPE |
272 | cciss_seq_tape_report(seq, h->ctlr); | ||
273 | #endif /* CONFIG_CISS_SCSI_TAPE */ | ||
274 | } | ||
275 | |||
276 | static void *cciss_seq_start(struct seq_file *seq, loff_t *pos) | ||
277 | { | ||
278 | ctlr_info_t *h = seq->private; | ||
279 | unsigned ctlr = h->ctlr; | ||
280 | unsigned long flags; | ||
261 | 281 | ||
262 | /* prevent displaying bogus info during configuration | 282 | /* prevent displaying bogus info during configuration |
263 | * or deconfiguration of a logical volume | 283 | * or deconfiguration of a logical volume |
@@ -265,115 +285,155 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, | |||
265 | spin_lock_irqsave(CCISS_LOCK(ctlr), flags); | 285 | spin_lock_irqsave(CCISS_LOCK(ctlr), flags); |
266 | if (h->busy_configuring) { | 286 | if (h->busy_configuring) { |
267 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 287 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); |
268 | return -EBUSY; | 288 | return ERR_PTR(-EBUSY); |
269 | } | 289 | } |
270 | h->busy_configuring = 1; | 290 | h->busy_configuring = 1; |
271 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 291 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); |
272 | 292 | ||
273 | size = sprintf(buffer, "%s: HP %s Controller\n" | 293 | if (*pos == 0) |
274 | "Board ID: 0x%08lx\n" | 294 | cciss_seq_show_header(seq); |
275 | "Firmware Version: %c%c%c%c\n" | ||
276 | "IRQ: %d\n" | ||
277 | "Logical drives: %d\n" | ||
278 | "Max sectors: %d\n" | ||
279 | "Current Q depth: %d\n" | ||
280 | "Current # commands on controller: %d\n" | ||
281 | "Max Q depth since init: %d\n" | ||
282 | "Max # commands on controller since init: %d\n" | ||
283 | "Max SG entries since init: %d\n\n", | ||
284 | h->devname, | ||
285 | h->product_name, | ||
286 | (unsigned long)h->board_id, | ||
287 | h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], | ||
288 | h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT], | ||
289 | h->num_luns, | ||
290 | h->cciss_max_sectors, | ||
291 | h->Qdepth, h->commands_outstanding, | ||
292 | h->maxQsinceinit, h->max_outstanding, h->maxSG); | ||
293 | |||
294 | pos += size; | ||
295 | len += size; | ||
296 | cciss_proc_tape_report(ctlr, buffer, &pos, &len); | ||
297 | for (i = 0; i <= h->highest_lun; i++) { | ||
298 | |||
299 | drv = &h->drv[i]; | ||
300 | if (drv->heads == 0) | ||
301 | continue; | ||
302 | 295 | ||
303 | vol_sz = drv->nr_blocks; | 296 | return pos; |
304 | vol_sz_frac = sector_div(vol_sz, ENG_GIG_FACTOR); | 297 | } |
305 | vol_sz_frac *= 100; | 298 | |
306 | sector_div(vol_sz_frac, ENG_GIG_FACTOR); | 299 | static int cciss_seq_show(struct seq_file *seq, void *v) |
300 | { | ||
301 | sector_t vol_sz, vol_sz_frac; | ||
302 | ctlr_info_t *h = seq->private; | ||
303 | unsigned ctlr = h->ctlr; | ||
304 | loff_t *pos = v; | ||
305 | drive_info_struct *drv = &h->drv[*pos]; | ||
306 | |||
307 | if (*pos > h->highest_lun) | ||
308 | return 0; | ||
309 | |||
310 | if (drv->heads == 0) | ||
311 | return 0; | ||
312 | |||
313 | vol_sz = drv->nr_blocks; | ||
314 | vol_sz_frac = sector_div(vol_sz, ENG_GIG_FACTOR); | ||
315 | vol_sz_frac *= 100; | ||
316 | sector_div(vol_sz_frac, ENG_GIG_FACTOR); | ||
317 | |||
318 | if (drv->raid_level > 5) | ||
319 | drv->raid_level = RAID_UNKNOWN; | ||
320 | seq_printf(seq, "cciss/c%dd%d:" | ||
321 | "\t%4u.%02uGB\tRAID %s\n", | ||
322 | ctlr, (int) *pos, (int)vol_sz, (int)vol_sz_frac, | ||
323 | raid_label[drv->raid_level]); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static void *cciss_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
328 | { | ||
329 | ctlr_info_t *h = seq->private; | ||
330 | |||
331 | if (*pos > h->highest_lun) | ||
332 | return NULL; | ||
333 | *pos += 1; | ||
334 | |||
335 | return pos; | ||
336 | } | ||
337 | |||
338 | static void cciss_seq_stop(struct seq_file *seq, void *v) | ||
339 | { | ||
340 | ctlr_info_t *h = seq->private; | ||
341 | |||
342 | /* Only reset h->busy_configuring if we succeeded in setting | ||
343 | * it during cciss_seq_start. */ | ||
344 | if (v == ERR_PTR(-EBUSY)) | ||
345 | return; | ||
307 | 346 | ||
308 | if (drv->raid_level > 5) | ||
309 | drv->raid_level = RAID_UNKNOWN; | ||
310 | size = sprintf(buffer + len, "cciss/c%dd%d:" | ||
311 | "\t%4u.%02uGB\tRAID %s\n", | ||
312 | ctlr, i, (int)vol_sz, (int)vol_sz_frac, | ||
313 | raid_label[drv->raid_level]); | ||
314 | pos += size; | ||
315 | len += size; | ||
316 | } | ||
317 | |||
318 | *eof = 1; | ||
319 | *start = buffer + offset; | ||
320 | len -= offset; | ||
321 | if (len > length) | ||
322 | len = length; | ||
323 | h->busy_configuring = 0; | 347 | h->busy_configuring = 0; |
324 | return len; | ||
325 | } | 348 | } |
326 | 349 | ||
327 | static int | 350 | static struct seq_operations cciss_seq_ops = { |
328 | cciss_proc_write(struct file *file, const char __user *buffer, | 351 | .start = cciss_seq_start, |
329 | unsigned long count, void *data) | 352 | .show = cciss_seq_show, |
353 | .next = cciss_seq_next, | ||
354 | .stop = cciss_seq_stop, | ||
355 | }; | ||
356 | |||
357 | static int cciss_seq_open(struct inode *inode, struct file *file) | ||
330 | { | 358 | { |
331 | unsigned char cmd[80]; | 359 | int ret = seq_open(file, &cciss_seq_ops); |
332 | int len; | 360 | struct seq_file *seq = file->private_data; |
333 | #ifdef CONFIG_CISS_SCSI_TAPE | 361 | |
334 | ctlr_info_t *h = (ctlr_info_t *) data; | 362 | if (!ret) |
335 | int rc; | 363 | seq->private = PDE(inode)->data; |
364 | |||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static ssize_t | ||
369 | cciss_proc_write(struct file *file, const char __user *buf, | ||
370 | size_t length, loff_t *ppos) | ||
371 | { | ||
372 | int err; | ||
373 | char *buffer; | ||
374 | |||
375 | #ifndef CONFIG_CISS_SCSI_TAPE | ||
376 | return -EINVAL; | ||
336 | #endif | 377 | #endif |
337 | 378 | ||
338 | if (count > sizeof(cmd) - 1) | 379 | if (!buf || length > PAGE_SIZE - 1) |
339 | return -EINVAL; | 380 | return -EINVAL; |
340 | if (copy_from_user(cmd, buffer, count)) | 381 | |
341 | return -EFAULT; | 382 | buffer = (char *)__get_free_page(GFP_KERNEL); |
342 | cmd[count] = '\0'; | 383 | if (!buffer) |
343 | len = strlen(cmd); // above 3 lines ensure safety | 384 | return -ENOMEM; |
344 | if (len && cmd[len - 1] == '\n') | 385 | |
345 | cmd[--len] = '\0'; | 386 | err = -EFAULT; |
346 | # ifdef CONFIG_CISS_SCSI_TAPE | 387 | if (copy_from_user(buffer, buf, length)) |
347 | if (strcmp("engage scsi", cmd) == 0) { | 388 | goto out; |
389 | buffer[length] = '\0'; | ||
390 | |||
391 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
392 | if (strncmp(ENGAGE_SCSI, buffer, sizeof ENGAGE_SCSI - 1) == 0) { | ||
393 | struct seq_file *seq = file->private_data; | ||
394 | ctlr_info_t *h = seq->private; | ||
395 | int rc; | ||
396 | |||
348 | rc = cciss_engage_scsi(h->ctlr); | 397 | rc = cciss_engage_scsi(h->ctlr); |
349 | if (rc != 0) | 398 | if (rc != 0) |
350 | return -rc; | 399 | err = -rc; |
351 | return count; | 400 | else |
352 | } | 401 | err = length; |
402 | } else | ||
403 | #endif /* CONFIG_CISS_SCSI_TAPE */ | ||
404 | err = -EINVAL; | ||
353 | /* might be nice to have "disengage" too, but it's not | 405 | /* might be nice to have "disengage" too, but it's not |
354 | safely possible. (only 1 module use count, lock issues.) */ | 406 | safely possible. (only 1 module use count, lock issues.) */ |
355 | # endif | 407 | |
356 | return -EINVAL; | 408 | out: |
409 | free_page((unsigned long)buffer); | ||
410 | return err; | ||
357 | } | 411 | } |
358 | 412 | ||
359 | /* | 413 | static struct file_operations cciss_proc_fops = { |
360 | * Get us a file in /proc/cciss that says something about each controller. | 414 | .owner = THIS_MODULE, |
361 | * Create /proc/cciss if it doesn't exist yet. | 415 | .open = cciss_seq_open, |
362 | */ | 416 | .read = seq_read, |
417 | .llseek = seq_lseek, | ||
418 | .release = seq_release, | ||
419 | .write = cciss_proc_write, | ||
420 | }; | ||
421 | |||
363 | static void __devinit cciss_procinit(int i) | 422 | static void __devinit cciss_procinit(int i) |
364 | { | 423 | { |
365 | struct proc_dir_entry *pde; | 424 | struct proc_dir_entry *pde; |
366 | 425 | ||
367 | if (proc_cciss == NULL) { | 426 | if (proc_cciss == NULL) |
368 | proc_cciss = proc_mkdir("cciss", proc_root_driver); | 427 | proc_cciss = proc_mkdir("cciss", proc_root_driver); |
369 | if (!proc_cciss) | 428 | if (!proc_cciss) |
370 | return; | 429 | return; |
371 | } | 430 | pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP | |
431 | S_IROTH, proc_cciss, | ||
432 | &cciss_proc_fops); | ||
433 | if (!pde) | ||
434 | return; | ||
372 | 435 | ||
373 | pde = create_proc_read_entry(hba[i]->devname, | 436 | pde->data = hba[i]; |
374 | S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, | ||
375 | proc_cciss, cciss_proc_get_info, hba[i]); | ||
376 | pde->write_proc = cciss_proc_write; | ||
377 | } | 437 | } |
378 | #endif /* CONFIG_PROC_FS */ | 438 | #endif /* CONFIG_PROC_FS */ |
379 | 439 | ||
@@ -1341,7 +1401,6 @@ geo_inq: | |||
1341 | disk->private_data = &h->drv[drv_index]; | 1401 | disk->private_data = &h->drv[drv_index]; |
1342 | 1402 | ||
1343 | /* Set up queue information */ | 1403 | /* Set up queue information */ |
1344 | disk->queue->backing_dev_info.ra_pages = READ_AHEAD; | ||
1345 | blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask); | 1404 | blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask); |
1346 | 1405 | ||
1347 | /* This is a hardware imposed limit. */ | 1406 | /* This is a hardware imposed limit. */ |
@@ -3434,7 +3493,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3434 | } | 3493 | } |
3435 | drv->queue = q; | 3494 | drv->queue = q; |
3436 | 3495 | ||
3437 | q->backing_dev_info.ra_pages = READ_AHEAD; | ||
3438 | blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); | 3496 | blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); |
3439 | 3497 | ||
3440 | /* This is a hardware imposed limit. */ | 3498 | /* This is a hardware imposed limit. */ |