0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <linux/module.h>
0021 #include <linux/init.h>
0022 #include <linux/string.h>
0023 #include <linux/mm.h>
0024 #include <linux/proc_fs.h>
0025 #include <linux/errno.h>
0026 #include <linux/blkdev.h>
0027 #include <linux/seq_file.h>
0028 #include <linux/mutex.h>
0029 #include <linux/gfp.h>
0030 #include <linux/uaccess.h>
0031
0032 #include <scsi/scsi.h>
0033 #include <scsi/scsi_device.h>
0034 #include <scsi/scsi_host.h>
0035 #include <scsi/scsi_transport.h>
0036
0037 #include "scsi_priv.h"
0038 #include "scsi_logging.h"
0039
0040
0041
0042 #define PROC_BLOCK_SIZE (3*1024)
0043
0044 static struct proc_dir_entry *proc_scsi;
0045
0046
0047 static DEFINE_MUTEX(global_host_template_mutex);
0048
0049 static ssize_t proc_scsi_host_write(struct file *file, const char __user *buf,
0050 size_t count, loff_t *ppos)
0051 {
0052 struct Scsi_Host *shost = pde_data(file_inode(file));
0053 ssize_t ret = -ENOMEM;
0054 char *page;
0055
0056 if (count > PROC_BLOCK_SIZE)
0057 return -EOVERFLOW;
0058
0059 if (!shost->hostt->write_info)
0060 return -EINVAL;
0061
0062 page = (char *)__get_free_page(GFP_KERNEL);
0063 if (page) {
0064 ret = -EFAULT;
0065 if (copy_from_user(page, buf, count))
0066 goto out;
0067 ret = shost->hostt->write_info(shost, page, count);
0068 }
0069 out:
0070 free_page((unsigned long)page);
0071 return ret;
0072 }
0073
0074 static int proc_scsi_show(struct seq_file *m, void *v)
0075 {
0076 struct Scsi_Host *shost = m->private;
0077 return shost->hostt->show_info(m, shost);
0078 }
0079
0080 static int proc_scsi_host_open(struct inode *inode, struct file *file)
0081 {
0082 return single_open_size(file, proc_scsi_show, pde_data(inode),
0083 4 * PAGE_SIZE);
0084 }
0085
0086 static const struct proc_ops proc_scsi_ops = {
0087 .proc_open = proc_scsi_host_open,
0088 .proc_release = single_release,
0089 .proc_read = seq_read,
0090 .proc_lseek = seq_lseek,
0091 .proc_write = proc_scsi_host_write
0092 };
0093
0094
0095
0096
0097
0098
0099
0100
0101 void scsi_proc_hostdir_add(struct scsi_host_template *sht)
0102 {
0103 if (!sht->show_info)
0104 return;
0105
0106 mutex_lock(&global_host_template_mutex);
0107 if (!sht->present++) {
0108 sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
0109 if (!sht->proc_dir)
0110 printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
0111 __func__, sht->proc_name);
0112 }
0113 mutex_unlock(&global_host_template_mutex);
0114 }
0115
0116
0117
0118
0119
0120 void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
0121 {
0122 if (!sht->show_info)
0123 return;
0124
0125 mutex_lock(&global_host_template_mutex);
0126 if (!--sht->present && sht->proc_dir) {
0127 remove_proc_entry(sht->proc_name, proc_scsi);
0128 sht->proc_dir = NULL;
0129 }
0130 mutex_unlock(&global_host_template_mutex);
0131 }
0132
0133
0134
0135
0136
0137
0138 void scsi_proc_host_add(struct Scsi_Host *shost)
0139 {
0140 struct scsi_host_template *sht = shost->hostt;
0141 struct proc_dir_entry *p;
0142 char name[10];
0143
0144 if (!sht->proc_dir)
0145 return;
0146
0147 sprintf(name,"%d", shost->host_no);
0148 p = proc_create_data(name, S_IRUGO | S_IWUSR,
0149 sht->proc_dir, &proc_scsi_ops, shost);
0150 if (!p)
0151 printk(KERN_ERR "%s: Failed to register host %d in"
0152 "%s\n", __func__, shost->host_no,
0153 sht->proc_name);
0154 }
0155
0156
0157
0158
0159
0160 void scsi_proc_host_rm(struct Scsi_Host *shost)
0161 {
0162 char name[10];
0163
0164 if (!shost->hostt->proc_dir)
0165 return;
0166
0167 sprintf(name,"%d", shost->host_no);
0168 remove_proc_entry(name, shost->hostt->proc_dir);
0169 }
0170
0171
0172
0173
0174
0175
0176
0177
0178 static int proc_print_scsidevice(struct device *dev, void *data)
0179 {
0180 struct scsi_device *sdev;
0181 struct seq_file *s = data;
0182 int i;
0183
0184 if (!scsi_is_sdev_device(dev))
0185 goto out;
0186
0187 sdev = to_scsi_device(dev);
0188 seq_printf(s,
0189 "Host: scsi%d Channel: %02d Id: %02d Lun: %02llu\n Vendor: ",
0190 sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
0191 for (i = 0; i < 8; i++) {
0192 if (sdev->vendor[i] >= 0x20)
0193 seq_putc(s, sdev->vendor[i]);
0194 else
0195 seq_putc(s, ' ');
0196 }
0197
0198 seq_puts(s, " Model: ");
0199 for (i = 0; i < 16; i++) {
0200 if (sdev->model[i] >= 0x20)
0201 seq_putc(s, sdev->model[i]);
0202 else
0203 seq_putc(s, ' ');
0204 }
0205
0206 seq_puts(s, " Rev: ");
0207 for (i = 0; i < 4; i++) {
0208 if (sdev->rev[i] >= 0x20)
0209 seq_putc(s, sdev->rev[i]);
0210 else
0211 seq_putc(s, ' ');
0212 }
0213
0214 seq_putc(s, '\n');
0215
0216 seq_printf(s, " Type: %s ", scsi_device_type(sdev->type));
0217 seq_printf(s, " ANSI SCSI revision: %02x",
0218 sdev->scsi_level - (sdev->scsi_level > 1));
0219 if (sdev->scsi_level == 2)
0220 seq_puts(s, " CCS\n");
0221 else
0222 seq_putc(s, '\n');
0223
0224 out:
0225 return 0;
0226 }
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
0244 {
0245 struct Scsi_Host *shost;
0246 int error = -ENXIO;
0247
0248 shost = scsi_host_lookup(host);
0249 if (!shost)
0250 return error;
0251
0252 if (shost->transportt->user_scan)
0253 error = shost->transportt->user_scan(shost, channel, id, lun);
0254 else
0255 error = scsi_scan_host_selected(shost, channel, id, lun,
0256 SCSI_SCAN_MANUAL);
0257 scsi_host_put(shost);
0258 return error;
0259 }
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271 static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
0272 {
0273 struct scsi_device *sdev;
0274 struct Scsi_Host *shost;
0275 int error = -ENXIO;
0276
0277 shost = scsi_host_lookup(host);
0278 if (!shost)
0279 return error;
0280 sdev = scsi_device_lookup(shost, channel, id, lun);
0281 if (sdev) {
0282 scsi_remove_device(sdev);
0283 scsi_device_put(sdev);
0284 error = 0;
0285 }
0286
0287 scsi_host_put(shost);
0288 return error;
0289 }
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310 static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
0311 size_t length, loff_t *ppos)
0312 {
0313 int host, channel, id, lun;
0314 char *buffer, *p;
0315 int err;
0316
0317 if (!buf || length > PAGE_SIZE)
0318 return -EINVAL;
0319
0320 buffer = (char *)__get_free_page(GFP_KERNEL);
0321 if (!buffer)
0322 return -ENOMEM;
0323
0324 err = -EFAULT;
0325 if (copy_from_user(buffer, buf, length))
0326 goto out;
0327
0328 err = -EINVAL;
0329 if (length < PAGE_SIZE)
0330 buffer[length] = '\0';
0331 else if (buffer[PAGE_SIZE-1])
0332 goto out;
0333
0334
0335
0336
0337
0338 if (!strncmp("scsi add-single-device", buffer, 22)) {
0339 p = buffer + 23;
0340
0341 host = simple_strtoul(p, &p, 0);
0342 channel = simple_strtoul(p + 1, &p, 0);
0343 id = simple_strtoul(p + 1, &p, 0);
0344 lun = simple_strtoul(p + 1, &p, 0);
0345
0346 err = scsi_add_single_device(host, channel, id, lun);
0347
0348
0349
0350
0351
0352 } else if (!strncmp("scsi remove-single-device", buffer, 25)) {
0353 p = buffer + 26;
0354
0355 host = simple_strtoul(p, &p, 0);
0356 channel = simple_strtoul(p + 1, &p, 0);
0357 id = simple_strtoul(p + 1, &p, 0);
0358 lun = simple_strtoul(p + 1, &p, 0);
0359
0360 err = scsi_remove_single_device(host, channel, id, lun);
0361 }
0362
0363
0364
0365
0366
0367 if (!err)
0368 err = length;
0369
0370 out:
0371 free_page((unsigned long)buffer);
0372 return err;
0373 }
0374
0375 static inline struct device *next_scsi_device(struct device *start)
0376 {
0377 struct device *next = bus_find_next_device(&scsi_bus_type, start);
0378
0379 put_device(start);
0380 return next;
0381 }
0382
0383 static void *scsi_seq_start(struct seq_file *sfile, loff_t *pos)
0384 {
0385 struct device *dev = NULL;
0386 loff_t n = *pos;
0387
0388 while ((dev = next_scsi_device(dev))) {
0389 if (!n--)
0390 break;
0391 sfile->private++;
0392 }
0393 return dev;
0394 }
0395
0396 static void *scsi_seq_next(struct seq_file *sfile, void *v, loff_t *pos)
0397 {
0398 (*pos)++;
0399 sfile->private++;
0400 return next_scsi_device(v);
0401 }
0402
0403 static void scsi_seq_stop(struct seq_file *sfile, void *v)
0404 {
0405 put_device(v);
0406 }
0407
0408 static int scsi_seq_show(struct seq_file *sfile, void *dev)
0409 {
0410 if (!sfile->private)
0411 seq_puts(sfile, "Attached devices:\n");
0412
0413 return proc_print_scsidevice(dev, sfile);
0414 }
0415
0416 static const struct seq_operations scsi_seq_ops = {
0417 .start = scsi_seq_start,
0418 .next = scsi_seq_next,
0419 .stop = scsi_seq_stop,
0420 .show = scsi_seq_show
0421 };
0422
0423
0424
0425
0426
0427
0428
0429
0430 static int proc_scsi_open(struct inode *inode, struct file *file)
0431 {
0432
0433
0434
0435
0436 return seq_open(file, &scsi_seq_ops);
0437 }
0438
0439 static const struct proc_ops scsi_scsi_proc_ops = {
0440 .proc_open = proc_scsi_open,
0441 .proc_read = seq_read,
0442 .proc_write = proc_scsi_write,
0443 .proc_lseek = seq_lseek,
0444 .proc_release = seq_release,
0445 };
0446
0447
0448
0449
0450 int __init scsi_init_procfs(void)
0451 {
0452 struct proc_dir_entry *pde;
0453
0454 proc_scsi = proc_mkdir("scsi", NULL);
0455 if (!proc_scsi)
0456 goto err1;
0457
0458 pde = proc_create("scsi/scsi", 0, NULL, &scsi_scsi_proc_ops);
0459 if (!pde)
0460 goto err2;
0461
0462 return 0;
0463
0464 err2:
0465 remove_proc_entry("scsi", NULL);
0466 err1:
0467 return -ENOMEM;
0468 }
0469
0470
0471
0472
0473 void scsi_exit_procfs(void)
0474 {
0475 remove_proc_entry("scsi/scsi", NULL);
0476 remove_proc_entry("scsi", NULL);
0477 }