[SCSI] implement parameter limits in the SPI transport class

There's a basic need not to have parameters go under or over certain
values when doing domain validation. The basic ones are

max_offset, max_width and min_period

This patch makes the transport class take and enforce these three
limits. Currently they can be set by the user, although they could
obviously be read from the HBA's on-board NVRAM area during
slave_configure (if it has one).

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

authored by James Bottomley and committed by James Bottomley 62a86129 88d7bd8c

+167 -27
+161 -27
drivers/scsi/scsi_transport_spi.c
··· 35 35 36 36 #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) 37 37 38 - #define SPI_NUM_ATTRS 10 /* increase this if you add attributes */ 38 + #define SPI_NUM_ATTRS 13 /* increase this if you add attributes */ 39 39 #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always 40 40 * on" attributes */ 41 41 #define SPI_HOST_ATTRS 1 ··· 219 219 struct scsi_target *starget = to_scsi_target(dev); 220 220 221 221 spi_period(starget) = -1; /* illegal value */ 222 + spi_min_period(starget) = 0; 222 223 spi_offset(starget) = 0; /* async */ 224 + spi_max_offset(starget) = 255; 223 225 spi_width(starget) = 0; /* narrow */ 226 + spi_max_width(starget) = 1; 224 227 spi_iu(starget) = 0; /* no IU */ 225 228 spi_dt(starget) = 0; /* ST */ 226 229 spi_qas(starget) = 0; ··· 236 233 init_MUTEX(&spi_dv_sem(starget)); 237 234 238 235 return 0; 236 + } 237 + 238 + #define spi_transport_show_simple(field, format_string) \ 239 + \ 240 + static ssize_t \ 241 + show_spi_transport_##field(struct class_device *cdev, char *buf) \ 242 + { \ 243 + struct scsi_target *starget = transport_class_to_starget(cdev); \ 244 + struct spi_transport_attrs *tp; \ 245 + \ 246 + tp = (struct spi_transport_attrs *)&starget->starget_data; \ 247 + return snprintf(buf, 20, format_string, tp->field); \ 248 + } 249 + 250 + #define spi_transport_store_simple(field, format_string) \ 251 + \ 252 + static ssize_t \ 253 + store_spi_transport_##field(struct class_device *cdev, const char *buf, \ 254 + size_t count) \ 255 + { \ 256 + int val; \ 257 + struct scsi_target *starget = transport_class_to_starget(cdev); \ 258 + struct spi_transport_attrs *tp; \ 259 + \ 260 + tp = (struct spi_transport_attrs *)&starget->starget_data; \ 261 + val = simple_strtoul(buf, NULL, 0); \ 262 + tp->field = val; \ 263 + return count; \ 239 264 } 240 265 241 266 #define spi_transport_show_function(field, format_string) \ ··· 292 261 struct spi_internal *i = to_spi_internal(shost->transportt); \ 293 262 \ 294 263 val = simple_strtoul(buf, NULL, 0); \ 264 + i->f->set_##field(starget, val); \ 265 + return count; \ 266 + } 267 + 268 + #define spi_transport_store_max(field, format_string) \ 269 + static ssize_t \ 270 + store_spi_transport_##field(struct class_device *cdev, const char *buf, \ 271 + size_t count) \ 272 + { \ 273 + int val; \ 274 + struct scsi_target *starget = transport_class_to_starget(cdev); \ 275 + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ 276 + struct spi_internal *i = to_spi_internal(shost->transportt); \ 277 + struct spi_transport_attrs *tp \ 278 + = (struct spi_transport_attrs *)&starget->starget_data; \ 279 + \ 280 + val = simple_strtoul(buf, NULL, 0); \ 281 + if (val > tp->max_##field) \ 282 + val = tp->max_##field; \ 295 283 i->f->set_##field(starget, val); \ 296 284 return count; \ 297 285 } ··· 322 272 show_spi_transport_##field, \ 323 273 store_spi_transport_##field); 324 274 275 + #define spi_transport_simple_attr(field, format_string) \ 276 + spi_transport_show_simple(field, format_string) \ 277 + spi_transport_store_simple(field, format_string) \ 278 + static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ 279 + show_spi_transport_##field, \ 280 + store_spi_transport_##field); 281 + 282 + #define spi_transport_max_attr(field, format_string) \ 283 + spi_transport_show_function(field, format_string) \ 284 + spi_transport_store_max(field, format_string) \ 285 + spi_transport_simple_attr(max_##field, format_string) \ 286 + static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ 287 + show_spi_transport_##field, \ 288 + store_spi_transport_##field); 289 + 325 290 /* The Parallel SCSI Tranport Attributes: */ 326 - spi_transport_rd_attr(offset, "%d\n"); 327 - spi_transport_rd_attr(width, "%d\n"); 291 + spi_transport_max_attr(offset, "%d\n"); 292 + spi_transport_max_attr(width, "%d\n"); 328 293 spi_transport_rd_attr(iu, "%d\n"); 329 294 spi_transport_rd_attr(dt, "%d\n"); 330 295 spi_transport_rd_attr(qas, "%d\n"); ··· 365 300 366 301 /* Translate the period into ns according to the current spec 367 302 * for SDTR/PPR messages */ 368 - static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf) 369 - 303 + static ssize_t 304 + show_spi_transport_period_helper(struct class_device *cdev, char *buf, 305 + int period) 370 306 { 371 - struct scsi_target *starget = transport_class_to_starget(cdev); 372 - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 373 - struct spi_transport_attrs *tp; 374 307 int len, picosec; 375 - struct spi_internal *i = to_spi_internal(shost->transportt); 376 308 377 - tp = (struct spi_transport_attrs *)&starget->starget_data; 378 - 379 - if (i->f->get_period) 380 - i->f->get_period(starget); 381 - 382 - if (tp->period < 0 || tp->period > 0xff) { 309 + if (period < 0 || period > 0xff) { 383 310 picosec = -1; 384 - } else if (tp->period <= SPI_STATIC_PPR) { 385 - picosec = ppr_to_ps[tp->period]; 311 + } else if (period <= SPI_STATIC_PPR) { 312 + picosec = ppr_to_ps[period]; 386 313 } else { 387 - picosec = tp->period * 4000; 314 + picosec = period * 4000; 388 315 } 389 316 390 317 if (picosec == -1) { ··· 391 334 } 392 335 393 336 static ssize_t 394 - store_spi_transport_period(struct class_device *cdev, const char *buf, 395 - size_t count) 337 + store_spi_transport_period_helper(struct class_device *cdev, const char *buf, 338 + size_t count, int *periodp) 396 339 { 397 - struct scsi_target *starget = transport_class_to_starget(cdev); 398 - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 399 - struct spi_internal *i = to_spi_internal(shost->transportt); 400 340 int j, picosec, period = -1; 401 341 char *endp; 402 342 ··· 422 368 if (period > 0xff) 423 369 period = 0xff; 424 370 425 - i->f->set_period(starget, period); 371 + *periodp = period; 426 372 427 373 return count; 374 + } 375 + 376 + static ssize_t 377 + show_spi_transport_period(struct class_device *cdev, char *buf) 378 + { 379 + struct scsi_target *starget = transport_class_to_starget(cdev); 380 + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 381 + struct spi_internal *i = to_spi_internal(shost->transportt); 382 + struct spi_transport_attrs *tp = 383 + (struct spi_transport_attrs *)&starget->starget_data; 384 + 385 + if (i->f->get_period) 386 + i->f->get_period(starget); 387 + 388 + return show_spi_transport_period_helper(cdev, buf, tp->period); 389 + } 390 + 391 + static ssize_t 392 + store_spi_transport_period(struct class_device *cdev, const char *buf, 393 + size_t count) 394 + { 395 + struct scsi_target *starget = transport_class_to_starget(cdev); 396 + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 397 + struct spi_internal *i = to_spi_internal(shost->transportt); 398 + struct spi_transport_attrs *tp = 399 + (struct spi_transport_attrs *)&starget->starget_data; 400 + int period, retval; 401 + 402 + retval = store_spi_transport_period_helper(cdev, buf, count, &period); 403 + 404 + if (period < tp->min_period) 405 + period = tp->min_period; 406 + 407 + i->f->set_period(starget, period); 408 + 409 + return retval; 428 410 } 429 411 430 412 static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 431 413 show_spi_transport_period, 432 414 store_spi_transport_period); 415 + 416 + static ssize_t 417 + show_spi_transport_min_period(struct class_device *cdev, char *buf) 418 + { 419 + struct scsi_target *starget = transport_class_to_starget(cdev); 420 + struct spi_transport_attrs *tp = 421 + (struct spi_transport_attrs *)&starget->starget_data; 422 + 423 + return show_spi_transport_period_helper(cdev, buf, tp->min_period); 424 + } 425 + 426 + static ssize_t 427 + store_spi_transport_min_period(struct class_device *cdev, const char *buf, 428 + size_t count) 429 + { 430 + struct scsi_target *starget = transport_class_to_starget(cdev); 431 + struct spi_transport_attrs *tp = 432 + (struct spi_transport_attrs *)&starget->starget_data; 433 + 434 + return store_spi_transport_period_helper(cdev, buf, count, 435 + &tp->min_period); 436 + } 437 + 438 + 439 + static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, 440 + show_spi_transport_min_period, 441 + store_spi_transport_min_period); 442 + 433 443 434 444 static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf) 435 445 { ··· 760 642 { 761 643 struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); 762 644 struct scsi_device *sdev = sreq->sr_device; 645 + struct scsi_target *starget = sdev->sdev_target; 763 646 int len = sdev->inquiry_len; 764 647 /* first set us up for narrow async */ 765 648 DV_SET(offset, 0); ··· 774 655 } 775 656 776 657 /* test width */ 777 - if (i->f->set_width && sdev->wdtr) { 658 + if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) { 778 659 i->f->set_width(sdev->sdev_target, 1); 660 + 661 + printk("WIDTH IS %d\n", spi_max_width(starget)); 779 662 780 663 if (spi_dv_device_compare_inquiry(sreq, buffer, 781 664 buffer + len, ··· 805 684 retry: 806 685 807 686 /* now set up to the maximum */ 808 - DV_SET(offset, 255); 809 - DV_SET(period, 1); 687 + DV_SET(offset, spi_max_offset(starget)); 688 + DV_SET(period, spi_min_period(starget)); 810 689 811 690 if (len == 0) { 812 691 SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n"); ··· 1013 892 if (i->f->show_##field) \ 1014 893 count++ 1015 894 895 + #define SETUP_RELATED_ATTRIBUTE(field, rel_field) \ 896 + i->private_attrs[count] = class_device_attr_##field; \ 897 + if (!i->f->set_##rel_field) { \ 898 + i->private_attrs[count].attr.mode = S_IRUGO; \ 899 + i->private_attrs[count].store = NULL; \ 900 + } \ 901 + i->attrs[count] = &i->private_attrs[count]; \ 902 + if (i->f->show_##rel_field) \ 903 + count++ 904 + 1016 905 #define SETUP_HOST_ATTRIBUTE(field) \ 1017 906 i->private_host_attrs[count] = class_device_attr_##field; \ 1018 907 if (!i->f->set_##field) { \ ··· 1106 975 i->f = ft; 1107 976 1108 977 SETUP_ATTRIBUTE(period); 978 + SETUP_RELATED_ATTRIBUTE(min_period, period); 1109 979 SETUP_ATTRIBUTE(offset); 980 + SETUP_RELATED_ATTRIBUTE(max_offset, offset); 1110 981 SETUP_ATTRIBUTE(width); 982 + SETUP_RELATED_ATTRIBUTE(max_width, width); 1111 983 SETUP_ATTRIBUTE(iu); 1112 984 SETUP_ATTRIBUTE(dt); 1113 985 SETUP_ATTRIBUTE(qas);
+6
include/scsi/scsi_transport_spi.h
··· 27 27 28 28 struct spi_transport_attrs { 29 29 int period; /* value in the PPR/SDTR command */ 30 + int min_period; 30 31 int offset; 32 + int max_offset; 31 33 unsigned int width:1; /* 0 - narrow, 1 - wide */ 34 + unsigned int max_width:1; 32 35 unsigned int iu:1; /* Information Units enabled */ 33 36 unsigned int dt:1; /* DT clocking enabled */ 34 37 unsigned int qas:1; /* Quick Arbitration and Selection enabled */ ··· 66 63 67 64 /* accessor functions */ 68 65 #define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period) 66 + #define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period) 69 67 #define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset) 68 + #define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset) 70 69 #define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width) 70 + #define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width) 71 71 #define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu) 72 72 #define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt) 73 73 #define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas)