1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/drivers/scsi/scsi_proc.c 4 * 5 * The functions in this file provide an interface between 6 * the PROC file system and the SCSI device drivers 7 * It is mainly used for debugging, statistics and to pass 8 * information directly to the lowlevel driver. 9 * 10 * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de 11 * Version: 0.99.8 last change: 95/09/13 12 * 13 * generic command parser provided by: 14 * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de> 15 * 16 * generic_proc_info() support of xxxx_info() by: 17 * Michael A. Griffith <grif@acm.org> 18 */ 19 20 #include <linux/module.h> 21 #include <linux/init.h> 22 #include <linux/string.h> 23 #include <linux/mm.h> 24 #include <linux/proc_fs.h> 25 #include <linux/errno.h> 26 #include <linux/blkdev.h> 27 #include <linux/seq_file.h> 28 #include <linux/mutex.h> 29 #include <linux/gfp.h> 30 #include <linux/uaccess.h> 31 32 #include <scsi/scsi.h> 33 #include <scsi/scsi_device.h> 34 #include <scsi/scsi_host.h> 35 #include <scsi/scsi_transport.h> 36 37 #include "scsi_priv.h" 38 #include "scsi_logging.h" 39 40 41 /* 4K page size, but our output routines, use some slack for overruns */ 42 #define PROC_BLOCK_SIZE (3*1024) 43 44 static struct proc_dir_entry *proc_scsi; 45 46 /* Protects scsi_proc_list */ 47 static DEFINE_MUTEX(global_host_template_mutex); 48 static LIST_HEAD(scsi_proc_list); 49 50 /** 51 * struct scsi_proc_entry - (host template, SCSI proc dir) association 52 * @entry: entry in scsi_proc_list. 53 * @sht: SCSI host template associated with the procfs directory. 54 * @proc_dir: procfs directory associated with the SCSI host template. 55 * @present: Number of SCSI hosts instantiated for @sht. 56 */ 57 struct scsi_proc_entry { 58 struct list_head entry; 59 const struct scsi_host_template *sht; 60 struct proc_dir_entry *proc_dir; 61 unsigned int present; 62 }; 63 64 static ssize_t proc_scsi_host_write(struct file *file, const char __user *buf, 65 size_t count, loff_t *ppos) 66 { 67 struct Scsi_Host *shost = pde_data(file_inode(file)); 68 ssize_t ret = -ENOMEM; 69 char *page; 70 71 if (count > PROC_BLOCK_SIZE) 72 return -EOVERFLOW; 73 74 if (!shost->hostt->write_info) 75 return -EINVAL; 76 77 page = (char *)__get_free_page(GFP_KERNEL); 78 if (page) { 79 ret = -EFAULT; 80 if (copy_from_user(page, buf, count)) 81 goto out; 82 ret = shost->hostt->write_info(shost, page, count); 83 } 84 out: 85 free_page((unsigned long)page); 86 return ret; 87 } 88 89 static int proc_scsi_show(struct seq_file *m, void *v) 90 { 91 struct Scsi_Host *shost = m->private; 92 return shost->hostt->show_info(m, shost); 93 } 94 95 static int proc_scsi_host_open(struct inode *inode, struct file *file) 96 { 97 return single_open_size(file, proc_scsi_show, pde_data(inode), 98 4 * PAGE_SIZE); 99 } 100 101 static struct scsi_proc_entry * 102 __scsi_lookup_proc_entry(const struct scsi_host_template *sht) 103 { 104 struct scsi_proc_entry *e; 105 106 lockdep_assert_held(&global_host_template_mutex); 107 108 list_for_each_entry(e, &scsi_proc_list, entry) 109 if (e->sht == sht) 110 return e; 111 112 return NULL; 113 } 114 115 static struct scsi_proc_entry * 116 scsi_lookup_proc_entry(const struct scsi_host_template *sht) 117 { 118 struct scsi_proc_entry *e; 119 120 mutex_lock(&global_host_template_mutex); 121 e = __scsi_lookup_proc_entry(sht); 122 mutex_unlock(&global_host_template_mutex); 123 124 return e; 125 } 126 127 /** 128 * scsi_template_proc_dir() - returns the procfs dir for a SCSI host template 129 * @sht: SCSI host template pointer. 130 */ 131 struct proc_dir_entry * 132 scsi_template_proc_dir(const struct scsi_host_template *sht) 133 { 134 struct scsi_proc_entry *e = scsi_lookup_proc_entry(sht); 135 136 return e ? e->proc_dir : NULL; 137 } 138 EXPORT_SYMBOL_GPL(scsi_template_proc_dir); 139 140 static const struct proc_ops proc_scsi_ops = { 141 .proc_open = proc_scsi_host_open, 142 .proc_release = single_release, 143 .proc_read = seq_read, 144 .proc_lseek = seq_lseek, 145 .proc_write = proc_scsi_host_write 146 }; 147 148 /** 149 * scsi_proc_hostdir_add - Create directory in /proc for a scsi host 150 * @sht: owner of this directory 151 * 152 * Sets sht->proc_dir to the new directory. 153 */ 154 int scsi_proc_hostdir_add(const struct scsi_host_template *sht) 155 { 156 struct scsi_proc_entry *e; 157 int ret; 158 159 if (!sht->show_info) 160 return 0; 161 162 mutex_lock(&global_host_template_mutex); 163 e = __scsi_lookup_proc_entry(sht); 164 if (!e) { 165 e = kzalloc(sizeof(*e), GFP_KERNEL); 166 if (!e) { 167 ret = -ENOMEM; 168 goto unlock; 169 } 170 } 171 if (e->present++) 172 goto success; 173 e->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); 174 if (!e->proc_dir) { 175 printk(KERN_ERR "%s: proc_mkdir failed for %s\n", __func__, 176 sht->proc_name); 177 ret = -ENOMEM; 178 goto unlock; 179 } 180 e->sht = sht; 181 list_add_tail(&e->entry, &scsi_proc_list); 182 success: 183 e = NULL; 184 ret = 0; 185 unlock: 186 mutex_unlock(&global_host_template_mutex); 187 188 kfree(e); 189 return ret; 190 } 191 192 /** 193 * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host 194 * @sht: owner of directory 195 */ 196 void scsi_proc_hostdir_rm(const struct scsi_host_template *sht) 197 { 198 struct scsi_proc_entry *e; 199 200 if (!sht->show_info) 201 return; 202 203 mutex_lock(&global_host_template_mutex); 204 e = __scsi_lookup_proc_entry(sht); 205 if (e && !--e->present) { 206 remove_proc_entry(sht->proc_name, proc_scsi); 207 list_del(&e->entry); 208 kfree(e); 209 } 210 mutex_unlock(&global_host_template_mutex); 211 } 212 213 214 /** 215 * scsi_proc_host_add - Add entry for this host to appropriate /proc dir 216 * @shost: host to add 217 */ 218 void scsi_proc_host_add(struct Scsi_Host *shost) 219 { 220 const struct scsi_host_template *sht = shost->hostt; 221 struct scsi_proc_entry *e; 222 struct proc_dir_entry *p; 223 char name[10]; 224 225 if (!sht->show_info) 226 return; 227 228 e = scsi_lookup_proc_entry(sht); 229 if (!e) 230 goto err; 231 232 sprintf(name,"%d", shost->host_no); 233 p = proc_create_data(name, S_IRUGO | S_IWUSR, e->proc_dir, 234 &proc_scsi_ops, shost); 235 if (!p) 236 goto err; 237 return; 238 239 err: 240 shost_printk(KERN_ERR, shost, 241 "%s: Failed to register host (%s failed)\n", __func__, 242 e ? "proc_create_data()" : "scsi_proc_hostdir_add()"); 243 } 244 245 /** 246 * scsi_proc_host_rm - remove this host's entry from /proc 247 * @shost: which host 248 */ 249 void scsi_proc_host_rm(struct Scsi_Host *shost) 250 { 251 const struct scsi_host_template *sht = shost->hostt; 252 struct scsi_proc_entry *e; 253 char name[10]; 254 255 if (!sht->show_info) 256 return; 257 258 e = scsi_lookup_proc_entry(sht); 259 if (!e) 260 return; 261 262 sprintf(name,"%d", shost->host_no); 263 remove_proc_entry(name, e->proc_dir); 264 } 265 /** 266 * proc_print_scsidevice - return data about this host 267 * @dev: A scsi device 268 * @data: &struct seq_file to output to. 269 * 270 * Description: prints Host, Channel, Id, Lun, Vendor, Model, Rev, Type, 271 * and revision. 272 */ 273 static int proc_print_scsidevice(struct device *dev, void *data) 274 { 275 struct scsi_device *sdev; 276 struct seq_file *s = data; 277 int i; 278 279 if (!scsi_is_sdev_device(dev)) 280 goto out; 281 282 sdev = to_scsi_device(dev); 283 seq_printf(s, 284 "Host: scsi%d Channel: %02d Id: %02d Lun: %02llu\n Vendor: ", 285 sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); 286 for (i = 0; i < 8; i++) { 287 if (sdev->vendor[i] >= 0x20) 288 seq_putc(s, sdev->vendor[i]); 289 else 290 seq_putc(s, ' '); 291 } 292 293 seq_puts(s, " Model: "); 294 for (i = 0; i < 16; i++) { 295 if (sdev->model[i] >= 0x20) 296 seq_putc(s, sdev->model[i]); 297 else 298 seq_putc(s, ' '); 299 } 300 301 seq_puts(s, " Rev: "); 302 for (i = 0; i < 4; i++) { 303 if (sdev->rev[i] >= 0x20) 304 seq_putc(s, sdev->rev[i]); 305 else 306 seq_putc(s, ' '); 307 } 308 309 seq_putc(s, '\n'); 310 311 seq_printf(s, " Type: %s ", scsi_device_type(sdev->type)); 312 seq_printf(s, " ANSI SCSI revision: %02x", 313 sdev->scsi_level - (sdev->scsi_level > 1)); 314 if (sdev->scsi_level == 2) 315 seq_puts(s, " CCS\n"); 316 else 317 seq_putc(s, '\n'); 318 319 out: 320 return 0; 321 } 322 323 /** 324 * scsi_add_single_device - Respond to user request to probe for/add device 325 * @host: user-supplied decimal integer 326 * @channel: user-supplied decimal integer 327 * @id: user-supplied decimal integer 328 * @lun: user-supplied decimal integer 329 * 330 * Description: called by writing "scsi add-single-device" to /proc/scsi/scsi. 331 * 332 * does scsi_host_lookup() and either user_scan() if that transport 333 * type supports it, or else scsi_scan_host_selected() 334 * 335 * Note: this seems to be aimed exclusively at SCSI parallel busses. 336 */ 337 338 static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) 339 { 340 struct Scsi_Host *shost; 341 int error = -ENXIO; 342 343 shost = scsi_host_lookup(host); 344 if (!shost) 345 return error; 346 347 if (shost->transportt->user_scan) 348 error = shost->transportt->user_scan(shost, channel, id, lun); 349 else 350 error = scsi_scan_host_selected(shost, channel, id, lun, 351 SCSI_SCAN_MANUAL); 352 scsi_host_put(shost); 353 return error; 354 } 355 356 /** 357 * scsi_remove_single_device - Respond to user request to remove a device 358 * @host: user-supplied decimal integer 359 * @channel: user-supplied decimal integer 360 * @id: user-supplied decimal integer 361 * @lun: user-supplied decimal integer 362 * 363 * Description: called by writing "scsi remove-single-device" to 364 * /proc/scsi/scsi. Does a scsi_device_lookup() and scsi_remove_device() 365 */ 366 static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) 367 { 368 struct scsi_device *sdev; 369 struct Scsi_Host *shost; 370 int error = -ENXIO; 371 372 shost = scsi_host_lookup(host); 373 if (!shost) 374 return error; 375 sdev = scsi_device_lookup(shost, channel, id, lun); 376 if (sdev) { 377 scsi_remove_device(sdev); 378 scsi_device_put(sdev); 379 error = 0; 380 } 381 382 scsi_host_put(shost); 383 return error; 384 } 385 386 /** 387 * proc_scsi_write - handle writes to /proc/scsi/scsi 388 * @file: not used 389 * @buf: buffer to write 390 * @length: length of buf, at most PAGE_SIZE 391 * @ppos: not used 392 * 393 * Description: this provides a legacy mechanism to add or remove devices by 394 * Host, Channel, ID, and Lun. To use, 395 * "echo 'scsi add-single-device 0 1 2 3' > /proc/scsi/scsi" or 396 * "echo 'scsi remove-single-device 0 1 2 3' > /proc/scsi/scsi" with 397 * "0 1 2 3" replaced by the Host, Channel, Id, and Lun. 398 * 399 * Note: this seems to be aimed at parallel SCSI. Most modern busses (USB, 400 * SATA, Firewire, Fibre Channel, etc) dynamically assign these values to 401 * provide a unique identifier and nothing more. 402 */ 403 404 405 static ssize_t proc_scsi_write(struct file *file, const char __user *buf, 406 size_t length, loff_t *ppos) 407 { 408 int host, channel, id, lun; 409 char *buffer, *p; 410 int err; 411 412 if (!buf || length > PAGE_SIZE) 413 return -EINVAL; 414 415 buffer = (char *)__get_free_page(GFP_KERNEL); 416 if (!buffer) 417 return -ENOMEM; 418 419 err = -EFAULT; 420 if (copy_from_user(buffer, buf, length)) 421 goto out; 422 423 err = -EINVAL; 424 if (length < PAGE_SIZE) 425 buffer[length] = '\0'; 426 else if (buffer[PAGE_SIZE-1]) 427 goto out; 428 429 /* 430 * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi 431 * with "0 1 2 3" replaced by your "Host Channel Id Lun". 432 */ 433 if (!strncmp("scsi add-single-device", buffer, 22)) { 434 p = buffer + 23; 435 436 host = simple_strtoul(p, &p, 0); 437 channel = simple_strtoul(p + 1, &p, 0); 438 id = simple_strtoul(p + 1, &p, 0); 439 lun = simple_strtoul(p + 1, &p, 0); 440 441 err = scsi_add_single_device(host, channel, id, lun); 442 443 /* 444 * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi 445 * with "0 1 2 3" replaced by your "Host Channel Id Lun". 446 */ 447 } else if (!strncmp("scsi remove-single-device", buffer, 25)) { 448 p = buffer + 26; 449 450 host = simple_strtoul(p, &p, 0); 451 channel = simple_strtoul(p + 1, &p, 0); 452 id = simple_strtoul(p + 1, &p, 0); 453 lun = simple_strtoul(p + 1, &p, 0); 454 455 err = scsi_remove_single_device(host, channel, id, lun); 456 } 457 458 /* 459 * convert success returns so that we return the 460 * number of bytes consumed. 461 */ 462 if (!err) 463 err = length; 464 465 out: 466 free_page((unsigned long)buffer); 467 return err; 468 } 469 470 static inline struct device *next_scsi_device(struct device *start) 471 { 472 struct device *next = bus_find_next_device(&scsi_bus_type, start); 473 474 put_device(start); 475 return next; 476 } 477 478 static void *scsi_seq_start(struct seq_file *sfile, loff_t *pos) 479 { 480 struct device *dev = NULL; 481 loff_t n = *pos; 482 483 while ((dev = next_scsi_device(dev))) { 484 if (!n--) 485 break; 486 sfile->private++; 487 } 488 return dev; 489 } 490 491 static void *scsi_seq_next(struct seq_file *sfile, void *v, loff_t *pos) 492 { 493 (*pos)++; 494 sfile->private++; 495 return next_scsi_device(v); 496 } 497 498 static void scsi_seq_stop(struct seq_file *sfile, void *v) 499 { 500 put_device(v); 501 } 502 503 static int scsi_seq_show(struct seq_file *sfile, void *dev) 504 { 505 if (!sfile->private) 506 seq_puts(sfile, "Attached devices:\n"); 507 508 return proc_print_scsidevice(dev, sfile); 509 } 510 511 static const struct seq_operations scsi_seq_ops = { 512 .start = scsi_seq_start, 513 .next = scsi_seq_next, 514 .stop = scsi_seq_stop, 515 .show = scsi_seq_show 516 }; 517 518 /** 519 * proc_scsi_open - glue function 520 * @inode: not used 521 * @file: passed to single_open() 522 * 523 * Associates proc_scsi_show with this file 524 */ 525 static int proc_scsi_open(struct inode *inode, struct file *file) 526 { 527 /* 528 * We don't really need this for the write case but it doesn't 529 * harm either. 530 */ 531 return seq_open(file, &scsi_seq_ops); 532 } 533 534 static const struct proc_ops scsi_scsi_proc_ops = { 535 .proc_open = proc_scsi_open, 536 .proc_read = seq_read, 537 .proc_write = proc_scsi_write, 538 .proc_lseek = seq_lseek, 539 .proc_release = seq_release, 540 }; 541 542 /** 543 * scsi_init_procfs - create scsi and scsi/scsi in procfs 544 */ 545 int __init scsi_init_procfs(void) 546 { 547 struct proc_dir_entry *pde; 548 549 proc_scsi = proc_mkdir("scsi", NULL); 550 if (!proc_scsi) 551 goto err1; 552 553 pde = proc_create("scsi/scsi", 0, NULL, &scsi_scsi_proc_ops); 554 if (!pde) 555 goto err2; 556 557 return 0; 558 559 err2: 560 remove_proc_entry("scsi", NULL); 561 err1: 562 return -ENOMEM; 563 } 564 565 /** 566 * scsi_exit_procfs - Remove scsi/scsi and scsi from procfs 567 */ 568 void scsi_exit_procfs(void) 569 { 570 remove_proc_entry("scsi/scsi", NULL); 571 remove_proc_entry("scsi", NULL); 572 } 573