bk://linux-scsi.bkbits.net/scsi-rc-fixes-2.6 jejb@mulgrave.(none)|ChangeSet|20050123152601|59354 jejb # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/01/23 22:27:17-08:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-rc-fixes-2.6 # into bix.(none):/usr/src/bk-scsi-rc-fixes # # drivers/scsi/sr.c # 2005/01/23 22:27:12-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/sg.c # 2005/01/23 22:27:12-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/sd.c # 2005/01/23 22:27:12-08:00 akpm@bix.(none) +0 -1 # Auto merged # # drivers/scsi/scsi_debug.c # 2005/01/23 22:27:12-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/dpt_i2o.c # 2005/01/23 22:27:12-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/Kconfig # 2005/01/23 22:27:12-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/23 09:26:01-06:00 jejb@mulgrave.(none) # sd descriptor sense support # # From: Douglas Gilbert # # - make all sd driver sense data handling able to use # both fixed and descriptor format # - permit 64 bit lbas associated with medium (or # hardware) errors to be conveyed back to the block # layer # # Signed-off-by: James Bottomley # # drivers/scsi/sd.c # 2005/01/23 09:25:07-06:00 jejb@mulgrave.(none) +69 -43 # sd descriptor sense support # # ChangeSet # 2005/01/23 09:20:23-06:00 bunk@stusta.de # [PATCH] SCSI NCR_Q720.c: make some code static # # This patch makes two needlessly global structs static. # # Signed-off-by: Adrian Bunk # Signed-off-by: James Bottomley # # drivers/scsi/NCR_Q720.c # 2004/11/13 09:34:32-06:00 bunk@stusta.de +2 -2 # SCSI NCR_Q720.c: make some code static # # ChangeSet # 2005/01/23 09:12:43-06:00 markh@osdl.org # [PATCH] aacraid 2.6: add scsi synchronize cache support. # # This is an update from the Adaptec driver that adds support for the scsi # synchronize cache command. It essentially blocks further commands until # data has been flushed to the disks. # # Signed-off-by: Mark Haverkamp # Signed-off-by: James Bottomley # # drivers/scsi/aacraid/aacraid.h # 2005/01/19 12:48:23-06:00 markh@osdl.org +24 -0 # aacraid 2.6: add scsi synchronize cache support. # # drivers/scsi/aacraid/aachba.c # 2005/01/20 10:51:37-06:00 markh@osdl.org +113 -0 # aacraid 2.6: add scsi synchronize cache support. # # ChangeSet # 2005/01/23 08:51:23-06:00 jejb@mulgrave.(none) # SCSI: Fix style nitpicks # # Noticed by: Christoph Hellwig # # Signed-off-by: James Bottomley # # drivers/scsi/sd.c # 2005/01/23 08:49:12-06:00 jejb@mulgrave.(none) +1 -1 # SCSI: Fix style nitpicks # # drivers/scsi/scsi_lib.c # 2005/01/23 08:49:11-06:00 jejb@mulgrave.(none) +1 -1 # SCSI: Fix style nitpicks # # ChangeSet # 2005/01/23 08:41:37-06:00 dougg@torque.net # [PATCH] streamline block SG_IO error processing in sd # # - sd_init_command(): use retry count of 1 for block # SG_IO; minor cleanup # - sd_rw_init(): bypass sd level error processing for # block SG_IO # # Signed-off-by: Douglas Gilbert # Signed-off-by: James Bottomley # # drivers/scsi/sd.c # 2005/01/14 03:50:15-06:00 dougg@torque.net +31 -24 # streamline block SG_IO error processing # # ChangeSet # 2005/01/23 08:36:14-06:00 dougg@torque.net # [PATCH] streamline block SG_IO error processing # # - cleanup scsi_end_request() documentation # - shorten path for block SG_IO through scsi_io_completion() # - for non-SG_IO sense processing in scsi_io_completion(): # - ignore deferred errors (report + retry should suffice) # - consolidate into a cleaner switch statement # # Signed-off-by: Douglas Gilbert # Signed-off-by: James Bottomley # # drivers/scsi/scsi_lib.c # 2005/01/14 19:34:03-06:00 dougg@torque.net +54 -54 # streamline block SG_IO error processing # # ChangeSet # 2005/01/21 16:19:30-08:00 hch@lst.de # [PATCH] cosmetic jazz_esp updates # # small changes from Linux/MIPS CVS and typedef removal from me # # Signed-off-by: James Bottomley # # drivers/scsi/jazz_esp.c # 2005/01/19 03:33:09-08:00 hch@lst.de +25 -24 # cosmetic jazz_esp updates # # ChangeSet # 2005/01/21 16:12:34-08:00 hch@lst.de # [PATCH] update dec_esp with changes from mips CVS # # Changes are from Maciej W. Rozycki and not nicely splitup because it's # the changes to make it work with 2.6 again. Cosmetic changes by me # to avoid obsolete typedefs. # # Signed-off-by: James Bottomley # # drivers/scsi/dec_esp.c # 2005/01/16 02:49:14-08:00 hch@lst.de +205 -191 # update dec_esp with changes from mips CVS # # ChangeSet # 2005/01/21 16:07:11-08:00 hch@lst.de # [PATCH] update mips driver Kconfig bits # # Signed-off-by: James Bottomley # # drivers/scsi/Kconfig # 2005/01/16 02:44:56-08:00 hch@lst.de +2 -2 # update mips driver Kconfig bits # # ChangeSet # 2005/01/19 10:54:12-08:00 ak@muc.de # [PATCH] Add compat_ioctl to scsi host structure # # Add compat_ioctl vector to scsi_host. # # Signed-off-by: Andi Kleen # Signed-off-by: James Bottomley # # include/scsi/scsi_host.h # 2005/01/19 08:01:21-08:00 ak@muc.de +12 -1 # Add compat_ioctl to scsi host structure # # ChangeSet # 2005/01/19 10:34:55-08:00 dougg@torque.net # [PATCH] sense data helpers lk 2.6.11-rc1-bk1 # # - add sense data helper functions: # - scsi_sense_desc_find() to find a given # sense descriptor (e.g. type 0 -> information) # - scsi_get_sense_info_fld() to get the information # field from fixed or descriptor sense data # # Kai Makisara proposed the "find" function. For # example, it will help the st driver find the Filemark, # EOM and ILI flags which have been placed in the # "stream commands" sense data descriptor. # # Signed-off-by: Douglas Gilbert # Signed-off-by: James Bottomley # # include/scsi/scsi_eh.h # 2005/01/17 22:49:08-08:00 dougg@torque.net +6 -0 # sense data helpers lk 2.6.11-rc1-bk1 # # drivers/scsi/scsi_error.c # 2005/01/17 22:54:45-08:00 dougg@torque.net +93 -0 # sense data helpers lk 2.6.11-rc1-bk1 # # ChangeSet # 2005/01/19 09:06:54-08:00 geert@linux-m68k.org # [PATCH] SCSI NCR53C9x.c: some cleanups # # - Make esp_bootup_reset() global again, since the Amiga Oktagon SCSI driver # needs it, and move its prototype from oktagon_esp.c to NCR53C9x.h # - Make esp_cmd() static in the debug case. It's already a local macro in the # non-debug case. # # Signed-off-by: Geert Uytterhoeven # Signed-off-by: James Bottomley # # drivers/scsi/oktagon_esp.c # 2005/01/17 05:28:33-08:00 geert@linux-m68k.org +0 -2 # SCSI NCR53C9x.c: some cleanups # # drivers/scsi/NCR53C9x.h # 2005/01/17 05:30:46-08:00 geert@linux-m68k.org +1 -1 # SCSI NCR53C9x.c: some cleanups # # drivers/scsi/NCR53C9x.c # 2005/01/17 11:29:36-08:00 geert@linux-m68k.org +2 -2 # SCSI NCR53C9x.c: some cleanups # # ChangeSet # 2005/01/19 09:01:56-08:00 dougg@torque.net # [PATCH] sg descriptor sense cleanup lk 2.6.11-rc1-bk1 # # - expand sense data handling to descriptor format # - make module parameters visible in # /sys/modules/sg/parameters # - add "readable" SCSI commands: READ(16), REPORT LUNS, # SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG # and MAINTENANCE_IN_CMD to list # # Signed-off-by: Douglas Gilbert # Signed-off-by: James Bottomley # # drivers/scsi/sg.c # 2005/01/17 00:11:42-08:00 dougg@torque.net +19 -11 # sg descriptor sense cleanup lk 2.6.11-rc1-bk1 # # ChangeSet # 2005/01/18 11:16:13-08:00 jejb@mulgrave.(none) # move the SCSI transport classes over to the generic transport class # # This converts the three transport classes (SPI, FC and iSCSI) over to # the generic transport class code. # # It also converts the internals of the SCSI mid-layer to use generic # transport class trigger points and pulls out some of the duplicated code. # # Signed-off-by: James Bottomley # # include/scsi/scsi_transport_spi.h # 2005/01/18 11:15:07-08:00 jejb@mulgrave.(none) +1 -0 # move the SCSI transport classes over to the generic transport class # # include/scsi/scsi_transport.h # 2005/01/18 11:15:07-08:00 jejb@mulgrave.(none) +11 -22 # move the SCSI transport classes over to the generic transport class # # include/scsi/scsi_host.h # 2005/01/18 11:15:07-08:00 jejb@mulgrave.(none) +3 -3 # move the SCSI transport classes over to the generic transport class # # include/scsi/scsi_device.h # 2005/01/18 11:15:07-08:00 jejb@mulgrave.(none) +4 -5 # move the SCSI transport classes over to the generic transport class # # drivers/scsi/scsi_transport_spi.c # 2005/01/18 11:15:07-08:00 jejb@mulgrave.(none) +92 -47 # move the SCSI transport classes over to the generic transport class # # drivers/scsi/scsi_transport_iscsi.c # 2005/01/18 11:15:07-08:00 jejb@mulgrave.(none) +53 -32 # move the SCSI transport classes over to the generic transport class # # drivers/scsi/scsi_transport_fc.c # 2005/01/18 11:15:07-08:00 jejb@mulgrave.(none) +67 -45 # move the SCSI transport classes over to the generic transport class # # drivers/scsi/scsi_sysfs.c # 2005/01/18 11:15:07-08:00 jejb@mulgrave.(none) +25 -106 # move the SCSI transport classes over to the generic transport class # # drivers/scsi/scsi_scan.c # 2005/01/18 11:15:06-08:00 jejb@mulgrave.(none) +6 -18 # move the SCSI transport classes over to the generic transport class # # drivers/scsi/scsi_priv.h # 2005/01/18 11:15:06-08:00 jejb@mulgrave.(none) +1 -1 # move the SCSI transport classes over to the generic transport class # # drivers/scsi/hosts.c # 2005/01/18 11:15:06-08:00 jejb@mulgrave.(none) +8 -13 # move the SCSI transport classes over to the generic transport class # # ChangeSet # 2005/01/18 11:04:34-08:00 jejb@mulgrave.(none) # add a generic device transport class # # Transport classes are a mechanism for providing transport specific # services to drivers that the more generic command processing layers # don't care about. A good example is the SCSI mid-layer not caring about # parallel transfer characteristics or providing services for domain # validation. Transport classes usually provide a transport specific API # at one end and a class interface at the other (for the user to # interrogate and set parameters). # # Originally, transport classes were SCSI specific. However, this code is # generic to the device model. As long as you have a generic device # representing a storage interface (or device) then you can attach a # transport class to it. The new code also allows an arbitrary number of # transport classes to be attached to a device, unlike SCSI which only # allowed one. This is going to be important for things like SATA and SAS # which share the PHY layer (and hence should be capable of sharing a PHY # transport class). # # The generic transport class is designed to operate identically to the # current SCSI transport classes, except that it uses generic devices # rather than SCSI devices. # # We have five events: # # setup # add # ----- # configure # ----- # remove # destroy # # With callbacks for setup configure and remove. # # There's also an anonymous transport class which can only respond to # configure events (and which has no attributes). # # Signed-off-by: Greg Kroah-Hartman # Signed-off-by: James Bottomley # # include/linux/transport_class.h # 2005/01/18 11:03:33-08:00 jejb@mulgrave.(none) +77 -0 # # include/linux/transport_class.h # 2005/01/18 11:03:33-08:00 jejb@mulgrave.(none) +0 -0 # BitKeeper file /home/jejb/BK/scsi-rc-fixes-2.6/include/linux/transport_class.h # # drivers/base/transport_class.c # 2005/01/18 11:03:32-08:00 jejb@mulgrave.(none) +272 -0 # # drivers/base/transport_class.c # 2005/01/18 11:03:32-08:00 jejb@mulgrave.(none) +0 -0 # BitKeeper file /home/jejb/BK/scsi-rc-fixes-2.6/drivers/base/transport_class.c # # drivers/base/Makefile # 2005/01/18 11:03:32-08:00 jejb@mulgrave.(none) +1 -1 # add a generic device transport class # # ChangeSet # 2005/01/18 10:55:19-08:00 jejb@mulgrave.(none) # Add attribute container to generic device model # # Attribute containers allows a single device to belong to an arbitrary # number of classes, each with an arbitrary number of attributes. # # This will be used as the basis for a generic transport class # # Signed-off-by: Greg Kroah-Hartman # Signed-off-by: James Bottomley # # include/linux/attribute_container.h # 2005/01/18 10:54:22-08:00 jejb@mulgrave.(none) +61 -0 # # include/linux/attribute_container.h # 2005/01/18 10:54:22-08:00 jejb@mulgrave.(none) +0 -0 # BitKeeper file /home/jejb/BK/scsi-rc-fixes-2.6/include/linux/attribute_container.h # # drivers/base/attribute_container.c # 2005/01/18 10:54:21-08:00 jejb@mulgrave.(none) +274 -0 # # drivers/base/init.c # 2005/01/18 10:54:21-08:00 jejb@mulgrave.(none) +2 -1 # Add attribute container to generic device model # # drivers/base/attribute_container.c # 2005/01/18 10:54:21-08:00 jejb@mulgrave.(none) +0 -0 # BitKeeper file /home/jejb/BK/scsi-rc-fixes-2.6/drivers/base/attribute_container.c # # drivers/base/Makefile # 2005/01/18 10:54:20-08:00 jejb@mulgrave.(none) +2 -1 # Add attribute container to generic device model # # ChangeSet # 2005/01/17 12:08:43-06:00 jejb@mulgrave.(none) # fix use after potential free in scsi_cd_put # # kref_put could free the cd structure. We need a copy # of cd->device to do a scsi_device_put after the # kref_put. # # Signed-off-by: James Bottomley # # drivers/scsi/sr.c # 2005/01/17 12:08:00-06:00 jejb@mulgrave.(none) +3 -1 # fix use after potential free in scsi_cd_put # # ChangeSet # 2005/01/17 12:03:49-06:00 stern@rowland.harvard.edu # [PATCH] Fix reference to deallocated memory in sd.c # # This patch: # # http://linux-scsi.bkbits.net:8080/scsi-for-linus-2.6/cset@1.2034.95.5?nav=index.html|src/|src/drivers|src/drivers/scsi|related/drivers/scsi/sd.c # # is causing almost as much trouble as it fixed. If kref_put() drops the # last reference to the scsi_disk (this happens when the device file is # closed after the device has been hot-unplugged) then the call to # scsi_device_put() will take its argument from an area of memory that has # been deallocated. # # Signed-off-by: Alan Stern # Signed-off-by: James Bottomley # # drivers/scsi/sd.c # 2005/01/14 10:01:14-06:00 stern@rowland.harvard.edu +3 -1 # Fix reference to deallocated memory in sd.c # # ChangeSet # 2005/01/17 11:58:23-06:00 dougg@torque.net # [PATCH] scsi_debug dsense # # The dsense switch in the scsi_debug driver selects # whether fixed (default) or descriptor format sense # data is returned when an error/warning occurs. Due # to an oversight dsense was not sysfs visible. # # Signed-off-by: Douglas Gilbert # Signed-off-by: James Bottomley # # drivers/scsi/scsi_debug.c # 2005/01/12 22:34:43-06:00 dougg@torque.net +4 -2 # scsi_debug dsense # # ChangeSet # 2005/01/17 11:52:26-06:00 mark_salyzyn@adaptec.com # [PATCH] dpt_i2o: remove schedule_timeout() # # There was a patch to *remove* that line completely issued about a month # ago. It is a case of a second schedule_timeout left over from an editing # mistake made long ago in a distant galaxy. # # Signed-off-by: James Bottomley # # drivers/scsi/dpt_i2o.c # 2005/01/10 12:00:12-06:00 mark_salyzyn@adaptec.com +0 -1 # dpt_i2o: remove schedule_timeout() # # ChangeSet # 2005/01/17 11:47:26-06:00 domen@coderock.org # [PATCH] delete unused file dpt_osdutil.h # # Signed-off-by: Domen Puncer # Signed-off-by: James Bottomley # # BitKeeper/deleted/.del-dpt_osdutil.h~d761dac35b920619 # 2005/01/17 11:45:56-06:00 domen@coderock.org +0 -0 # Delete: drivers/scsi/dpt/dpt_osdutil.h # diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile --- a/drivers/base/Makefile 2005-01-23 22:28:26 -08:00 +++ b/drivers/base/Makefile 2005-01-23 22:28:26 -08:00 @@ -2,7 +2,8 @@ obj-y := core.o sys.o interface.o bus.o \ driver.o class.o class_simple.o platform.o \ - cpu.o firmware.o init.o map.o dmapool.o + cpu.o firmware.o init.o map.o dmapool.o \ + attribute_container.o transport_class.o obj-y += power/ obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o diff -Nru a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/base/attribute_container.c 2005-01-23 22:28:26 -08:00 @@ -0,0 +1,274 @@ +/* + * attribute_container.c - implementation of a simple container for classes + * + * Copyright (c) 2005 - James Bottomley + * + * This file is licensed under GPLv2 + * + * The basic idea here is to enable a device to be attached to an + * aritrary numer of classes without having to allocate storage for them. + * Instead, the contained classes select the devices they need to attach + * to via a matching function. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* This is a private structure used to tie the classdev and the + * container .. it should never be visible outside this file */ +struct internal_container { + struct list_head node; + struct attribute_container *cont; + struct class_device classdev; +}; + +/** + * attribute_container_classdev_to_container - given a classdev, return the container + * + * @classdev: the class device created by attribute_container_add_device. + * + * Returns the container associated with this classdev. + */ +struct attribute_container * +attribute_container_classdev_to_container(struct class_device *classdev) +{ + struct internal_container *ic = + container_of(classdev, struct internal_container, classdev); + return ic->cont; +} +EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); + +static struct list_head attribute_container_list; + +static DECLARE_MUTEX(attribute_container_mutex); + +/** + * attribute_container_register - register an attribute container + * + * @cont: The container to register. This must be allocated by the + * callee and should also be zeroed by it. + */ +int +attribute_container_register(struct attribute_container *cont) +{ + INIT_LIST_HEAD(&cont->node); + INIT_LIST_HEAD(&cont->containers); + + down(&attribute_container_mutex); + list_add_tail(&cont->node, &attribute_container_list); + up(&attribute_container_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(attribute_container_register); + +/** + * attribute_container_unregister - remove a container registration + * + * @cont: previously registered container to remove + */ +int +attribute_container_unregister(struct attribute_container *cont) +{ + int retval = -EBUSY; + down(&attribute_container_mutex); + if (!list_empty(&cont->containers)) + goto out; + retval = 0; + list_del(&cont->node); + out: + up(&attribute_container_mutex); + return retval; + +} +EXPORT_SYMBOL_GPL(attribute_container_unregister); + +/* private function used as class release */ +static void attribute_container_release(struct class_device *classdev) +{ + struct internal_container *ic + = container_of(classdev, struct internal_container, classdev); + struct device *dev = classdev->dev; + + kfree(ic); + put_device(dev); +} + +/** + * attribute_container_add_device - see if any container is interested in dev + * + * @dev: device to add attributes to + * @fn: function to trigger addition of class device. + * + * This function allocates storage for the class device(s) to be + * attached to dev (one for each matching attribute_container). If no + * fn is provided, the code will simply register the class device via + * class_device_add. If a function is provided, it is expected to add + * the class device at the appropriate time. One of the things that + * might be necessary is to allocate and initialise the classdev and + * then add it a later time. To do this, call this routine for + * allocation and initialisation and then use + * attribute_container_device_trigger() to call class_device_add() on + * it. Note: after this, the class device contains a reference to dev + * which is not relinquished until the release of the classdev. + */ +void +attribute_container_add_device(struct device *dev, + int (*fn)(struct attribute_container *, + struct device *, + struct class_device *)) +{ + struct attribute_container *cont; + + down(&attribute_container_mutex); + list_for_each_entry(cont, &attribute_container_list, node) { + struct internal_container *ic; + + if (attribute_container_no_classdevs(cont)) + continue; + + if (!cont->match(cont, dev)) + continue; + ic = kmalloc(sizeof(struct internal_container), GFP_KERNEL); + if (!ic) { + dev_printk(KERN_ERR, dev, "failed to allocate class container\n"); + continue; + } + memset(ic, 0, sizeof(struct internal_container)); + INIT_LIST_HEAD(&ic->node); + ic->cont = cont; + class_device_initialize(&ic->classdev); + ic->classdev.dev = get_device(dev); + ic->classdev.class = cont->class; + cont->class->release = attribute_container_release; + strcpy(ic->classdev.class_id, dev->bus_id); + if (fn) + fn(cont, dev, &ic->classdev); + else + class_device_add(&ic->classdev); + list_add_tail(&ic->node, &cont->containers); + } + up(&attribute_container_mutex); +} + +/** + * attribute_container_remove_device - make device eligible for removal. + * + * @dev: The generic device + * @fn: A function to call to remove the device + * + * This routine triggers device removal. If fn is NULL, then it is + * simply done via class_device_unregister (note that if something + * still has a reference to the classdev, then the memory occupied + * will not be freed until the classdev is released). If you want a + * two phase release: remove from visibility and then delete the + * device, then you should use this routine with a fn that calls + * class_device_del() and then use + * attribute_container_device_trigger() to do the final put on the + * classdev. + */ +void +attribute_container_remove_device(struct device *dev, + void (*fn)(struct attribute_container *, + struct device *, + struct class_device *)) +{ + struct attribute_container *cont; + + down(&attribute_container_mutex); + list_for_each_entry(cont, &attribute_container_list, node) { + struct internal_container *ic, *tmp; + + if (attribute_container_no_classdevs(cont)) + continue; + + if (!cont->match(cont, dev)) + continue; + list_for_each_entry_safe(ic, tmp, &cont->containers, node) { + if (dev != ic->classdev.dev) + continue; + list_del(&ic->node); + if (fn) + fn(cont, dev, &ic->classdev); + else + class_device_unregister(&ic->classdev); + } + } + up(&attribute_container_mutex); +} +EXPORT_SYMBOL_GPL(attribute_container_remove_device); + +/** + * attribute_container_device_trigger - execute a trigger for each matching classdev + * + * @dev: The generic device to run the trigger for + * @fn the function to execute for each classdev. + * + * This funcion is for executing a trigger when you need to know both + * the container and the classdev. If you only care about the + * container, then use attribute_container_trigger() instead. + */ +void +attribute_container_device_trigger(struct device *dev, + int (*fn)(struct attribute_container *, + struct device *, + struct class_device *)) +{ + struct attribute_container *cont; + + down(&attribute_container_mutex); + list_for_each_entry(cont, &attribute_container_list, node) { + struct internal_container *ic, *tmp; + + if (!cont->match(cont, dev)) + continue; + + list_for_each_entry_safe(ic, tmp, &cont->containers, node) { + if (dev == ic->classdev.dev) + fn(cont, dev, &ic->classdev); + } + } + up(&attribute_container_mutex); +} +EXPORT_SYMBOL_GPL(attribute_container_device_trigger); + +/** + * attribute_container_trigger - trigger a function for each matching container + * + * @dev: The generic device to activate the trigger for + * @fn: the function to trigger + * + * This routine triggers a function that only needs to know the + * matching containers (not the classdev) associated with a device. + * It is more lightweight than attribute_container_device_trigger, so + * should be used in preference unless the triggering function + * actually needs to know the classdev. + */ +void +attribute_container_trigger(struct device *dev, + int (*fn)(struct attribute_container *, + struct device *)) +{ + struct attribute_container *cont; + + down(&attribute_container_mutex); + list_for_each_entry(cont, &attribute_container_list, node) { + if (cont->match(cont, dev)) + fn(cont, dev); + } + up(&attribute_container_mutex); +} +EXPORT_SYMBOL_GPL(attribute_container_trigger); + + +int __init +attribute_container_init(void) +{ + INIT_LIST_HEAD(&attribute_container_list); + return 0; +} diff -Nru a/drivers/base/init.c b/drivers/base/init.c --- a/drivers/base/init.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/base/init.c 2005-01-23 22:28:26 -08:00 @@ -17,7 +17,7 @@ extern int platform_bus_init(void); extern int system_bus_init(void); extern int cpu_dev_init(void); - +extern int attribute_container_init(void); /** * driver_init - initialize driver model. * @@ -39,4 +39,5 @@ platform_bus_init(); system_bus_init(); cpu_dev_init(); + attribute_container_init(); } diff -Nru a/drivers/base/transport_class.c b/drivers/base/transport_class.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/base/transport_class.c 2005-01-23 22:28:26 -08:00 @@ -0,0 +1,272 @@ +/* + * transport_class.c - implementation of generic transport classes + * using attribute_containers + * + * Copyright (c) 2005 - James Bottomley + * + * This file is licensed under GPLv2 + * + * The basic idea here is to allow any "device controller" (which + * would most often be a Host Bus Adapter" to use the services of one + * or more tranport classes for performing transport specific + * services. Transport specific services are things that the generic + * command layer doesn't want to know about (speed settings, line + * condidtioning, etc), but which the user might be interested in. + * Thus, the HBA's use the routines exported by the transport classes + * to perform these functions. The transport classes export certain + * values to the user via sysfs using attribute containers. + * + * Note: because not every HBA will care about every transport + * attribute, there's a many to one relationship that goes like this: + * + * transport class<-----attribute container<----class device + * + * Usually the attribute container is per-HBA, but the design doesn't + * mandate that. Although most of the services will be specific to + * the actual external storage connection used by the HBA, the generic + * transport class is framed entirely in terms of generic devices to + * allow it to be used by any physical HBA in the system. + */ +#include +#include + +/** + * transport_class_register - register an initial transport class + * + * @tclass: a pointer to the transport class structure to be initialised + * + * The transport class contains an embedded class which is used to + * identify it. The caller should initialise this structure with + * zeros and then generic class must have been initialised with the + * actual transport class unique name. There's a macro + * DECLARE_TRANSPORT_CLASS() to do this (declared classes still must + * be registered). + * + * Returns 0 on success or error on failure. + */ +int transport_class_register(struct transport_class *tclass) +{ + return class_register(&tclass->class); +} +EXPORT_SYMBOL_GPL(transport_class_register); + +/** + * transport_class_unregister - unregister a previously registered class + * + * @tclass: The transport class to unregister + * + * Must be called prior to deallocating the memory for the transport + * class. + */ +void transport_class_unregister(struct transport_class *tclass) +{ + class_unregister(&tclass->class); +} +EXPORT_SYMBOL_GPL(transport_class_unregister); + +static int anon_transport_dummy_function(struct device *dev) +{ + /* do nothing */ + return 0; +} + +/** + * anon_transport_class_register - register an anonymous class + * + * @atc: The anon transport class to register + * + * The anonymous transport class contains both a transport class and a + * container. The idea of an anonymous class is that it never + * actually has any device attributes associated with it (and thus + * saves on container storage). So it can only be used for triggering + * events. Use prezero and then use DECLARE_ANON_TRANSPORT_CLASS() to + * initialise the anon transport class storage. + */ +int anon_transport_class_register(struct anon_transport_class *atc) +{ + int error; + atc->container.class = &atc->tclass.class; + attribute_container_set_no_classdevs(&atc->container); + error = attribute_container_register(&atc->container); + if (error) + return error; + atc->tclass.setup = anon_transport_dummy_function; + atc->tclass.remove = anon_transport_dummy_function; + return 0; +} +EXPORT_SYMBOL_GPL(anon_transport_class_register); + +/** + * anon_transport_class_unregister - unregister an anon class + * + * @atc: Pointer to the anon transport class to unregister + * + * Must be called prior to deallocating the memory for the anon + * transport class. + */ +void anon_transport_class_unregister(struct anon_transport_class *atc) +{ + attribute_container_unregister(&atc->container); +} +EXPORT_SYMBOL_GPL(anon_transport_class_unregister); + +static int transport_setup_classdev(struct attribute_container *cont, + struct device *dev, + struct class_device *classdev) +{ + struct transport_class *tclass = class_to_transport_class(cont->class); + + if (tclass->setup) + tclass->setup(dev); + + return 0; +} + +/** + * transport_setup_device - declare a new dev for transport class association + * but don't make it visible yet. + * + * @dev: the generic device representing the entity being added + * + * Usually, dev represents some component in the HBA system (either + * the HBA itself or a device remote across the HBA bus). This + * routine is simply a trigger point to see if any set of transport + * classes wishes to associate with the added device. This allocates + * storage for the class device and initialises it, but does not yet + * add it to the system or add attributes to it (you do this with + * transport_add_device). If you have no need for a separate setup + * and add operations, use transport_register_device (see + * transport_class.h). + */ + +void transport_setup_device(struct device *dev) +{ + attribute_container_add_device(dev, transport_setup_classdev); +} +EXPORT_SYMBOL_GPL(transport_setup_device); + + +static int transport_add_classdev(struct attribute_container *cont, + struct device *dev, + struct class_device *classdev) +{ + struct class_device_attribute **attrs = cont->attrs; + int i, error; + + error = class_device_add(classdev); + if (error) + return error; + for (i = 0; attrs[i]; i++) { + error = class_device_create_file(classdev, attrs[i]); + if (error) + return error; + } + + return 0; +} + +/** + * transport_add_device - declare a new dev for transport class association + * + * @dev: the generic device representing the entity being added + * + * Usually, dev represents some component in the HBA system (either + * the HBA itself or a device remote across the HBA bus). This + * routine is simply a trigger point used to add the device to the + * system and register attributes for it. + */ + +void transport_add_device(struct device *dev) +{ + attribute_container_device_trigger(dev, transport_add_classdev); +} +EXPORT_SYMBOL_GPL(transport_add_device); + +static int transport_configure(struct attribute_container *cont, + struct device *dev) +{ + struct transport_class *tclass = class_to_transport_class(cont->class); + + if (tclass->configure) + tclass->configure(dev); + + return 0; +} + +/** + * transport_configure_device - configure an already set up device + * + * @dev: generic device representing device to be configured + * + * The idea of configure is simply to provide a point within the setup + * process to allow the transport class to extract information from a + * device after it has been setup. This is used in SCSI because we + * have to have a setup device to begin using the HBA, but after we + * send the initial inquiry, we use configure to extract the device + * parameters. The device need not have been added to be configured. + */ +void transport_configure_device(struct device *dev) +{ + attribute_container_trigger(dev, transport_configure); +} +EXPORT_SYMBOL_GPL(transport_configure_device); + +static int transport_remove_classdev(struct attribute_container *cont, + struct device *dev, + struct class_device *classdev) +{ + struct transport_class *tclass = class_to_transport_class(cont->class); + + if (tclass->remove) + tclass->remove(dev); + + return 0; +} + + +/** + * transport_remove_device - remove the visibility of a device + * + * @dev: generic device to remove + * + * This call removes the visibility of the device (to the user from + * sysfs), but does not destroy it. To eliminate a device entirely + * you must also call transport_destroy_device. If you don't need to + * do remove and destroy as separate operations, use + * transport_unregister_device() (see transport_class.h) which will + * perform both calls for you. + */ +void transport_remove_device(struct device *dev) +{ + attribute_container_device_trigger(dev, transport_remove_classdev); +} +EXPORT_SYMBOL_GPL(transport_remove_device); + +static void transport_destroy_classdev(struct attribute_container *cont, + struct device *dev, + struct class_device *classdev) +{ + struct transport_class *tclass = class_to_transport_class(cont->class); + + if (tclass->remove != anon_transport_dummy_function) + class_device_put(classdev); +} + + +/** + * transport_destroy_device - destroy a removed device + * + * @dev: device to eliminate from the transport class. + * + * This call triggers the elimination of storage associated with the + * transport classdev. Note: all it really does is relinquish a + * reference to the classdev. The memory will not be freed until the + * last reference goes to zero. Note also that the classdev retains a + * reference count on dev, so dev too will remain for as long as the + * transport class device remains around. + */ +void transport_destroy_device(struct device *dev) +{ + attribute_container_remove_device(dev, transport_destroy_classdev); +} +EXPORT_SYMBOL_GPL(transport_destroy_device); diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/Kconfig 2005-01-23 22:28:26 -08:00 @@ -225,14 +225,14 @@ config SCSI_DECNCR tristate "DEC NCR53C94 Scsi Driver" - depends on DECSTATION && TC && SCSI + depends on MACH_DECSTATION && SCSI && TC help Say Y here to support the NCR53C94 SCSI controller chips on IOASIC based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. config SCSI_DECSII tristate "DEC SII Scsi Driver" - depends on DECSTATION && SCSI + depends on MACH_DECSTATION && SCSI && MIPS32 config BLK_DEV_3W_XXXX_RAID tristate "3ware 5/6/7/8xxx ATA-RAID support" diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c --- a/drivers/scsi/NCR53C9x.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/NCR53C9x.c 2005-01-23 22:28:26 -08:00 @@ -290,7 +290,7 @@ #endif #ifdef DEBUG_ESP_CMDS -inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, +static inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, unchar cmd) { esp->espcmdlog[esp->espcmdent] = cmd; @@ -505,7 +505,7 @@ } /* This places the ESP into a known state at boot time. */ -static void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs) +void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs) { volatile unchar trash; diff -Nru a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h --- a/drivers/scsi/NCR53C9x.h 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/NCR53C9x.h 2005-01-23 22:28:26 -08:00 @@ -652,7 +652,7 @@ /* External functions */ -extern void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, unchar cmd); +extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs); extern struct NCR_ESP *esp_allocate(Scsi_Host_Template *, void *); extern void esp_deallocate(struct NCR_ESP *); extern void esp_release(void); diff -Nru a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c --- a/drivers/scsi/NCR_Q720.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/NCR_Q720.c 2005-01-23 22:28:26 -08:00 @@ -48,7 +48,7 @@ struct Scsi_Host *hosts[4]; }; -struct scsi_host_template NCR_Q720_tpnt = { +static struct scsi_host_template NCR_Q720_tpnt = { .module = THIS_MODULE, .proc_name = "NCR_Q720", }; @@ -345,7 +345,7 @@ static short NCR_Q720_id_table[] = { NCR_Q720_MCA_ID, 0 }; -struct mca_driver NCR_Q720_driver = { +static struct mca_driver NCR_Q720_driver = { .id_table = NCR_Q720_id_table, .driver = { .name = "NCR_Q720", diff -Nru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c --- a/drivers/scsi/aacraid/aachba.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/aacraid/aachba.c 2005-01-23 22:28:26 -08:00 @@ -1029,6 +1029,114 @@ return 0; } +static void synchronize_callback(void *context, struct fib *fibptr) +{ + struct aac_synchronize_reply *synchronizereply; + struct scsi_cmnd *cmd; + + cmd = context; + + dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", + smp_processor_id(), jiffies)); + BUG_ON(fibptr == NULL); + + + synchronizereply = fib_data(fibptr); + if (le32_to_cpu(synchronizereply->status) == CT_OK) + cmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + else { + struct scsi_device *sdev = cmd->device; + struct aac_dev *dev = (struct aav_dev *)sdev->host->hostdata; + u32 cid = ID_LUN_TO_CONTAINER(sdev->id, sdev->lun); + printk(KERN_WARNING + "synchronize_callback: synchronize failed, status = %d\n", + synchronizereply->status); + cmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; + set_sense((u8 *)&dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); + memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, + min(sizeof(dev->fsa_dev[cid].sense_data), + sizeof(cmd->sense_buffer))); + } + + fib_complete(fibptr); + fib_free(fibptr); + aac_io_done(cmd); +} + +static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid) +{ + int status; + struct fib *cmd_fibcontext; + struct aac_synchronize *synchronizecmd; + struct scsi_cmnd *cmd; + struct scsi_device *sdev = scsicmd->device; + int active = 0; + unsigned long flags; + + /* + * Wait for all commands to complete to this specific + * target (block). + */ + spin_lock_irqsave(&sdev->list_lock, flags); + list_for_each_entry(cmd, &sdev->cmd_list, list) + if (cmd != scsicmd && cmd->serial_number != 0) { + ++active; + break; + } + + spin_unlock_irqrestore(&sdev->list_lock, flags); + + /* + * Yield the processor (requeue for later) + */ + if (active) + return SCSI_MLQUEUE_DEVICE_BUSY; + + /* + * Alocate and initialize a Fib + */ + if (!(cmd_fibcontext = + fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) + return SCSI_MLQUEUE_HOST_BUSY; + + fib_init(cmd_fibcontext); + + synchronizecmd = fib_data(cmd_fibcontext); + synchronizecmd->command = cpu_to_le32(VM_ContainerConfig); + synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE); + synchronizecmd->cid = cpu_to_le32(cid); + synchronizecmd->count = + cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data)); + + /* + * Now send the Fib to the adapter + */ + status = fib_send(ContainerCommand, + cmd_fibcontext, + sizeof(struct aac_synchronize), + FsaNormal, + 0, 1, + (fib_callback)synchronize_callback, + (void *)scsicmd); + + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) + return 0; + + printk(KERN_WARNING + "aac_synchronize: fib_send failed with status: %d.\n", status); + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return SCSI_MLQUEUE_HOST_BUSY; +} /** * aac_scsi_cmd() - Process SCSI command @@ -1274,6 +1382,11 @@ ret = aac_write(scsicmd, cid); spin_lock_irq(host->host_lock); return ret; + + case SYNCHRONIZE_CACHE: + /* Issue FIB to tell Firmware to flush it's cache */ + return aac_synchronize(scsicmd, cid); + default: /* * Unhandled commands diff -Nru a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h --- a/drivers/scsi/aacraid/aacraid.h 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/aacraid/aacraid.h 2005-01-23 22:28:26 -08:00 @@ -1069,6 +1069,30 @@ u32 committed; }; +#define CT_FLUSH_CACHE 129 +struct aac_synchronize { + u32 command; /* VM_ContainerConfig */ + u32 type; /* CT_FLUSH_CACHE */ + u32 cid; + u32 parm1; + u32 parm2; + u32 parm3; + u32 parm4; + u32 count; /* sizeof(((struct aac_synchronize_reply *)NULL)->data) */ +}; + +struct aac_synchronize_reply { + u32 dummy0; + u32 dummy1; + u32 status; /* CT_OK */ + u32 parm1; + u32 parm2; + u32 parm3; + u32 parm4; + u32 parm5; + u8 data[16]; +}; + struct aac_srb { u32 function; diff -Nru a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c --- a/drivers/scsi/dec_esp.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/dec_esp.c 2005-01-23 22:28:26 -08:00 @@ -17,6 +17,8 @@ * data. * 20001005 - Initialization fixes for 2.4.0-test9 * Florian Lohoff + * + * Copyright (C) 2002, 2003 Maciej W. Rozycki */ #include @@ -26,59 +28,52 @@ #include #include #include +#include #include -#include "scsi.h" -#include -#include "NCR53C9x.h" - -#include -#include -#include #include - +#include #include +#include -#include #include +#include #include #include #include +#include #define DEC_SCSI_SREG 0 #define DEC_SCSI_DMAREG 0x40000 #define DEC_SCSI_SRAM 0x80000 #define DEC_SCSI_DIAG 0xC0000 -/* - * Once upon a time the pmaz code used to be working but - * it hasn't been maintained for quite some time. - * It isn't working anymore but I'll leave here as a - * starting point. #define this an be prepared for tons - * of warnings and errors :) - */ +#include "scsi.h" +#include +#include "NCR53C9x.h" + static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); static void dma_drain(struct NCR_ESP *esp); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp); static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length); static void dma_ints_off(struct NCR_ESP *esp); static void dma_ints_on(struct NCR_ESP *esp); static int dma_irq_p(struct NCR_ESP *esp); static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); -static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp); -static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp); -static void dma_advance_sg(Scsi_Cmnd * sp); +static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write); +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp); +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp); +static void dma_advance_sg(struct scsi_cmnd * sp); static void pmaz_dma_drain(struct NCR_ESP *esp); -static void pmaz_dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); -static void pmaz_dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length); +static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length); static void pmaz_dma_ints_off(struct NCR_ESP *esp); static void pmaz_dma_ints_on(struct NCR_ESP *esp); -static void pmaz_dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); -static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write); +static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp); #define TC_ESP_RAM_SIZE 0x20000 #define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1)) @@ -88,7 +83,7 @@ #define TC_ESP_DMAR_WRITE 0x80000000 #define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK) -__u32 esp_virt_buffer; +u32 esp_virt_buffer; int scsi_current_length; volatile unsigned char cmd_buffer[16]; @@ -98,16 +93,11 @@ * via PIO. */ -volatile unsigned long *scsi_dma_ptr; -volatile unsigned long *scsi_next_ptr; -volatile unsigned long *scsi_scr; -volatile unsigned long *ioasic_ssr; -volatile unsigned long *scsi_sdr0; -volatile unsigned long *scsi_sdr1; +static irqreturn_t scsi_dma_merr_int(int, void *, struct pt_regs *); +static irqreturn_t scsi_dma_err_int(int, void *, struct pt_regs *); +static irqreturn_t scsi_dma_int(int, void *, struct pt_regs *); -static void scsi_dma_int(int, void *, struct pt_regs *); - -int dec_esp_detect(Scsi_Host_Template * tpnt); +static int dec_esp_detect(struct scsi_host_template * tpnt); static int dec_esp_release(struct Scsi_Host *shost) { @@ -119,9 +109,9 @@ return 0; } -static Scsi_Host_Template driver_template = { +static struct scsi_host_template driver_template = { .proc_name = "dec_esp", - .proc_info = &esp_proc_info, + .proc_info = esp_proc_info, .name = "NCR53C94", .detect = dec_esp_detect, .slave_alloc = esp_slave_alloc, @@ -142,7 +132,7 @@ #include "scsi_module.c" /***************************************************************** Detection */ -int dec_esp_detect(Scsi_Host_Template * tpnt) +static int dec_esp_detect(Scsi_Host_Template * tpnt) { struct NCR_ESP *esp; struct ConfigDev *esp_dev; @@ -152,17 +142,10 @@ if (IOASIC) { esp_dev = 0; esp = esp_allocate(tpnt, (void *) esp_dev); - - scsi_dma_ptr = (unsigned long *) (system_base + IOCTL + SCSI_DMA_P); - scsi_next_ptr = (unsigned long *) (system_base + IOCTL + SCSI_DMA_BP); - scsi_scr = (unsigned long *) (system_base + IOCTL + SCSI_SCR); - ioasic_ssr = (unsigned long *) (system_base + IOCTL + SSR); - scsi_sdr0 = (unsigned long *) (system_base + IOCTL + SCSI_SDR0); - scsi_sdr1 = (unsigned long *) (system_base + IOCTL + SCSI_SDR1); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; - + /* Required functions */ esp->dma_bytes_sent = &dma_bytes_sent; esp->dma_can_transfer = &dma_can_transfer; @@ -185,7 +168,7 @@ esp->dma_reset = 0; esp->dma_led_off = 0; esp->dma_led_on = 0; - + /* virtual DMA functions */ esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; @@ -197,38 +180,42 @@ /* SCSI chip speed */ esp->cfreq = 25000000; - /* - * we don't give the address of DMA channel, but the number - * of DMA channel, so we can use the jazz DMA functions - * - */ - esp->dregs = JAZZ_SCSI_DMA; - + esp->dregs = 0; + /* ESP register base */ - esp->eregs = (struct ESP_regs *) (system_base + SCSI); - + esp->eregs = (struct ESP_regs *) (system_base + IOASIC_SCSI); + /* Set the command buffer */ esp->esp_command = (volatile unsigned char *) cmd_buffer; - + /* get virtual dma address for command buffer */ - esp->esp_command_dvma = (__u32) KSEG1ADDR((volatile unsigned char *) cmd_buffer); - - esp->irq = SCSI_INT; + esp->esp_command_dvma = virt_to_phys(cmd_buffer); + + esp->irq = dec_interrupt[DEC_IRQ_ASC]; esp->scsi_id = 7; - + /* Check for differential SCSI-bus */ esp->diff = 0; esp_initialize(esp); - if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, - "NCR 53C94 SCSI", esp->ehost)) + if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, + "ncr53c94", esp->ehost)) goto err_dealloc; - if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, - "JUNKIO SCSI DMA", esp->ehost)) + if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], + scsi_dma_merr_int, SA_INTERRUPT, + "ncr53c94 error", esp->ehost)) goto err_free_irq; - + if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], + scsi_dma_err_int, SA_INTERRUPT, + "ncr53c94 overrun", esp->ehost)) + goto err_free_irq_merr; + if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], + scsi_dma_int, SA_INTERRUPT, + "ncr53c94 dma", esp->ehost)) + goto err_free_irq_err; + } if (TURBOCHANNEL) { @@ -241,7 +228,7 @@ mem_start = get_tc_base_addr(slot); /* Store base addr into esp struct */ - esp->slot = mem_start; + esp->slot = PHYSADDR(mem_start); esp->dregs = 0; esp->eregs = (struct ESP_regs *) (mem_start + DEC_SCSI_SREG); @@ -251,7 +238,7 @@ esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer; /* get virtual dma address for command buffer */ - esp->esp_command_dvma = (__u32) KSEG0ADDR((volatile unsigned char *) pmaz_cmd_buffer); + esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); esp->cfreq = get_tc_speed(); @@ -286,7 +273,7 @@ esp->dma_mmu_release_scsi_sgl = 0; esp->dma_advance_sg = 0; - if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, + if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, "PMAZ_AA", esp->ehost)) { esp_deallocate(esp); release_tc_card(slot); @@ -305,231 +292,259 @@ } return 0; - err_free_irq: +err_free_irq_err: + free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int); +err_free_irq_merr: + free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int); +err_free_irq: free_irq(esp->irq, esp_intr); - err_dealloc: +err_dealloc: esp_deallocate(esp); return 0; } /************************************************************* DMA Functions */ -static void scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs) { - extern volatile unsigned int *isr; - unsigned int dummy; + printk("Got unexpected SCSI DMA Interrupt! < "); + printk("SCSI_DMA_MEMRDERR "); + printk(">\n"); - if (*isr & SCSI_PTR_LOADED) { - /* next page */ - *scsi_next_ptr = ((*scsi_dma_ptr + PAGE_SIZE) & PAGE_MASK) << 3; - *isr &= ~SCSI_PTR_LOADED; - } else { - if (*isr & SCSI_PAGOVRRUN) - *isr &= ~SCSI_PAGOVRRUN; - if (*isr & SCSI_DMA_MEMRDERR) { - printk("Got unexpected SCSI DMA Interrupt! < "); - printk("SCSI_DMA_MEMRDERR "); - printk(">\n"); - *isr &= ~SCSI_DMA_MEMRDERR; - } - } + return IRQ_HANDLED; +} - /* - * This routine will only work on IOASIC machines - * so we can avoid an indirect function call here - * and flush the writeback buffer the fast way - */ - dummy = *isr; - dummy = *isr; +static irqreturn_t scsi_dma_err_int(int irq, void *dev_id, struct pt_regs *regs) +{ + /* empty */ + + return IRQ_HANDLED; +} + +static irqreturn_t scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 scsi_next_ptr; + + scsi_next_ptr = ioasic_read(IO_REG_SCSI_DMA_P); + + /* next page */ + scsi_next_ptr = (((scsi_next_ptr >> 3) + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); + fast_iob(); + + return IRQ_HANDLED; } static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) { - return fifo_count; + return fifo_count; } static void dma_drain(struct NCR_ESP *esp) { - unsigned long nw = *scsi_scr; - unsigned short *p = (unsigned short *)KSEG1ADDR((*scsi_dma_ptr) >> 3); + u32 nw, data0, data1, scsi_data_ptr; + u16 *p; + + nw = ioasic_read(IO_REG_SCSI_SCR); - /* + /* * Is there something in the dma buffers left? - */ + */ if (nw) { + scsi_data_ptr = ioasic_read(IO_REG_SCSI_DMA_P) >> 3; + p = phys_to_virt(scsi_data_ptr); switch (nw) { case 1: - *p = (unsigned short) *scsi_sdr0; + data0 = ioasic_read(IO_REG_SCSI_SDR0); + p[0] = data0 & 0xffff; break; case 2: - *p++ = (unsigned short) (*scsi_sdr0); - *p = (unsigned short) ((*scsi_sdr0) >> 16); + data0 = ioasic_read(IO_REG_SCSI_SDR0); + p[0] = data0 & 0xffff; + p[1] = (data0 >> 16) & 0xffff; break; case 3: - *p++ = (unsigned short) (*scsi_sdr0); - *p++ = (unsigned short) ((*scsi_sdr0) >> 16); - *p = (unsigned short) (*scsi_sdr1); + data0 = ioasic_read(IO_REG_SCSI_SDR0); + data1 = ioasic_read(IO_REG_SCSI_SDR1); + p[0] = data0 & 0xffff; + p[1] = (data0 >> 16) & 0xffff; + p[2] = data1 & 0xffff; break; default: - printk("Strange: %d words in dma buffer left\n", (int) nw); + printk("Strange: %d words in dma buffer left\n", nw); break; } } } -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp) +static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd * sp) { return sp->SCp.this_residual; } static void dma_dump_state(struct NCR_ESP *esp) { -/* - ESPLOG(("esp%d: dma -- enable <%08x> residue <%08x\n", - esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_resdiue((int)esp->dregs))); - */ } -static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) +static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length) { - extern volatile unsigned int *isr; - unsigned int dummy; + u32 scsi_next_ptr, ioasic_ssr; + unsigned long flags; if (vaddress & 3) - panic("dec_efs.c: unable to handle partial word transfers, yet..."); + panic("dec_esp.c: unable to handle partial word transfers, yet..."); dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); - *ioasic_ssr &= ~SCSI_DMA_EN; - *scsi_scr = 0; - *scsi_dma_ptr = vaddress << 3; + spin_lock_irqsave(&ioasic_ssr_lock, flags); + + fast_mb(); + ioasic_ssr = ioasic_read(IO_REG_SSR); + + ioasic_ssr &= ~IO_SSR_SCSI_DMA_EN; + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_wmb(); + ioasic_write(IO_REG_SCSI_SCR, 0); + ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3); /* prepare for next page */ - *scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; - *ioasic_ssr |= (SCSI_DMA_DIR | SCSI_DMA_EN); + scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); - /* - * see above - */ - dummy = *isr; - dummy = *isr; + ioasic_ssr |= (IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN); + fast_wmb(); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_iob(); + spin_unlock_irqrestore(&ioasic_ssr_lock, flags); } -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length) { - extern volatile unsigned int *isr; - unsigned int dummy; + u32 scsi_next_ptr, ioasic_ssr; + unsigned long flags; if (vaddress & 3) - panic("dec_efs.c: unable to handle partial word transfers, yet..."); + panic("dec_esp.c: unable to handle partial word transfers, yet..."); dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); - *ioasic_ssr &= ~(SCSI_DMA_DIR | SCSI_DMA_EN); - *scsi_scr = 0; - *scsi_dma_ptr = vaddress << 3; + spin_lock_irqsave(&ioasic_ssr_lock, flags); + + fast_mb(); + ioasic_ssr = ioasic_read(IO_REG_SSR); + + ioasic_ssr &= ~(IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_wmb(); + ioasic_write(IO_REG_SCSI_SCR, 0); + ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3); /* prepare for next page */ - *scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; - *ioasic_ssr |= SCSI_DMA_EN; + scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); - /* - * see above - */ - dummy = *isr; - dummy = *isr; + ioasic_ssr |= IO_SSR_SCSI_DMA_EN; + fast_wmb(); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_iob(); + spin_unlock_irqrestore(&ioasic_ssr_lock, flags); } static void dma_ints_off(struct NCR_ESP *esp) { - disable_irq(SCSI_DMA_INT); + disable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]); } static void dma_ints_on(struct NCR_ESP *esp) { - enable_irq(SCSI_DMA_INT); + enable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]); } static int dma_irq_p(struct NCR_ESP *esp) { - return (esp->eregs->esp_status & ESP_STAT_INTR); + return (esp->eregs->esp_status & ESP_STAT_INTR); } static int dma_ports_p(struct NCR_ESP *esp) { -/* - * FIXME: what's this good for? - */ + /* + * FIXME: what's this good for? + */ return 1; } -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write) { - /* - * On the Sparc, DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if (write) { - dma_init_read(esp, addr, count); - } else { - dma_init_write(esp, addr, count); - } + /* + * DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if (write) + dma_init_read(esp, addr, count); + else + dma_init_write(esp, addr, count); } -/* - * These aren't used yet - */ -static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp) +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp) { - sp->SCp.ptr = (char *)PHYSADDR(sp->SCp.buffer); + sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); } -static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp) +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp) { - int sz = sp->SCp.buffers_residual; - struct mmu_sglist *sg = (struct mmu_sglist *) sp->SCp.buffer; + int sz = sp->SCp.buffers_residual; + struct scatterlist *sg = sp->SCp.buffer; - while (sz >= 0) { - sg[sz].dvma_addr = PHYSADDR(sg[sz].addr); - sz--; - } - sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address); + while (sz >= 0) { + sg[sz].dma_address = page_to_phys(sg[sz].page) + sg[sz].offset; + sz--; + } + sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); } -static void dma_advance_sg(Scsi_Cmnd * sp) +static void dma_advance_sg(struct scsi_cmnd * sp) { - sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address); + sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); } static void pmaz_dma_drain(struct NCR_ESP *esp) { - memcpy((void *) (KSEG0ADDR(esp_virt_buffer)), - (void *) ( esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE), + memcpy(phys_to_virt(esp_virt_buffer), + (void *)KSEG1ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE), scsi_current_length); } -static void pmaz_dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) +static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length) { - volatile int *dmareg = (volatile int *) (esp->slot + DEC_SCSI_DMAREG); + volatile u32 *dmareg = + (volatile u32 *)KSEG1ADDR(esp->slot + DEC_SCSI_DMAREG); if (length > ESP_TGT_DMA_SIZE) length = ESP_TGT_DMA_SIZE; - *dmareg = TC_ESP_DMA_ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE); + *dmareg = TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE); + + iob(); esp_virt_buffer = vaddress; scsi_current_length = length; } -static void pmaz_dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length) { - volatile int *dmareg = (volatile int *) ( esp->slot + DEC_SCSI_DMAREG ); + volatile u32 *dmareg = + (volatile u32 *)KSEG1ADDR(esp->slot + DEC_SCSI_DMAREG); - memcpy((void *)(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE), - (void *)KSEG0ADDR(vaddress), length); + memcpy((void *)KSEG1ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE), + phys_to_virt(vaddress), length); - *dmareg = TC_ESP_DMAR_WRITE | - TC_ESP_DMA_ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE); + wmb(); + *dmareg = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE); + iob(); } static void pmaz_dma_ints_off(struct NCR_ESP *esp) @@ -540,20 +555,19 @@ { } -static void pmaz_dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write) { /* - * On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * DMA_ST_WRITE means "move data from device to memory" * so when (write) is true, it actually means READ! */ - if (write) { + if (write) pmaz_dma_init_read(esp, addr, count); - } else { + else pmaz_dma_init_write(esp, addr, count); - } } -static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp) +static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp) { - sp->SCp.ptr = (char *)KSEG0ADDR((sp->request_buffer)); + sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); } diff -Nru a/drivers/scsi/dpt/dpt_osdutil.h b/drivers/scsi/dpt/dpt_osdutil.h --- a/drivers/scsi/dpt/dpt_osdutil.h 2005-01-23 22:28:26 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,358 +0,0 @@ -/* BSDI osd_util.h,v 1.8 1998/06/03 19:14:58 karels Exp */ - -/* - * Copyright (c) 1996-1999 Distributed Processing Technology Corporation - * All rights reserved. - * - * Redistribution and use in source form, with or without modification, are - * permitted provided that redistributions of source code must retain the - * above copyright notice, this list of conditions and the following disclaimer. - * - * This software is provided `as is' by Distributed Processing Technology and - * any express or implied warranties, including, but not limited to, the - * implied warranties of merchantability and fitness for a particular purpose, - * are disclaimed. In no event shall Distributed Processing Technology be - * liable for any direct, indirect, incidental, special, exemplary or - * consequential damages (including, but not limited to, procurement of - * substitute goods or services; loss of use, data, or profits; or business - * interruptions) however caused and on any theory of liability, whether in - * contract, strict liability, or tort (including negligence or otherwise) - * arising in any way out of the use of this driver software, even if advised - * of the possibility of such damage. - * - */ - -#ifndef __OSD_UTIL_H -#define __OSD_UTIL_H - -/*File - OSD_UTIL.H - **************************************************************************** - * - *Description: - * - * This file contains defines and function prototypes that are - *operating system dependent. The resources defined in this file - *are not specific to any particular application. - * - *Copyright Distributed Processing Technology, Corp. - * 140 Candace Dr. - * Maitland, Fl. 32751 USA - * Phone: (407) 830-5522 Fax: (407) 260-5366 - * All Rights Reserved - * - *Author: Doug Anderson - *Date: 1/7/94 - * - *Editors: - * - *Remarks: - * - * - *****************************************************************************/ - - -/*Definitions - Defines & Constants ----------------------------------------- */ - -/*----------------------------- */ -/* Operating system selections: */ -/*----------------------------- */ - -/*#define _DPT_MSDOS */ -/*#define _DPT_WIN_3X */ -/*#define _DPT_WIN_4X */ -/*#define _DPT_WIN_NT */ -/*#define _DPT_NETWARE */ -/*#define _DPT_OS2 */ -/*#define _DPT_SCO */ -/*#define _DPT_UNIXWARE */ -/*#define _DPT_SOLARIS */ -/*#define _DPT_NEXTSTEP */ -/*#define _DPT_BANYAN */ - -/*-------------------------------- */ -/* Include the OS specific defines */ -/*-------------------------------- */ - -/*#define OS_SELECTION From Above List */ -/*#define SEMAPHORE_T ??? */ -/*#define DLL_HANDLE_T ??? */ - -#if (defined(KERNEL) && (defined(__FreeBSD__) || defined(__bsdi__))) -# include "i386/isa/dpt_osd_defs.h" -#else -# include "osd_defs.h" -#endif - -#ifndef DPT_UNALIGNED - #define DPT_UNALIGNED -#endif - -#ifndef DPT_EXPORT - #define DPT_EXPORT -#endif - -#ifndef DPT_IMPORT - #define DPT_IMPORT -#endif - -#ifndef DPT_RUNTIME_IMPORT - #define DPT_RUNTIME_IMPORT DPT_IMPORT -#endif - -/*--------------------- */ -/* OS dependent defines */ -/*--------------------- */ - -#if defined (_DPT_MSDOS) || defined (_DPT_WIN_3X) - #define _DPT_16_BIT -#else - #define _DPT_32_BIT -#endif - -#if defined (_DPT_SCO) || defined (_DPT_UNIXWARE) || defined (_DPT_SOLARIS) || defined (_DPT_AIX) || defined (SNI_MIPS) || defined (_DPT_BSDI) || defined (_DPT_FREE_BSD) || defined(_DPT_LINUX) - #define _DPT_UNIX -#endif - -#if defined (_DPT_WIN_3x) || defined (_DPT_WIN_4X) || defined (_DPT_WIN_NT) \ - || defined (_DPT_OS2) - #define _DPT_DLL_SUPPORT -#endif - -#if !defined (_DPT_MSDOS) && !defined (_DPT_WIN_3X) && !defined (_DPT_NETWARE) - #define _DPT_PREEMPTIVE -#endif - -#if !defined (_DPT_MSDOS) && !defined (_DPT_WIN_3X) - #define _DPT_MULTI_THREADED -#endif - -#if !defined (_DPT_MSDOS) - #define _DPT_MULTI_TASKING -#endif - - /* These exist for platforms that */ - /* chunk when accessing mis-aligned */ - /* data */ -#if defined (SNI_MIPS) || defined (_DPT_SOLARIS) - #if defined (_DPT_BIG_ENDIAN) - #if !defined (_DPT_STRICT_ALIGN) - #define _DPT_STRICT_ALIGN - #endif - #endif -#endif - - /* Determine if in C or C++ mode */ -#ifdef __cplusplus - #define _DPT_CPP -#else - #define _DPT_C -#endif - -/*-------------------------------------------------------------------*/ -/* Under Solaris the compiler refuses to accept code like: */ -/* { {"DPT"}, 0, NULL .... }, */ -/* and complains about the {"DPT"} part by saying "cannot use { } */ -/* to initialize char*". */ -/* */ -/* By defining these ugly macros we can get around this and also */ -/* not have to copy and #ifdef large sections of code. I know that */ -/* these macros are *really* ugly, but they should help reduce */ -/* maintenance in the long run. */ -/* */ -/*-------------------------------------------------------------------*/ -#if !defined (DPTSQO) - #if defined (_DPT_SOLARIS) - #define DPTSQO - #define DPTSQC - #else - #define DPTSQO { - #define DPTSQC } - #endif /* solaris */ -#endif /* DPTSQO */ - - -/*---------------------- */ -/* OS dependent typedefs */ -/*---------------------- */ - -#if defined (_DPT_MSDOS) || defined (_DPT_SCO) - #define BYTE unsigned char - #define WORD unsigned short -#endif - -#ifndef _DPT_TYPEDEFS - #define _DPT_TYPEDEFS - typedef unsigned char uCHAR; - typedef unsigned short uSHORT; - typedef unsigned int uINT; - typedef unsigned long uLONG; - - typedef union { - uCHAR u8[4]; - uSHORT u16[2]; - uLONG u32; - } access_U; -#endif - -#if !defined (NULL) - #define NULL 0 -#endif - - -/*Prototypes - function ----------------------------------------------------- */ - -#ifdef __cplusplus - extern "C" { /* Declare all these functions as "C" functions */ -#endif - -/*------------------------ */ -/* Byte reversal functions */ -/*------------------------ */ - - /* Reverses the byte ordering of a 2 byte variable */ -#if (!defined(osdSwap2)) - uSHORT osdSwap2(DPT_UNALIGNED uSHORT *); -#endif // !osdSwap2 - - /* Reverses the byte ordering of a 4 byte variable and shifts left 8 bits */ -#if (!defined(osdSwap3)) - uLONG osdSwap3(DPT_UNALIGNED uLONG *); -#endif // !osdSwap3 - - -#ifdef _DPT_NETWARE - #include "novpass.h" /* For DPT_Bswapl() prototype */ - /* Inline the byte swap */ - #ifdef __cplusplus - inline uLONG osdSwap4(uLONG *inLong) { - return *inLong = DPT_Bswapl(*inLong); - } - #else - #define osdSwap4(inLong) DPT_Bswapl(inLong) - #endif // cplusplus -#else - /* Reverses the byte ordering of a 4 byte variable */ -# if (!defined(osdSwap4)) - uLONG osdSwap4(DPT_UNALIGNED uLONG *); -# endif // !osdSwap4 - - /* The following functions ALWAYS swap regardless of the * - * presence of DPT_BIG_ENDIAN */ - - uSHORT trueSwap2(DPT_UNALIGNED uSHORT *); - uLONG trueSwap4(DPT_UNALIGNED uLONG *); - -#endif // netware - - -/*-------------------------------------* - * Network order swap functions * - * * - * These functions/macros will be used * - * by the structure insert()/extract() * - * functions. * - * - * We will enclose all structure * - * portability modifications inside * - * #ifdefs. When we are ready, we * - * will #define DPT_PORTABLE to begin * - * using the modifications. * - *-------------------------------------*/ -uLONG netSwap4(uLONG val); - -#if defined (_DPT_BIG_ENDIAN) - -// for big-endian we need to swap - -#ifndef NET_SWAP_2 -#define NET_SWAP_2(x) (((x) >> 8) | ((x) << 8)) -#endif // NET_SWAP_2 - -#ifndef NET_SWAP_4 -#define NET_SWAP_4(x) netSwap4((x)) -#endif // NET_SWAP_4 - -#else - -// for little-endian we don't need to do anything - -#ifndef NET_SWAP_2 -#define NET_SWAP_2(x) (x) -#endif // NET_SWAP_2 - -#ifndef NET_SWAP_4 -#define NET_SWAP_4(x) (x) -#endif // NET_SWAP_4 - -#endif // big endian - - - -/*----------------------------------- */ -/* Run-time loadable module functions */ -/*----------------------------------- */ - - /* Loads the specified run-time loadable DLL */ -DLL_HANDLE_T osdLoadModule(uCHAR *); - /* Unloads the specified run-time loadable DLL */ -uSHORT osdUnloadModule(DLL_HANDLE_T); - /* Returns a pointer to a function inside a run-time loadable DLL */ -void * osdGetFnAddr(DLL_HANDLE_T,uCHAR *); - -/*--------------------------------------- */ -/* Mutually exclusive semaphore functions */ -/*--------------------------------------- */ - - /* Create a named semaphore */ -SEMAPHORE_T osdCreateNamedSemaphore(char *); - /* Create a mutually exlusive semaphore */ -SEMAPHORE_T osdCreateSemaphore(void); - /* create an event semaphore */ -SEMAPHORE_T osdCreateEventSemaphore(void); - /* create a named event semaphore */ -SEMAPHORE_T osdCreateNamedEventSemaphore(char *); - - /* Destroy the specified mutually exclusive semaphore object */ -uSHORT osdDestroySemaphore(SEMAPHORE_T); - /* Request access to the specified mutually exclusive semaphore */ -uLONG osdRequestSemaphore(SEMAPHORE_T,uLONG); - /* Release access to the specified mutually exclusive semaphore */ -uSHORT osdReleaseSemaphore(SEMAPHORE_T); - /* wait for a event to happen */ -uLONG osdWaitForEventSemaphore(SEMAPHORE_T, uLONG); - /* signal an event */ -uLONG osdSignalEventSemaphore(SEMAPHORE_T); - /* reset the event */ -uLONG osdResetEventSemaphore(SEMAPHORE_T); - -/*----------------- */ -/* Thread functions */ -/*----------------- */ - - /* Releases control to the task switcher in non-preemptive */ - /* multitasking operating systems. */ -void osdSwitchThreads(void); - - /* Starts a thread function */ -uLONG osdStartThread(void *,void *); - -/* what is my thread id */ -uLONG osdGetThreadID(void); - -/* wakes up the specifed thread */ -void osdWakeThread(uLONG); - -/* osd sleep for x miliseconds */ -void osdSleep(uLONG); - -#define DPT_THREAD_PRIORITY_LOWEST 0x00 -#define DPT_THREAD_PRIORITY_NORMAL 0x01 -#define DPT_THREAD_PRIORITY_HIGHEST 0x02 - -uCHAR osdSetThreadPriority(uLONG tid, uCHAR priority); - -#ifdef __cplusplus - } /* end the xtern "C" declaration */ -#endif - -#endif /* osd_util_h */ diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c --- a/drivers/scsi/dpt_i2o.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/dpt_i2o.c 2005-01-23 22:28:26 -08:00 @@ -1178,7 +1178,6 @@ // dangerous. status = -ETIME; } - schedule_timeout(timeout*HZ); } if(pHba->host) spin_lock_irq(pHba->host->host_lock); diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/hosts.c 2005-01-23 22:28:26 -08:00 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -79,15 +80,8 @@ set_bit(SHOST_DEL, &shost->shost_state); - if (shost->transportt->host_destroy) - shost->transportt->host_destroy(shost); + transport_unregister_device(&shost->shost_gendev); class_device_unregister(&shost->shost_classdev); - if (shost->transport_classdev.class) { - if (shost->transportt->host_statistics) - sysfs_remove_group(&shost->transport_classdev.kobj, - shost->transportt->host_statistics); - class_device_unregister(&shost->transport_classdev); - } device_del(&shost->shost_gendev); } EXPORT_SYMBOL(scsi_remove_host); @@ -135,9 +129,6 @@ GFP_KERNEL)) == NULL) goto out_del_classdev; - if (shost->transportt->host_setup) - shost->transportt->host_setup(shost); - error = scsi_sysfs_add_host(shost); if (error) goto out_destroy_host; @@ -146,8 +137,6 @@ return error; out_destroy_host: - if (shost->transportt->host_destroy) - shost->transportt->host_destroy(shost); out_del_classdev: class_device_del(&shost->shost_classdev); out_del_gendev: @@ -397,3 +386,9 @@ { class_unregister(&shost_class); } + +int scsi_is_host_device(const struct device *dev) +{ + return dev->release == scsi_host_dev_release; +} +EXPORT_SYMBOL(scsi_is_host_device); diff -Nru a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c --- a/drivers/scsi/jazz_esp.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/jazz_esp.c 2005-01-23 22:28:26 -08:00 @@ -6,6 +6,7 @@ * jazz_esp is based on David S. Miller's ESP driver and cyber_esp */ +#include #include #include #include @@ -27,7 +28,7 @@ #include static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp); static void dma_dump_state(struct NCR_ESP *esp); static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); @@ -36,11 +37,11 @@ static int dma_irq_p(struct NCR_ESP *esp); static int dma_ports_p(struct NCR_ESP *esp); static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); -static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_advance_sg (Scsi_Cmnd *sp); +static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp); +static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp); +static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp); +static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp); +static void dma_advance_sg (struct scsi_cmnd *sp); static void dma_led_off(struct NCR_ESP *); static void dma_led_on(struct NCR_ESP *); @@ -52,7 +53,7 @@ */ /***************************************************************** Detection */ -int jazz_esp_detect(Scsi_Host_Template *tpnt) +static int jazz_esp_detect(struct scsi_host_template *tpnt) { struct NCR_ESP *esp; struct ConfigDev *esp_dev; @@ -115,7 +116,7 @@ esp->esp_command = (volatile unsigned char *)cmd_buffer; /* get virtual dma address for command buffer */ - esp->esp_command_dvma = vdma_alloc(PHYSADDR(cmd_buffer), sizeof (cmd_buffer)); + esp->esp_command_dvma = vdma_alloc(CPHYSADDR(cmd_buffer), sizeof (cmd_buffer)); esp->irq = JAZZ_SCSI_IRQ; request_irq(JAZZ_SCSI_IRQ, esp_intr, SA_INTERRUPT, "JAZZ SCSI", @@ -157,7 +158,7 @@ return fifo_count; } -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp) { /* * maximum DMA size is 1MB @@ -230,43 +231,43 @@ } } -static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) +static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp) { - sp->SCp.have_data_in = vdma_alloc(PHYSADDR(sp->SCp.buffer), sp->SCp.this_residual); + sp->SCp.have_data_in = vdma_alloc(CPHYSADDR(sp->SCp.buffer), sp->SCp.this_residual); sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in); } -static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) +static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp) { int sz = sp->SCp.buffers_residual; - struct mmu_sglist *sg = (struct mmu_sglist *) sp->SCp.buffer; + struct scatterlist *sg = (struct scatterlist *) sp->SCp.buffer; while (sz >= 0) { - sg[sz].dvma_addr = vdma_alloc(PHYSADDR(sg[sz].addr), sg[sz].len); + sg[sz].dma_address = vdma_alloc(CPHYSADDR(page_address(sg[sz].page) + sg[sz].offset), sg[sz].length); sz--; } - sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address); + sp->SCp.ptr=(char *)(sp->SCp.buffer->dma_address); } -static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) +static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp) { vdma_free(sp->SCp.have_data_in); } -static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) +static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp) { int sz = sp->use_sg - 1; - struct mmu_sglist *sg = (struct mmu_sglist *)sp->buffer; + struct scatterlist *sg = (struct scatterlist *)sp->buffer; while(sz >= 0) { - vdma_free(sg[sz].dvma_addr); + vdma_free(sg[sz].dma_address); sz--; } } -static void dma_advance_sg (Scsi_Cmnd *sp) +static void dma_advance_sg (struct scsi_cmnd *sp) { - sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address); + sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); } #define JAZZ_HDC_LED 0xe000d100 /* FIXME, find correct address */ @@ -285,9 +286,9 @@ #endif } -static Scsi_Host_Template driver_template = { +static struct scsi_host_template driver_template = { .proc_name = "jazz_esp", - .proc_info = &esp_proc_info, + .proc_info = esp_proc_info, .name = "ESP 100/100a/200", .detect = jazz_esp_detect, .slave_alloc = esp_slave_alloc, @@ -303,4 +304,4 @@ .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, }; - +#include "scsi_module.c" diff -Nru a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c --- a/drivers/scsi/oktagon_esp.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/oktagon_esp.c 2005-01-23 22:28:26 -08:00 @@ -72,8 +72,6 @@ static void dma_advance_sg(Scsi_Cmnd *); static int oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x); -void esp_bootup_reset(struct NCR_ESP *esp,struct ESP_regs *eregs); - #ifdef USE_BOTTOM_HALF static void dma_commit(void *opaque); diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_debug.c 2005-01-23 22:28:26 -08:00 @@ -11,7 +11,7 @@ * (or disk like devices) sharing a common amount of RAM * * - * For documentation see http://www.torque.net/sg/sdebug25.html + * For documentation see http://www.torque.net/sg/sdebug26.html * * D. Gilbert (dpg) work for Magneto-Optical device test [20010421] * dpg: work for devfs large number of disks [20010809] @@ -56,7 +56,7 @@ #include "scsi_debug.h" #define SCSI_DEBUG_VERSION "1.75" -static const char * scsi_debug_version_date = "20041023"; +static const char * scsi_debug_version_date = "20050113"; /* Additional Sense Code (ASC) used */ #define NO_ADDED_SENSE 0x0 @@ -1675,6 +1675,7 @@ driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); + driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); @@ -1693,6 +1694,7 @@ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); + driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_error.c 2005-01-23 22:28:26 -08:00 @@ -1948,3 +1948,96 @@ sizeof(cmd->sense_buffer), sshdr); } EXPORT_SYMBOL(scsi_command_normalize_sense); + +/** + * scsi_sense_desc_find - search for a given descriptor type in + * descriptor sense data format. + * + * @sense_buffer: byte array of descriptor format sense data + * @sb_len: number of valid bytes in sense_buffer + * @desc_type: value of descriptor type to find + * (e.g. 0 -> information) + * + * Notes: + * only valid when sense data is in descriptor format + * + * Return value: + * pointer to start of (first) descriptor if found else NULL + **/ +const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, + int desc_type) +{ + int add_sen_len, add_len, desc_len, k; + const u8 * descp; + + if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7]))) + return NULL; + if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73)) + return NULL; + add_sen_len = (add_sen_len < (sb_len - 8)) ? + add_sen_len : (sb_len - 8); + descp = &sense_buffer[8]; + for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { + descp += desc_len; + add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; + desc_len = add_len + 2; + if (descp[0] == desc_type) + return descp; + if (add_len < 0) // short descriptor ?? + break; + } + return NULL; +} +EXPORT_SYMBOL(scsi_sense_desc_find); + +/** + * scsi_get_sense_info_fld - attempts to get information field from + * sense data (either fixed or descriptor format) + * + * @sense_buffer: byte array of sense data + * @sb_len: number of valid bytes in sense_buffer + * @info_out: pointer to 64 integer where 8 or 4 byte information + * field will be placed if found. + * + * Return value: + * 1 if information field found, 0 if not found. + **/ +int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, + u64 * info_out) +{ + int j; + const u8 * ucp; + u64 ull; + + if (sb_len < 7) + return 0; + switch (sense_buffer[0] & 0x7f) { + case 0x70: + case 0x71: + if (sense_buffer[0] & 0x80) { + *info_out = (sense_buffer[3] << 24) + + (sense_buffer[4] << 16) + + (sense_buffer[5] << 8) + sense_buffer[6]; + return 1; + } else + return 0; + case 0x72: + case 0x73: + ucp = scsi_sense_desc_find(sense_buffer, sb_len, + 0 /* info desc */); + if (ucp && (0xa == ucp[1])) { + ull = 0; + for (j = 0; j < 8; ++j) { + if (j > 0) + ull <<= 8; + ull |= ucp[4 + j]; + } + *info_out = ull; + return 1; + } else + return 0; + default: + return 0; + } +} +EXPORT_SYMBOL(scsi_get_sense_info_fld); diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_lib.c 2005-01-23 22:28:26 -08:00 @@ -498,19 +498,17 @@ /* * Function: scsi_end_request() * - * Purpose: Post-processing of completed commands called from interrupt - * handler or a bottom-half handler. + * Purpose: Post-processing of completed commands (usually invoked at end + * of upper level post-processing and scsi_io_completion). * * Arguments: cmd - command that is complete. - * uptodate - 1 if I/O indicates success, 0 for I/O error. - * sectors - number of sectors we want to mark. + * uptodate - 1 if I/O indicates success, <= 0 for I/O error. + * bytes - number of bytes of completed I/O * requeue - indicates whether we should requeue leftovers. - * frequeue - indicates that if we release the command block - * that the queue request function should be called. * * Lock status: Assumed that lock is not held upon entry. * - * Returns: Nothing + * Returns: cmd if requeue done or required, NULL otherwise * * Notes: This is called for block device requests in order to * mark some number of sectors as complete. @@ -694,8 +692,9 @@ int this_count = cmd->bufflen; request_queue_t *q = cmd->device->request_queue; struct request *req = cmd->request; - int clear_errors = 1; struct scsi_sense_hdr sshdr; + int sense_valid = 0; + int sense_deferred = 0; /* * Free up any indirection buffers we allocated for DMA purposes. @@ -714,11 +713,15 @@ kfree(cmd->buffer); } + if (result) { + sense_valid = scsi_command_normalize_sense(cmd, &sshdr); + if (sense_valid) + sense_deferred = scsi_sense_is_deferred(&sshdr); + } if (blk_pc_request(req)) { /* SG_IO ioctl from block level */ req->errors = result; if (result) { - clear_errors = 0; - if (scsi_command_normalize_sense(cmd, &sshdr)) { + if (sense_valid) { /* * SG_IO wants current and deferred errors */ @@ -742,6 +745,11 @@ cmd->request_buffer = NULL; cmd->request_bufflen = 0; + if (blk_pc_request(req)) { /* SG_IO ioctl from block level */ + scsi_end_request(cmd, 1, good_bytes, 0); + return; + } + /* * Next deal with any sectors which we were able to correctly * handle. @@ -751,8 +759,7 @@ req->nr_sectors, good_bytes)); SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); - if (clear_errors) - req->errors = 0; + req->errors = 0; /* * If multiple sectors are requested in one buffer, then * they will have been finished off by the first command. @@ -779,52 +786,37 @@ * sense buffer. We can extract information from this, so we * can choose a block to remap, etc. */ - if (driver_byte(result) != 0) { - if (scsi_command_normalize_sense(cmd, &sshdr) && - !scsi_sense_is_deferred(&sshdr)) { - /* - * If the device is in the process of becoming ready, - * retry. - */ - if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { + if (sense_valid && !sense_deferred) { + switch (sshdr.sense_key) { + case UNIT_ATTENTION: + if (cmd->device->removable) { + /* detected disc change. set a bit + * and quietly refuse further access. + */ + cmd->device->changed = 1; + cmd = scsi_end_request(cmd, 0, + this_count, 1); + return; + } else { + /* + * Must have been a power glitch, or a + * bus reset. Could not have been a + * media change, so we just retry the + * request and see what happens. + */ scsi_requeue_command(q, cmd); return; } - if (sshdr.sense_key == UNIT_ATTENTION) { - if (cmd->device->removable) { - /* detected disc change. set a bit - * and quietly refuse further access. - */ - cmd->device->changed = 1; - cmd = scsi_end_request(cmd, 0, - this_count, 1); - return; - } else { - /* - * Must have been a power glitch, or a - * bus reset. Could not have been a - * media change, so we just retry the - * request and see what happens. - */ - scsi_requeue_command(q, cmd); - return; - } - } - } - /* - * If we had an ILLEGAL REQUEST returned, then we may have - * performed an unsupported command. The only thing this - * should be would be a ten byte read where only a six byte - * read was supported. Also, on a system where READ CAPACITY - * failed, we may have read past the end of the disk. - */ - - /* - * XXX: Following is probably broken since deferred errors - * fall through [dpg 20040827] - */ - switch (sshdr.sense_key) { + break; case ILLEGAL_REQUEST: + /* + * If we had an ILLEGAL REQUEST returned, then we may + * have performed an unsupported command. The only + * thing this should be would be a ten byte read where + * only a six byte read was supported. Also, on a + * system where READ CAPACITY failed, we may have read + * past the end of the disk. + */ if (cmd->device->use_10_for_rw && (cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == WRITE_10)) { @@ -841,6 +833,14 @@ } break; case NOT_READY: + /* + * If the device is in the process of becoming ready, + * retry. + */ + if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { + scsi_requeue_command(q, cmd); + return; + } printk(KERN_INFO "Device %s not ready.\n", req->rq_disk ? req->rq_disk->disk_name : ""); cmd = scsi_end_request(cmd, 0, this_count, 1); diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h --- a/drivers/scsi/scsi_priv.h 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_priv.h 2005-01-23 22:28:26 -08:00 @@ -146,7 +146,7 @@ extern int scsi_sysfs_add_host(struct Scsi_Host *); extern int scsi_sysfs_register(void); extern void scsi_sysfs_unregister(void); -extern int scsi_sysfs_device_initialize(struct scsi_device *); +extern void scsi_sysfs_device_initialize(struct scsi_device *); extern int scsi_sysfs_target_initialize(struct scsi_device *); extern struct scsi_transport_template blank_transport_template; diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_scan.c 2005-01-23 22:28:26 -08:00 @@ -254,10 +254,7 @@ sdev->request_queue->queuedata = sdev; scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); - if (shost->transportt->device_setup) { - if (shost->transportt->device_setup(sdev)) - goto out_free_queue; - } + scsi_sysfs_device_initialize(sdev); if (shost->hostt->slave_alloc) { ret = shost->hostt->slave_alloc(sdev); @@ -272,10 +269,6 @@ } } - if (scsi_sysfs_device_initialize(sdev) != 0) - goto out_cleanup_slave; - - /* NOTE: this target initialisation code depends critically on * lun scanning being sequential. */ if (scsi_sysfs_target_initialize(sdev)) @@ -288,13 +281,11 @@ list_del(&sdev->siblings); list_del(&sdev->same_target_siblings); spin_unlock_irqrestore(shost->host_lock, flags); -out_cleanup_slave: + if (shost->hostt->slave_destroy) shost->hostt->slave_destroy(sdev); out_device_destroy: - if (shost->transportt->device_destroy) - shost->transportt->device_destroy(sdev); -out_free_queue: + transport_destroy_device(&sdev->sdev_gendev); scsi_free_queue(sdev->request_queue); out_free_dev: kfree(sdev); @@ -629,8 +620,7 @@ if (*bflags & BLIST_NOT_LOCKABLE) sdev->lockable = 0; - if (sdev->host->transportt->device_configure) - sdev->host->transportt->device_configure(sdev); + transport_configure_device(&sdev->sdev_gendev); if (sdev->host->hostt->slave_configure) sdev->host->hostt->slave_configure(sdev); @@ -749,8 +739,7 @@ } else { if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); - if (sdev->host->transportt->device_destroy) - sdev->host->transportt->device_destroy(sdev); + transport_destroy_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev); } out: @@ -1330,8 +1319,7 @@ if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); - if (sdev->host->transportt->device_destroy) - sdev->host->transportt->device_destroy(sdev); + transport_destroy_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev); } EXPORT_SYMBOL(scsi_free_host_dev); diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_sysfs.c 2005-01-23 22:28:26 -08:00 @@ -170,14 +170,12 @@ if (delete) { struct scsi_target *starget = to_scsi_target(parent); - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); if (!starget->create) { - if (shost->transportt->target_destroy) - shost->transportt->target_destroy(starget); + transport_remove_device(&starget->dev); device_del(parent); - if (starget->transport_classdev.class) - class_device_unregister(&starget->transport_classdev); } + transport_destroy_device(&starget->dev); + put_device(parent); } if (sdev->request_queue) @@ -553,7 +551,6 @@ **/ int scsi_sysfs_add_sdev(struct scsi_device *sdev) { - struct class_device_attribute **attrs; struct scsi_target *starget = sdev->sdev_target; struct Scsi_Host *shost = sdev->host; int error, i, create; @@ -570,31 +567,7 @@ printk(KERN_ERR "Target device_add failed\n"); return error; } - if (starget->transport_classdev.class) { - int i; - struct class_device_attribute **attrs = - sdev->host->transportt->target_attrs; - - error = class_device_add(&starget->transport_classdev); - if (error) { - dev_printk(KERN_ERR, &starget->dev, - "Target transport add failed\n"); - return error; - } - - /* take a reference for the transport_classdev; this - * is released by the transport_class .release */ - get_device(&starget->dev); - for (i = 0; attrs[i]; i++) { - error = class_device_create_file(&starget->transport_classdev, - attrs[i]); - if (error) { - dev_printk(KERN_ERR, &starget->dev, - "Target transport attr add failed\n"); - return error; - } - } - } + transport_add_device(&starget->dev); } if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) @@ -606,25 +579,15 @@ printk(KERN_INFO "error 1\n"); return error; } - error = class_device_add(&sdev->sdev_classdev); if (error) { printk(KERN_INFO "error 2\n"); goto clean_device; } + /* take a reference for the sdev_classdev; this is * released by the sdev_class .release */ get_device(&sdev->sdev_gendev); - if (sdev->transport_classdev.class) { - error = class_device_add(&sdev->transport_classdev); - if (error) - goto clean_device2; - /* take a reference for the transport_classdev; this - * is released by the transport_class .release */ - get_device(&sdev->sdev_gendev); - - } - if (sdev->host->hostt->sdev_attrs) { for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { error = attr_add(&sdev->sdev_gendev, @@ -650,27 +613,16 @@ } } - if (sdev->transport_classdev.class) { - attrs = sdev->host->transportt->device_attrs; - for (i = 0; attrs[i]; i++) { - error = class_device_create_file(&sdev->transport_classdev, - attrs[i]); - if (error) { - scsi_remove_device(sdev); - goto out; - } - } - } - + transport_add_device(&sdev->sdev_gendev); out: return error; - clean_device2: class_device_del(&sdev->sdev_classdev); clean_device: scsi_device_set_state(sdev, SDEV_CANCEL); device_del(&sdev->sdev_gendev); + transport_destroy_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev); return error; @@ -689,14 +641,11 @@ goto out; class_device_unregister(&sdev->sdev_classdev); - if (sdev->transport_classdev.class) - class_device_unregister(&sdev->transport_classdev); device_del(&sdev->sdev_gendev); scsi_device_set_state(sdev, SDEV_DEL); if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); - if (sdev->host->transportt->device_destroy) - sdev->host->transportt->device_destroy(sdev); + transport_unregister_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev); out: @@ -786,41 +735,11 @@ } } - class_device_initialize(&shost->transport_classdev); - shost->transport_classdev.class = shost->transportt->host_class; - shost->transport_classdev.dev = &shost->shost_gendev; - snprintf(shost->transport_classdev.class_id, BUS_ID_SIZE, - "host%d", shost->host_no); - - if (shost->transport_classdev.class) { - struct class_device_attribute **attrs = - shost->transportt->host_attrs; - error = class_device_add(&shost->transport_classdev); - if (error) - return error; - /* take a reference for the transport_classdev; this - * is released by the transport_class .release */ - get_device(&shost->shost_gendev); - for (i = 0; attrs[i]; i++) { - error = class_device_create_file(&shost->transport_classdev, - attrs[i]); - if (error) - return error; - } - - if (shost->transportt->host_statistics) { - error = sysfs_create_group( - &shost->transport_classdev.kobj, - shost->transportt->host_statistics); - if (error) - return error; - } - } - + transport_register_device(&shost->shost_gendev); return 0; } -int scsi_sysfs_device_initialize(struct scsi_device *sdev) +void scsi_sysfs_device_initialize(struct scsi_device *sdev) { device_initialize(&sdev->sdev_gendev); sdev->sdev_gendev.bus = &scsi_bus_type; @@ -836,14 +755,14 @@ "%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - class_device_initialize(&sdev->transport_classdev); - sdev->transport_classdev.dev = &sdev->sdev_gendev; - sdev->transport_classdev.class = sdev->host->transportt->device_class; - snprintf(sdev->transport_classdev.class_id, BUS_ID_SIZE, - "%d:%d:%d:%d", sdev->host->host_no, - sdev->channel, sdev->id, sdev->lun); - return 0; + transport_setup_device(&sdev->sdev_gendev); +} + +int scsi_is_sdev_device(const struct device *dev) +{ + return dev->release == scsi_device_dev_release; } +EXPORT_SYMBOL(scsi_is_sdev_device); int scsi_sysfs_target_initialize(struct scsi_device *sdev) { @@ -886,12 +805,6 @@ dev->release = scsi_target_dev_release; sprintf(dev->bus_id, "target%d:%d:%d", shost->host_no, sdev->channel, sdev->id); - class_device_initialize(&starget->transport_classdev); - starget->transport_classdev.dev = &starget->dev; - starget->transport_classdev.class = shost->transportt->target_class; - snprintf(starget->transport_classdev.class_id, BUS_ID_SIZE, - "target%d:%d:%d", - shost->host_no, sdev->channel, sdev->id); starget->id = sdev->id; starget->channel = sdev->channel; create = starget->create = 1; @@ -907,10 +820,16 @@ sdev->sdev_target = starget; list_add_tail(&sdev->siblings, &shost->__devices); spin_unlock_irqrestore(shost->host_lock, flags); - if (create && shost->transportt->target_setup) - shost->transportt->target_setup(starget); + if (create) + transport_setup_device(&starget->dev); return 0; } + +int scsi_is_target_device(const struct device *dev) +{ + return dev->release == scsi_target_dev_release; +} +EXPORT_SYMBOL(scsi_is_target_device); /* A blank transport template that is used in drivers that don't * yet implement Transport Attributes */ diff -Nru a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c --- a/drivers/scsi/scsi_transport_fc.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_transport_fc.c 2005-01-23 22:28:26 -08:00 @@ -180,8 +180,6 @@ -static void transport_class_release(struct class_device *class_dev); -static void host_class_release(struct class_device *class_dev); static void fc_timeout_blocked_host(void *data); static void fc_timeout_blocked_tgt(void *data); @@ -207,32 +205,9 @@ #define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) -struct class fc_transport_class = { - .name = "fc_transport", - .release = transport_class_release, -}; - -struct class fc_host_class = { - .name = "fc_host", - .release = host_class_release, -}; - -static __init int fc_transport_init(void) -{ - int error = class_register(&fc_host_class); - if (error) - return error; - return class_register(&fc_transport_class); -} - -static void __exit fc_transport_exit(void) -{ - class_unregister(&fc_transport_class); - class_unregister(&fc_host_class); -} - -static int fc_setup_starget_transport_attrs(struct scsi_target *starget) +static int fc_add_target(struct device *dev) { + struct scsi_target *starget = to_scsi_target(dev); /* * Set default values easily detected by the midlayer as * failure cases. The scsi lldd is responsible for initializing @@ -247,15 +222,24 @@ return 0; } -static void fc_destroy_starget(struct scsi_target *starget) +static int fc_remove_target(struct device *dev) { + struct scsi_target *starget = to_scsi_target(dev); /* Stop the target timer */ if (cancel_delayed_work(&fc_starget_dev_loss_work(starget))) flush_scheduled_work(); + return 0; } -static int fc_setup_host_transport_attrs(struct Scsi_Host *shost) +static DECLARE_TRANSPORT_CLASS(fc_transport_class, + "fc_transport", + fc_add_target, + fc_remove_target, + NULL); + +static int fc_add_host(struct device *dev) { + struct Scsi_Host *shost = dev_to_shost(dev); /* * Set default values easily detected by the midlayer as * failure cases. The scsi lldd is responsible for initializing @@ -297,26 +281,35 @@ return 0; } -static void fc_destroy_host(struct Scsi_Host *shost) +static int fc_remove_host(struct device *dev) { + struct Scsi_Host *shost = dev_to_shost(dev); /* Stop the host timer */ if (cancel_delayed_work(&fc_host_link_down_work(shost))) flush_scheduled_work(); + return 0; } -static void transport_class_release(struct class_device *class_dev) +static DECLARE_TRANSPORT_CLASS(fc_host_class, + "fc_host", + fc_add_host, + fc_remove_host, + NULL); + +static __init int fc_transport_init(void) { - struct scsi_target *starget = transport_class_to_starget(class_dev); - put_device(&starget->dev); + int error = transport_class_register(&fc_host_class); + if (error) + return error; + return transport_class_register(&fc_transport_class); } -static void host_class_release(struct class_device *class_dev) +static void __exit fc_transport_exit(void) { - struct Scsi_Host *shost = transport_class_to_shost(class_dev); - put_device(&shost->shost_gendev); + transport_class_unregister(&fc_transport_class); + transport_class_unregister(&fc_host_class); } - /* * Remote Port (Target) Attribute Management */ @@ -731,6 +724,35 @@ .attrs = fc_statistics_attrs, }; +static int fc_host_match(struct attribute_container *cont, + struct device *dev) +{ + struct Scsi_Host *shost; + + if (!scsi_is_host_device(dev)) + return 0; + + shost = dev_to_shost(dev); + if (!shost->transportt || shost->transportt->host_attrs.class + != &fc_host_class.class) + return 0; + return 1; +} + +static int fc_target_match(struct attribute_container *cont, + struct device *dev) +{ + struct Scsi_Host *shost; + + if (!scsi_is_target_device(dev)) + return 0; + + shost = dev_to_shost(dev->parent); + if (!shost->transportt || shost->transportt->host_attrs.class + != &fc_host_class.class) + return 0; + return 1; +} struct scsi_transport_template * @@ -745,16 +767,16 @@ memset(i, 0, sizeof(struct fc_internal)); - i->t.target_attrs = &i->starget_attrs[0]; - i->t.target_class = &fc_transport_class; - i->t.target_setup = &fc_setup_starget_transport_attrs; - i->t.target_destroy = &fc_destroy_starget; + i->t.target_attrs.attrs = &i->starget_attrs[0]; + i->t.target_attrs.class = &fc_transport_class.class; + i->t.target_attrs.match = fc_target_match; + attribute_container_register(&i->t.target_attrs); i->t.target_size = sizeof(struct fc_starget_attrs); - i->t.host_attrs = &i->host_attrs[0]; - i->t.host_class = &fc_host_class; - i->t.host_setup = &fc_setup_host_transport_attrs; - i->t.host_destroy = &fc_destroy_host; + i->t.host_attrs.attrs = &i->host_attrs[0]; + i->t.host_attrs.class = &fc_host_class.class; + i->t.host_attrs.match = fc_host_match; + attribute_container_register(&i->t.host_attrs); i->t.host_size = sizeof(struct fc_host_attrs); if (ft->get_fc_host_stats) diff -Nru a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c --- a/drivers/scsi/scsi_transport_iscsi.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_transport_iscsi.c 2005-01-23 22:28:26 -08:00 @@ -40,28 +40,17 @@ #define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t) -static void iscsi_transport_class_release(struct class_device *class_dev) -{ - struct scsi_target *starget = transport_class_to_starget(class_dev); - put_device(&starget->dev); -} - -struct class iscsi_transport_class = { - .name = "iscsi_transport_class", - .release = iscsi_transport_class_release, -}; - -static void iscsi_host_class_release(struct class_device *class_dev) -{ - struct Scsi_Host *shost = transport_class_to_shost(class_dev); - put_device(&shost->shost_gendev); -} - -struct class iscsi_host_class = { - .name = "iscsi_host", - .release = iscsi_host_class_release, -}; - +static DECLARE_TRANSPORT_CLASS(iscsi_transport_class, + "iscsi_transport", + NULL, + NULL, + NULL); + +static DECLARE_TRANSPORT_CLASS(iscsi_host_class, + "iscsi_host", + NULL, + NULL, + NULL); /* * iSCSI target and session attrs */ @@ -265,6 +254,36 @@ count++; \ } +static int iscsi_host_match(struct attribute_container *cont, + struct device *dev) +{ + struct Scsi_Host *shost; + + if (!scsi_is_host_device(dev)) + return 0; + + shost = dev_to_shost(dev); + if (!shost->transportt || shost->transportt->host_attrs.class + != &iscsi_host_class.class) + return 0; + return 1; +} + +static int iscsi_target_match(struct attribute_container *cont, + struct device *dev) +{ + struct Scsi_Host *shost; + + if (!scsi_is_target_device(dev)) + return 0; + + shost = dev_to_shost(dev->parent); + if (!shost->transportt || shost->transportt->host_attrs.class + != &iscsi_host_class.class) + return 0; + return 1; +} + struct scsi_transport_template * iscsi_attach_transport(struct iscsi_function_template *fnt) { @@ -278,9 +297,10 @@ memset(i, 0, sizeof(struct iscsi_internal)); i->fnt = fnt; - i->t.target_attrs = &i->session_attrs[0]; - i->t.target_class = &iscsi_transport_class; - i->t.target_setup = NULL; + i->t.target_attrs.attrs = &i->session_attrs[0]; + i->t.target_attrs.class = &iscsi_transport_class.class; + i->t.target_attrs.match = iscsi_target_match; + attribute_container_register(&i->t.target_attrs); i->t.target_size = sizeof(struct iscsi_class_session); SETUP_SESSION_RD_ATTR(tsih); @@ -307,9 +327,10 @@ BUG_ON(count > ISCSI_SESSION_ATTRS); i->session_attrs[count] = NULL; - i->t.host_attrs = &i->host_attrs[0]; - i->t.host_class = &iscsi_host_class; - i->t.host_setup = NULL; + i->t.host_attrs.attrs = &i->host_attrs[0]; + i->t.host_attrs.class = &iscsi_host_class.class; + i->t.host_attrs.match = iscsi_host_match; + attribute_container_register(&i->t.host_attrs); i->t.host_size = 0; count = 0; @@ -334,17 +355,17 @@ static __init int iscsi_transport_init(void) { - int err = class_register(&iscsi_transport_class); + int err = transport_class_register(&iscsi_transport_class); if (err) return err; - return class_register(&iscsi_host_class); + return transport_class_register(&iscsi_host_class); } static void __exit iscsi_transport_exit(void) { - class_unregister(&iscsi_host_class); - class_unregister(&iscsi_transport_class); + transport_class_unregister(&iscsi_host_class); + transport_class_unregister(&iscsi_transport_class); } module_init(iscsi_transport_init); diff -Nru a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c --- a/drivers/scsi/scsi_transport_spi.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/scsi_transport_spi.c 2005-01-23 22:28:26 -08:00 @@ -2,6 +2,7 @@ * Parallel SCSI (SPI) transport specific attributes exported to sysfs. * * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2004, 2005 James Bottomley * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,9 +38,6 @@ #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) -static void transport_class_release(struct class_device *class_dev); -static void host_class_release(struct class_device *class_dev); - #define SPI_NUM_ATTRS 10 /* increase this if you add attributes */ #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always * on" attributes */ @@ -119,40 +117,39 @@ return SPI_SIGNAL_UNKNOWN; } +static int spi_host_setup(struct device *dev) +{ + struct Scsi_Host *shost = dev_to_shost(dev); -struct class spi_transport_class = { - .name = "spi_transport", - .release = transport_class_release, -}; - -struct class spi_host_class = { - .name = "spi_host", - .release = host_class_release, -}; + spi_signalling(shost) = SPI_SIGNAL_UNKNOWN; -static __init int spi_transport_init(void) -{ - int error = class_register(&spi_host_class); - if (error) - return error; - return class_register(&spi_transport_class); + return 0; } -static void __exit spi_transport_exit(void) -{ - class_unregister(&spi_transport_class); - class_unregister(&spi_host_class); -} +static DECLARE_TRANSPORT_CLASS(spi_host_class, + "spi_host", + spi_host_setup, + NULL, + NULL); -static int spi_setup_host_attrs(struct Scsi_Host *shost) +static int spi_host_match(struct attribute_container *cont, + struct device *dev) { - spi_signalling(shost) = SPI_SIGNAL_UNKNOWN; + struct Scsi_Host *shost; - return 0; + if (!scsi_is_host_device(dev)) + return 0; + + shost = dev_to_shost(dev); + if (!shost->transportt || shost->transportt->host_attrs.class + != &spi_host_class.class) + return 0; + return 1; } -static int spi_configure_device(struct scsi_device *sdev) +static int spi_device_configure(struct device *dev) { + struct scsi_device *sdev = to_scsi_device(dev); struct scsi_target *starget = sdev->sdev_target; /* Populate the target capability fields with the values @@ -168,8 +165,10 @@ return 0; } -static int spi_setup_transport_attrs(struct scsi_target *starget) +static int spi_setup_transport_attrs(struct device *dev) { + struct scsi_target *starget = to_scsi_target(dev); + spi_period(starget) = -1; /* illegal value */ spi_offset(starget) = 0; /* async */ spi_width(starget) = 0; /* narrow */ @@ -187,18 +186,6 @@ return 0; } -static void transport_class_release(struct class_device *class_dev) -{ - struct scsi_target *starget = transport_class_to_starget(class_dev); - put_device(&starget->dev); -} - -static void host_class_release(struct class_device *class_dev) -{ - struct Scsi_Host *shost = transport_class_to_shost(class_dev); - put_device(&shost->shost_gendev); -} - #define spi_transport_show_function(field, format_string) \ \ static ssize_t \ @@ -823,6 +810,48 @@ i->host_attrs[count] = &i->private_host_attrs[count]; \ count++ +static int spi_device_match(struct attribute_container *cont, + struct device *dev) +{ + struct scsi_device *sdev; + struct Scsi_Host *shost; + + if (!scsi_is_sdev_device(dev)) + return 0; + + sdev = to_scsi_device(dev); + shost = sdev->host; + if (!shost->transportt || shost->transportt->host_attrs.class + != &spi_host_class.class) + return 0; + return 1; +} + +static int spi_target_match(struct attribute_container *cont, + struct device *dev) +{ + struct Scsi_Host *shost; + + if (!scsi_is_target_device(dev)) + return 0; + + shost = dev_to_shost(dev->parent); + if (!shost->transportt || shost->transportt->host_attrs.class + != &spi_host_class.class) + return 0; + return 1; +} + +static DECLARE_TRANSPORT_CLASS(spi_transport_class, + "spi_transport", + spi_setup_transport_attrs, + NULL, + NULL); + +static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class, + spi_device_match, + spi_device_configure); + struct scsi_transport_template * spi_attach_transport(struct spi_function_template *ft) { @@ -835,14 +864,15 @@ memset(i, 0, sizeof(struct spi_internal)); - i->t.target_attrs = &i->attrs[0]; - i->t.target_class = &spi_transport_class; - i->t.target_setup = &spi_setup_transport_attrs; - i->t.device_configure = &spi_configure_device; + i->t.target_attrs.class = &spi_transport_class.class; + i->t.target_attrs.attrs = &i->attrs[0]; + i->t.target_attrs.match = spi_target_match; + attribute_container_register(&i->t.target_attrs); i->t.target_size = sizeof(struct spi_transport_attrs); - i->t.host_attrs = &i->host_attrs[0]; - i->t.host_class = &spi_host_class; - i->t.host_setup = &spi_setup_host_attrs; + i->t.host_attrs.class = &spi_host_class.class; + i->t.host_attrs.attrs = &i->host_attrs[0]; + i->t.host_attrs.match = spi_host_match; + attribute_container_register(&i->t.host_attrs); i->t.host_size = sizeof(struct spi_host_attrs); i->f = ft; @@ -884,6 +914,21 @@ } EXPORT_SYMBOL(spi_release_transport); +static __init int spi_transport_init(void) +{ + int error = transport_class_register(&spi_transport_class); + if (error) + return error; + error = anon_transport_class_register(&spi_device_class); + return transport_class_register(&spi_host_class); +} + +static void __exit spi_transport_exit(void) +{ + transport_class_unregister(&spi_transport_class); + anon_transport_class_unregister(&spi_device_class); + transport_class_unregister(&spi_host_class); +} MODULE_AUTHOR("Martin Hicks"); MODULE_DESCRIPTION("SPI Transport Attributes"); diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/sd.c 2005-01-23 22:28:26 -08:00 @@ -87,6 +87,7 @@ * Number of allowed retries */ #define SD_MAX_RETRIES 5 +#define SD_PASSTHROUGH_RETRIES 1 static void scsi_disk_release(struct kref *kref); @@ -197,9 +198,11 @@ static void scsi_disk_put(struct scsi_disk *sdkp) { + struct scsi_device *sdev = sdkp->device; + down(&sd_ref_sem); kref_put(&sdkp->kref, scsi_disk_release); - scsi_device_put(sdkp->device); + scsi_device_put(sdev); up(&sd_ref_sem); } @@ -217,15 +220,14 @@ struct gendisk *disk; sector_t block; struct scsi_device *sdp = SCpnt->device; + struct request *rq = SCpnt->request; timeout = sdp->timeout; /* - * these are already setup, just copy cdb basically + * SG_IO from block layer already setup, just copy cdb basically */ - if (SCpnt->request->flags & REQ_BLOCK_PC) { - struct request *rq = SCpnt->request; - + if (blk_pc_request(rq)) { if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd)) return 0; @@ -242,26 +244,28 @@ timeout = rq->timeout; SCpnt->transfersize = rq->data_len; + SCpnt->allowed = SD_PASSTHROUGH_RETRIES; goto queue; } /* * we only do REQ_CMD and REQ_BLOCK_PC */ - if (!(SCpnt->request->flags & REQ_CMD)) + if (!blk_fs_request(rq)) return 0; - disk = SCpnt->request->rq_disk; - block = SCpnt->request->sector; + disk = rq->rq_disk; + block = rq->sector; this_count = SCpnt->request_bufflen >> 9; SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, " - "count=%d\n", disk->disk_name, (unsigned long long)block, this_count)); + "count=%d\n", disk->disk_name, + (unsigned long long)block, this_count)); if (!sdp || !scsi_device_online(sdp) || - block + SCpnt->request->nr_sectors > get_capacity(disk)) { + block + rq->nr_sectors > get_capacity(disk)) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", - SCpnt->request->nr_sectors)); + rq->nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); return 0; } @@ -289,7 +293,7 @@ * for this. */ if (sdp->sector_size == 1024) { - if ((block & 1) || (SCpnt->request->nr_sectors & 1)) { + if ((block & 1) || (rq->nr_sectors & 1)) { printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { @@ -298,7 +302,7 @@ } } if (sdp->sector_size == 2048) { - if ((block & 3) || (SCpnt->request->nr_sectors & 3)) { + if ((block & 3) || (rq->nr_sectors & 3)) { printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { @@ -307,7 +311,7 @@ } } if (sdp->sector_size == 4096) { - if ((block & 7) || (SCpnt->request->nr_sectors & 7)) { + if ((block & 7) || (rq->nr_sectors & 7)) { printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { @@ -315,25 +319,24 @@ this_count = this_count >> 3; } } - if (rq_data_dir(SCpnt->request) == WRITE) { + if (rq_data_dir(rq) == WRITE) { if (!sdp->writeable) { return 0; } SCpnt->cmnd[0] = WRITE_6; SCpnt->sc_data_direction = DMA_TO_DEVICE; - } else if (rq_data_dir(SCpnt->request) == READ) { + } else if (rq_data_dir(rq) == READ) { SCpnt->cmnd[0] = READ_6; SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { - printk(KERN_ERR "sd: Unknown command %lx\n", - SCpnt->request->flags); -/* overkill panic("Unknown sd command %lx\n", SCpnt->request->flags); */ + printk(KERN_ERR "sd: Unknown command %lx\n", rq->flags); +/* overkill panic("Unknown sd command %lx\n", rq->flags); */ return 0; } SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", - disk->disk_name, (rq_data_dir(SCpnt->request) == WRITE) ? - "writing" : "reading", this_count, SCpnt->request->nr_sectors)); + disk->disk_name, (rq_data_dir(rq) == WRITE) ? + "writing" : "reading", this_count, rq->nr_sectors)); SCpnt->cmnd[1] = 0; @@ -385,9 +388,9 @@ */ SCpnt->transfersize = sdp->sector_size; SCpnt->underflow = this_count << 9; + SCpnt->allowed = SD_MAX_RETRIES; queue: - SCpnt->allowed = SD_MAX_RETRIES; SCpnt->timeout_per_command = timeout; /* @@ -760,15 +763,26 @@ int this_count = SCpnt->bufflen; int good_bytes = (result == 0 ? this_count : 0); sector_t block_sectors = 1; + u64 first_err_block; sector_t error_sector; + struct scsi_sense_hdr sshdr; + int sense_valid = 0; + int sense_deferred = 0; + int info_valid; + + if (result) { + sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); + if (sense_valid) + sense_deferred = scsi_sense_is_deferred(&sshdr); + } + #ifdef CONFIG_SCSI_LOGGING SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", SCpnt->request->rq_disk->disk_name, result)); - if (0 != result) { - SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]" - "=%x,%x,%x,%x\n", SCpnt->sense_buffer[0], - SCpnt->sense_buffer[2], SCpnt->sense_buffer[12], - SCpnt->sense_buffer[13])); + if (sense_valid) { + SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc," + "ascq]=%x,%x,%x,%x\n", sshdr.response_code, + sshdr.sense_key, sshdr.asc, sshdr.ascq)); } #endif /* @@ -777,19 +791,27 @@ unnecessary additional work such as memcpy's that could be avoided. */ - /* An error occurred */ - if (driver_byte(result) != 0 && /* An error occurred */ - (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */ - switch (SCpnt->sense_buffer[2]) { + /* + * If SG_IO from block layer then set good_bytes to stop retries; + * else if errors, check them, and if necessary prepare for + * (partial) retries. + */ + if (blk_pc_request(SCpnt->request)) + good_bytes = this_count; + else if (driver_byte(result) != 0 && + sense_valid && !sense_deferred) { + switch (sshdr.sense_key) { case MEDIUM_ERROR: - if (!(SCpnt->sense_buffer[0] & 0x80)) - break; if (!blk_fs_request(SCpnt->request)) break; - error_sector = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | - SCpnt->sense_buffer[6]; + info_valid = scsi_get_sense_info_fld( + SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE, + &first_err_block); + /* + * May want to warn and skip if following cast results + * in actual truncation (if sector_t < 64 bits) + */ + error_sector = (sector_t)first_err_block; if (SCpnt->request->bio != NULL) block_sectors = bio_sectors(SCpnt->request->bio); switch (SCpnt->device->sector_size) { @@ -829,7 +851,7 @@ */ scsi_print_sense("sd", SCpnt); SCpnt->result = 0; - SCpnt->sense_buffer[0] = 0x0; + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); good_bytes = this_count; break; @@ -858,16 +880,20 @@ static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp) { + struct scsi_sense_hdr sshdr; + if (!srp->sr_result) return 0; if (!(driver_byte(srp->sr_result) & DRIVER_SENSE)) return 0; - if (srp->sr_sense_buffer[2] != NOT_READY && - srp->sr_sense_buffer[2] != UNIT_ATTENTION) - return 0; - if (srp->sr_sense_buffer[12] != 0x3A) /* medium not present */ - return 0; - + /* not invoked for commands that could return deferred errors */ + if (scsi_request_normalize_sense(srp, &sshdr)) { + if (sshdr.sense_key != NOT_READY && + sshdr.sense_key != UNIT_ATTENTION) + return 0; + if (sshdr.asc != 0x3A) /* medium not present */ + return 0; + } set_media_not_present(sdkp); return 1; } @@ -882,6 +908,8 @@ unsigned long spintime_value = 0; int retries, spintime; unsigned int the_result; + struct scsi_sense_hdr sshdr; + int sense_valid = 0; spintime = 0; @@ -895,19 +923,22 @@ memset((void *) &cmd[1], 0, 9); SRpnt->sr_cmd_len = 0; - SRpnt->sr_sense_buffer[0] = 0; - SRpnt->sr_sense_buffer[2] = 0; + memset(SRpnt->sr_sense_buffer, 0, + SCSI_SENSE_BUFFERSIZE); SRpnt->sr_data_direction = DMA_NONE; scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); the_result = SRpnt->sr_result; + if (the_result) + sense_valid = scsi_request_normalize_sense( + SRpnt, &sshdr); retries++; } while (retries < 3 && (!scsi_status_is_good(the_result) || ((driver_byte(the_result) & DRIVER_SENSE) && - SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION))); + sense_valid && sshdr.sense_key == UNIT_ATTENTION))); /* * If the drive has indicated to us that it doesn't have @@ -921,7 +952,8 @@ /* no sense, TUR either succeeded or failed * with a status error */ if(!spintime && !scsi_status_is_good(the_result)) - printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", diskname, the_result); + printk(KERN_NOTICE "%s: Unit Not Ready, " + "error = 0x%x\n", diskname, the_result); break; } @@ -936,15 +968,15 @@ * If manual intervention is required, or this is an * absent USB storage device, a spinup is meaningless. */ - if (SRpnt->sr_sense_buffer[2] == NOT_READY && - SRpnt->sr_sense_buffer[12] == 4 /* not ready */ && - SRpnt->sr_sense_buffer[13] == 3) { + if (sense_valid && + sshdr.sense_key == NOT_READY && + sshdr.asc == 4 && sshdr.ascq == 3) { break; /* manual intervention required */ /* * Issue command to spin up drive when not ready */ - } else if (SRpnt->sr_sense_buffer[2] == NOT_READY) { + } else if (sense_valid && sshdr.sense_key == NOT_READY) { if (!spintime) { printk(KERN_NOTICE "%s: Spinning up disk...", diskname); @@ -953,8 +985,8 @@ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ SRpnt->sr_cmd_len = 0; - SRpnt->sr_sense_buffer[0] = 0; - SRpnt->sr_sense_buffer[2] = 0; + memset(SRpnt->sr_sense_buffer, 0, + SCSI_SENSE_BUFFERSIZE); SRpnt->sr_data_direction = DMA_NONE; scsi_wait_req(SRpnt, (void *)cmd, @@ -970,7 +1002,8 @@ /* we don't understand the sense code, so it's * probably pointless to loop */ if(!spintime) { - printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", diskname); + printk(KERN_NOTICE "%s: Unit Not Ready, " + "sense:\n", diskname); scsi_print_req_sense("", SRpnt); } break; @@ -998,6 +1031,8 @@ int the_result, retries; int sector_size = 0; int longrc = 0; + struct scsi_sense_hdr sshdr; + int sense_valid = 0; repeat: retries = 3; @@ -1015,8 +1050,7 @@ } SRpnt->sr_cmd_len = 0; - SRpnt->sr_sense_buffer[0] = 0; - SRpnt->sr_sense_buffer[2] = 0; + memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); SRpnt->sr_data_direction = DMA_FROM_DEVICE; scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, @@ -1026,6 +1060,9 @@ return; the_result = SRpnt->sr_result; + if (the_result) + sense_valid = scsi_request_normalize_sense(SRpnt, + &sshdr); retries--; } while (the_result && retries); @@ -1047,7 +1084,7 @@ /* Set dirty bit for removable devices if not ready - * sometimes drives will not report this properly. */ if (sdp->removable && - SRpnt->sr_sense_buffer[2] == NOT_READY) + sense_valid && sshdr.sense_key == NOT_READY) sdp->changed = 1; /* Either no media are present but the drive didn't tell us, @@ -1255,6 +1292,7 @@ const int dbd = 0; /* DBD */ const int modepage = 0x08; /* current values, cache page */ struct scsi_mode_data data; + struct scsi_sense_hdr sshdr; if (sdkp->device->skip_ms_page_8) goto defaults; @@ -1304,17 +1342,14 @@ } bad_sense: - if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 - && (SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST - /* ASC 0x24 ASCQ 0x00: Invalid field in CDB */ - && SRpnt->sr_sense_buffer[12] == 0x24 - && SRpnt->sr_sense_buffer[13] == 0x00) { + if (scsi_request_normalize_sense(SRpnt, &sshdr) && + sshdr.sense_key == ILLEGAL_REQUEST && + sshdr.asc == 0x24 && sshdr.ascq == 0x0) printk(KERN_NOTICE "%s: cache data unavailable\n", - diskname); - } else { + diskname); /* Invalid field in CDB */ + else printk(KERN_ERR "%s: asking for cache data failed\n", diskname); - } defaults: printk(KERN_ERR "%s: assuming drive cache: write through\n", diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/sg.c 2005-01-23 22:28:26 -08:00 @@ -7,7 +7,7 @@ * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2004 Douglas Gilbert + * Copyright (C) 1998 - 2005 Douglas Gilbert * * Modified 19-JAN-1998 Richard Gooch Devfs support * @@ -18,8 +18,8 @@ * */ -static int sg_version_num = 30531; /* 2 digits for each component */ -#define SG_VERSION_STR "3.5.31" +static int sg_version_num = 30532; /* 2 digits for each component */ +#define SG_VERSION_STR "3.5.32" /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: @@ -60,7 +60,7 @@ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20040516"; +static char *sg_version_date = "20050117"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -1282,6 +1282,8 @@ srp->header.duration = jiffies_to_msecs(jiffies - srp->header.duration); if (0 != SRpnt->sr_result) { + struct scsi_sense_hdr sshdr; + memcpy(srp->sense_b, SRpnt->sr_sense_buffer, sizeof (srp->sense_b)); srp->header.status = 0xff & SRpnt->sr_result; @@ -1296,11 +1298,12 @@ /* Following if statement is a patch supplied by Eric Youngdale */ if (driver_byte(SRpnt->sr_result) != 0 - && (SRpnt->sr_sense_buffer[0] & 0x7f) == 0x70 - && (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION + && scsi_command_normalize_sense(SCpnt, &sshdr) + && !scsi_sense_is_deferred(&sshdr) + && sshdr.sense_key == UNIT_ATTENTION && sdp->device->removable) { - /* Detected disc change. Set the bit - this may be used if */ - /* there are filesystems using this device. */ + /* Detected possible disc change. Set the bit - this */ + /* may be used if there are filesystems using this device */ sdp->device->changed = 1; } } @@ -1573,8 +1576,8 @@ * of sysfs parameters (which module_param doesn't yet support). * Sysfs parameters defined explicitly below. */ -module_param_named(def_reserved_size, def_reserved_size, int, 0); -module_param_named(allow_dio, sg_allow_dio, int, 0); +module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO); +module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); MODULE_AUTHOR("Douglas Gilbert"); MODULE_DESCRIPTION("SCSI generic (sg) driver"); @@ -2606,9 +2609,14 @@ free_pages((unsigned long) buff, order); } +#ifndef MAINTENANCE_IN_CMD +#define MAINTENANCE_IN_CMD 0xa3 +#endif + static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE, INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, - MODE_SENSE, MODE_SENSE_10, LOG_SENSE + READ_16, MODE_SENSE, MODE_SENSE_10, LOG_SENSE, REPORT_LUNS, + SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG, MAINTENANCE_IN_CMD }; static int diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c 2005-01-23 22:28:26 -08:00 +++ b/drivers/scsi/sr.c 2005-01-23 22:28:26 -08:00 @@ -152,9 +152,11 @@ static inline void scsi_cd_put(struct scsi_cd *cd) { + struct scsi_device *sdev = cd->device; + down(&sr_ref_sem); kref_put(&cd->kref, sr_kref_release); - scsi_device_put(cd->device); + scsi_device_put(sdev); up(&sr_ref_sem); } diff -Nru a/include/linux/attribute_container.h b/include/linux/attribute_container.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/linux/attribute_container.h 2005-01-23 22:28:26 -08:00 @@ -0,0 +1,61 @@ +/* + * class_container.h - a generic container for all classes + * + * Copyright (c) 2005 - James Bottomley + * + * This file is licensed under GPLv2 + */ + +#ifndef _ATTRIBUTE_CONTAINER_H_ +#define _ATTRIBUTE_CONTAINER_H_ + +#include +#include + +struct attribute_container { + struct list_head node; + struct list_head containers; + struct class *class; + struct class_device_attribute **attrs; + int (*match)(struct attribute_container *, struct device *); +#define ATTRIBUTE_CONTAINER_NO_CLASSDEVS 0x01 + unsigned long flags; +}; + +static inline int +attribute_container_no_classdevs(struct attribute_container *atc) +{ + return atc->flags & ATTRIBUTE_CONTAINER_NO_CLASSDEVS; +} + +static inline void +attribute_container_set_no_classdevs(struct attribute_container *atc) +{ + atc->flags |= ATTRIBUTE_CONTAINER_NO_CLASSDEVS; +} + +int attribute_container_register(struct attribute_container *cont); +int attribute_container_unregister(struct attribute_container *cont); +void attribute_container_create_device(struct device *dev, + int (*fn)(struct attribute_container *, + struct device *, + struct class_device *)); +void attribute_container_add_device(struct device *dev, + int (*fn)(struct attribute_container *, + struct device *, + struct class_device *)); +void attribute_container_remove_device(struct device *dev, + void (*fn)(struct attribute_container *, + struct device *, + struct class_device *)); +void attribute_container_device_trigger(struct device *dev, + int (*fn)(struct attribute_container *, + struct device *, + struct class_device *)); +void attribute_container_trigger(struct device *dev, + int (*fn)(struct attribute_container *, + struct device *)); + +struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev); + +#endif diff -Nru a/include/linux/transport_class.h b/include/linux/transport_class.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/linux/transport_class.h 2005-01-23 22:28:26 -08:00 @@ -0,0 +1,77 @@ +/* + * transport_class.h - a generic container for all transport classes + * + * Copyright (c) 2005 - James Bottomley + * + * This file is licensed under GPLv2 + */ + +#ifndef _TRANSPORT_CLASS_H_ +#define _TRANSPORT_CLASS_H_ + +#include +#include + +struct transport_class { + struct class class; + int (*setup)(struct device *); + int (*configure)(struct device *); + int (*remove)(struct device *); +}; + +#define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg) \ +struct transport_class cls = { \ + .class = { \ + .name = nm, \ + }, \ + .setup = su, \ + .remove = rm, \ + .configure = cfg, \ +} + + +struct anon_transport_class { + struct transport_class tclass; + struct attribute_container container; +}; + +#define DECLARE_ANON_TRANSPORT_CLASS(cls, mtch, cfg) \ +struct anon_transport_class cls = { \ + .tclass = { \ + .configure = cfg, \ + }, \ + . container = { \ + .match = mtch, \ + }, \ +} + +#define class_to_transport_class(x) \ + container_of(x, struct transport_class, class) + +void transport_remove_device(struct device *); +void transport_add_device(struct device *); +void transport_setup_device(struct device *); +void transport_configure_device(struct device *); +void transport_destroy_device(struct device *); + +static inline void +transport_register_device(struct device *dev) +{ + transport_setup_device(dev); + transport_add_device(dev); +} + +static inline void +transport_unregister_device(struct device *dev) +{ + transport_remove_device(dev); + transport_destroy_device(dev); +} + +int transport_class_register(struct transport_class *); +int anon_transport_class_register(struct anon_transport_class *); +void transport_class_unregister(struct transport_class *); +void anon_transport_class_unregister(struct anon_transport_class *); + + +#endif diff -Nru a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h --- a/include/scsi/scsi_device.h 2005-01-23 22:28:26 -08:00 +++ b/include/scsi/scsi_device.h 2005-01-23 22:28:26 -08:00 @@ -123,8 +123,6 @@ struct device sdev_gendev; struct class_device sdev_classdev; - struct class_device transport_classdev; - enum scsi_device_state sdev_state; unsigned long sdev_data[0]; } __attribute__((aligned(sizeof(unsigned long)))); @@ -133,7 +131,7 @@ #define class_to_sdev(d) \ container_of(d, struct scsi_device, sdev_classdev) #define transport_class_to_sdev(class_dev) \ - container_of(class_dev, struct scsi_device, transport_classdev) + to_scsi_device(class_dev->dev) /* * scsi_target: representation of a scsi target, for now, this is only @@ -146,7 +144,6 @@ unsigned int channel; unsigned int id; /* target id ... replace * scsi_device.id eventually */ - struct class_device transport_classdev; unsigned long create:1; /* signal that it needs to be added */ unsigned long starget_data[0]; } __attribute__((aligned(sizeof(unsigned long)))); @@ -157,7 +154,7 @@ return to_scsi_target(sdev->sdev_gendev.parent); } #define transport_class_to_starget(class_dev) \ - container_of(class_dev, struct scsi_target, transport_classdev) + to_scsi_target(class_dev->dev) extern struct scsi_device *__scsi_add_device(struct Scsi_Host *, uint, uint, uint, void *hostdata); @@ -226,6 +223,8 @@ extern void scsi_target_quiesce(struct scsi_target *); extern void scsi_target_resume(struct scsi_target *); extern const char *scsi_device_state_name(enum scsi_device_state); +extern int scsi_is_sdev_device(const struct device *); +extern int scsi_is_target_device(const struct device *); static inline int scsi_device_online(struct scsi_device *sdev) { return sdev->sdev_state != SDEV_OFFLINE; diff -Nru a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h --- a/include/scsi/scsi_eh.h 2005-01-23 22:28:26 -08:00 +++ b/include/scsi/scsi_eh.h 2005-01-23 22:28:26 -08:00 @@ -44,6 +44,12 @@ { return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1)); } + +extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, + int desc_type); + +extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, + u64 * info_out); /* * Reset request from external source diff -Nru a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h --- a/include/scsi/scsi_host.h 2005-01-23 22:28:26 -08:00 +++ b/include/scsi/scsi_host.h 2005-01-23 22:28:26 -08:00 @@ -71,7 +71,18 @@ * Status: OPTIONAL */ int (* ioctl)(struct scsi_device *dev, int cmd, void __user *arg); - + + +#ifdef CONFIG_COMPAT + /* + * Compat handler. Handle 32bit ABI. + * When unknown ioctl is passed return -ENOIOCTLCMD. + * + * Status: OPTIONAL + */ + int (* compat_ioctl)(struct scsi_device *dev, int cmd, void __user *arg); +#endif + /* * The queuecommand function is used to queue up a scsi * command block to the LLDD. When the driver finished @@ -528,7 +539,6 @@ * separately */ void *shost_data; - struct class_device transport_classdev; /* * We should ensure that this is aligned, both for better performance @@ -542,8 +552,6 @@ container_of(d, struct Scsi_Host, shost_gendev) #define class_to_shost(d) \ container_of(d, struct Scsi_Host, shost_classdev) -#define transport_class_to_shost(class_dev) \ - container_of(class_dev, struct Scsi_Host, transport_classdev) extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); @@ -578,6 +586,7 @@ extern void scsi_unblock_requests(struct Scsi_Host *); extern void scsi_block_requests(struct Scsi_Host *); +struct class_container; /* * These two functions are used to allocate and free a pseudo device * which will connect to the host adapter itself rather than any @@ -587,6 +596,8 @@ */ extern void scsi_free_host_dev(struct scsi_device *); extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *); +int scsi_is_host_device(const struct device *); + /* legacy interfaces */ extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int); diff -Nru a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h --- a/include/scsi/scsi_transport.h 2005-01-23 22:28:26 -08:00 +++ b/include/scsi/scsi_transport.h 2005-01-23 22:28:26 -08:00 @@ -20,31 +20,16 @@ #ifndef SCSI_TRANSPORT_H #define SCSI_TRANSPORT_H -struct scsi_transport_template { - /* The NULL terminated list of transport attributes - * that should be exported. - */ - struct class_device_attribute **device_attrs; - struct class_device_attribute **target_attrs; - struct class_device_attribute **host_attrs; - +#include - /* The transport class that the device is in */ - struct class *device_class; - struct class *target_class; - struct class *host_class; +struct scsi_transport_template { + /* The statistics attached to the host class only */ struct attribute_group *host_statistics; - /* Constructor functions */ - int (*device_setup)(struct scsi_device *); - int (*device_configure)(struct scsi_device *); - int (*target_setup)(struct scsi_target *); - int (*host_setup)(struct Scsi_Host *); - - /* Destructor functions */ - void (*device_destroy)(struct scsi_device *); - void (*target_destroy)(struct scsi_target *); - void (*host_destroy)(struct Scsi_Host *); + /* the attribute containers */ + struct attribute_container host_attrs; + struct attribute_container target_attrs; + struct attribute_container device_attrs; /* The size of the specific transport attribute structure (a * space of this size will be left at the end of the @@ -53,5 +38,9 @@ int target_size; int host_size; }; + +#define transport_class_to_shost(tc) \ + dev_to_shost((tc)->dev) + #endif /* SCSI_TRANSPORT_H */ diff -Nru a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h --- a/include/scsi/scsi_transport_spi.h 2005-01-23 22:28:26 -08:00 +++ b/include/scsi/scsi_transport_spi.h 2005-01-23 22:28:26 -08:00 @@ -21,6 +21,7 @@ #define SCSI_TRANSPORT_SPI_H #include +#include struct scsi_transport_template;