GIT 9dd15a13b332e9f5c8ee752b1ccd9b84cb5bdf17 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git commit 9dd15a13b332e9f5c8ee752b1ccd9b84cb5bdf17 Author: James Bottomley Date: Sat Nov 24 19:55:53 2007 +0200 [SCSI] fix domain validation to work again commit 8655a546c83fc43f0a73416bbd126d02de7ad6c0 effectively altered the meaning of REQ_FAILFAST so that it now causes failures on over depth and other initial requeue conditions. Applications (like DV) which use it to mean curtail error handling aren't set up to handle failures in queueing conditions (and even if they were, it's not clear from the return whether it's a queueing problem or a curtailed error recovery). Hack this by preventing some of the error returns if REQ_PREEMPT (which DV uses) is set. Signed-off-by: James Bottomley commit 983289045faa96fba8841d3c51b98bb8623d9504 Author: James Bottomley Date: Sat Nov 24 19:47:25 2007 +0200 [SCSI] fix up REQ_FASTFAIL not to fail when state is QUIESCE commit 8655a546c83fc43f0a73416bbd126d02de7ad6c0 changed the way state BLOCKED works to fail immediately for REQ_FASTFAIL. Unfortunately, this also affected the QUIESCED state that DV uses, so separate QUIESCED and BLOCKED so as not to fail on REQ_FASTFAIL in QUIESCED state. Signed-off-by: James Bottomley commit f7f6f9c9ee6e557758088aba8ce89ec4be3f9cca Author: Andrew Vasquez Date: Mon Nov 12 10:31:00 2007 -0800 [SCSI] qla2xxx: Update version number to 8.02.00-k6. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit f5741085b96c09079cc3ad6d755682e86a58134b Author: Shyam Sundar Date: Mon Nov 12 10:30:59 2007 -0800 [SCSI] qla2xxx: Properly handle Vport state-change-notifications. Drivers do SCRs for each Vport. When something changes in the fabric, firmware generates one interrupt for each RSCN. Based on the current implementation, in each case, we make recursive calls to handle RSCN for physical and each subsequent virtual ports. The fix is to also take into consideration the vp_idx, which is set by the firmware to indicate the vport the RSCN was meant for. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 934fac3c6b63e04a75e1865c98218d9b98f90f1d Author: Andrew Vasquez Date: Mon Nov 12 10:30:58 2007 -0800 [SCSI] qla2xxx: Correct NPIV support for recent ISPs. Firmware will export to software the maximum number of vports supported for any given firmware version and ISP type. Use this information rather than the current hardcoding of limitations within the driver. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit c3192cfebd802277d845486741920ab53ec86684 Author: Andrew Vasquez Date: Mon Nov 12 10:30:57 2007 -0800 [SCSI] qla2xxx: Don't explicitly read mbx registers while processing a system-error. Callers of qla2x00_async_event() already populate the mb[] array upon invocation, doing so via the appropriate mailbox register accessors. The stale codes removed are leftover-bits kept during the FWI2 transition. Though relatively benign, the extra-reads are not valid for FWI2 boards (ISP24xx and above) and peek into the incorrect regions of registers. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 5db523de6cce2e474bb263ab806a1b8a13bd2e8a Author: Robert Jennings Date: Mon Nov 12 09:00:23 2007 -0600 [SCSI] ibmvscsi: requeue while CRQ closed CRQ send errors that return with H_CLOSED should return with SCSI_MLQUEUE_HOST_BUSY until firmware alerts the client of a CRQ transport event. The transport event will either reinitialize and requeue the requests or fail and return IO with DID_ERROR. To avoid failing the eh_* functions while re-attaching to the server adapter this will retry for a period of time while ibmvscsi_send_srp_event returns SCSI_MLQUEUE_HOST_BUSY. In ibmvscsi_eh_abort_handler() the loop includes the search of the event list. The lock on the hostdata is dropped while waiting to try again after failing ibmvscsi_send_srp_event. The event could have been purged if a login was in progress when the function was called. In ibmvscsi_eh_device_reset_handler() the loop includes the call to get_event_struct() because a failing call to ibmvscsi_send_srp_event() will have freed the event struct. Signed-off-by: Robert Jennings Signed-off-by: Brian King Signed-off-by: James Bottomley commit 3c020fc76bec7bec22d9553d191ea53cc65eef03 Author: Randy Dunlap Date: Thu Nov 15 15:42:30 2007 -0800 [SCSI] docbook and kernel-doc updates - Change title to remove "Mid-Layer" since the doc is about all of the SCSI layers. - Use "SCSI" instead of "scsi" in docbook text. - Use "*/" to end kernel-doc notation blocks. - A few other minor typo fixes. Signed-off-by: Randy Dunlap Signed-off-by: James Bottomley commit df6da98f7e7c1f5fe48c7f2a1403d82c7e8a5749 Author: Randy Dunlap Date: Thu Nov 15 17:07:28 2007 -0800 [SCSI] kernel-doc: use correct function name Use correct function name in kernel-doc. Signed-off-by: Randy Dunlap Signed-off-by: James Bottomley commit b11617c0c6cf19daef1c65bddadaf3283c07d374 Author: Randy Dunlap Date: Wed Nov 14 16:52:25 2007 -0800 [SCSI] boot options: correct option name and tell where to find docs for it Minor corrections and additions to 'scsi_logging_level', as pointed out by Chuck Ebbert. Also point out the IBM S390-tools 'scsi_logging_level' script. Signed-off-by: Randy Dunlap Signed-off-by: James Bottomley commit 09314f09d655bd4f5b93249d45dda47bbb74fd1d Author: Tony Battersby Date: Mon Nov 12 10:00:44 2007 -0500 [SCSI] move single_lun flag from scsi_device to scsi_target Some SCSI tape medium changers that need the BLIST_SINGLELUN flag have the medium changer at one LUN and the tape drive at a different LUN. The inquiry string of the tape drive may be different from that of the medium changer. In order for single_lun to be effective, every scsi_device under a given scsi_target must have it set. This means that there needs to be a blacklist entry for BOTH the medium changer AND the tape drive, which is impractical because some medium changers may be paired with a variety of different tape drive models. It makes more sense to put the single_lun flag in scsi_target instead of scsi_device, which causes every device at a given target ID to inherit the single_lun flag from one LUN. This makes it possible to blacklist just the medium changer and not the tape drive. Signed-off-by: Tony Battersby Signed-off-by: James Bottomley commit cb8d6aba76371e62ddd7fdd6671a254f0c75647e Author: bo yang Date: Fri Nov 9 04:44:56 2007 -0500 [SCSI] megaraid_sas: Update version and changelog Update version and changelog Signed-off-by: Bo Yang Signed-off-by: James Bottomley commit 98ec2d10fc50d32492e94745ef0084a2e8fa2ee2 Author: bo yang Date: Fri Nov 9 04:40:16 2007 -0500 [SCSI] megaraid_sas: support for poll_mode_io (reduced interrupt) Added module parameter "poll_mode_io" to support for "polling" (reduced interrupt operation). In this mode, IO completion interrupts are delayed. At the end of initiating IOs, the driver schedules for cmd completion if there are pending cmds. A timer-based interrupt has also been added to prevent IO completion from being delayed indefinitely in the case that no new IOs are initiated. Some formatting issues in resume, suspend comment block also corrected Signed-off-by: Bo Yang Signed-off-by: James Bottomley commit c1dbfb9d972991f428c73920896e3e7427963024 Author: bo yang Date: Fri Nov 9 04:35:44 2007 -0500 [SCSI] megaraid_sas: call cmd completion from reset Driver will call cmd completion routine from Reset path without waiting for cmd completion from isr context. Signed-off-by: Bo Yang Signed-off-by: James Bottomley commit bb49d4cd84a9f9657db9dc48fc35107881351c4b Author: bo yang Date: Fri Nov 9 04:28:47 2007 -0500 [SCSI] megaraid_sas: use unsigned long for sense_buff ptr MegaRAID utilities expect sense_buff to be of type unsigned long. Signed-off-by: Bo Yang Signed-off-by: James Bottomley commit dff499fe4851b0bfb642c164dc7f57bacf2e84ad Author: bo yang Date: Fri Nov 9 04:14:00 2007 -0500 [SCSI] megaraid_sas: check max_sgl reported by FW for setting max_sectors_per_req 1. Setting the max_sectors_per_req based on max SGL supported by the FW. Prior versions calculated this value from controller info's max_sectors_1, max_sectors_2. For certain controllers/FW, this was resulting in a value greater than max SGL supported by the FW. Now we take the min of max sgl from FW and max_sectors calculation. 2. Increased MFI_POLL_TIMEOUT_SECS to 60 seconds from 10. FW may take a max of 60 seconds to respond to the INIT cmd. Signed-off-by: Bo Yang Signed-off-by: James Bottomley commit 283c3bdd69c15edb44fe7cee2c46bb676927ebdd Author: bo yang Date: Wed Nov 7 12:09:50 2007 -0500 [SCSI] megaraid_sas: add hibernation support Adding hibernation support. suspend, resume routine implemented. Signed-off-by: Bo Yang Signed-off-by: James Bottomley commit 5ad598d342ff2ef8576c764bb4995a31fe59c6ea Author: Tony Battersby Date: Fri Nov 9 13:04:35 2007 -0500 [SCSI] 3w-9xxx: fix abysmal write performance on some motherboards The 3ware 9500S-8 SATA RAID controller exhibits terrible write performance when PCI memory-write-and-invalidate is disabled. This is easy to demonstrate by replacing pci_try_set_mwi() in the patch below with pci_clear_mwi(). My benchmarks show the following: MWI disabled: 15 MB/s write, 330 MB/s read MWI enabled: 240 MB/s write, 330 MB/s read Most motherboards will enable MWI without the driver having to set it explicitly, so most people probably wouldn't encounter this problem. For the few motherboards that don't enable it, this patch could give a 16x performance improvement for writing. This issue does not seem to affect the 9550SX controller, but the patch doesn't hurt it either. I haven't tested any of the other 3ware controllers. Signed-off-by: Tony Battersby Acked-by: adam radford Signed-off-by: James Bottomley commit 8655a546c83fc43f0a73416bbd126d02de7ad6c0 Author: Hannes Reinecke Date: Tue Nov 6 09:23:40 2007 +0100 [SCSI] Do not requeue requests if REQ_FAILFAST is set Any requests with the REQ_FAILFAST flag set should not be requeued to the requeust queue, but rather terminated directly. Otherwise the multipath failover will stall until the command timeout triggers. Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley commit 5bc717b6bdaaf52edf365eb7d9d8c89fec79df5d Author: Darrick J. Wong Date: Mon Nov 5 11:52:14 2007 -0800 [SCSI] libsas: Fix various sparse complaints Annotate sas_queuecommand with locking details, and clean up a few more sparse warnings about static/non-static declarations. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 4bb8e720ace4c1ca8800b0688ba3a4f08f5586da Author: Darrick J. Wong Date: Mon Nov 5 11:51:17 2007 -0800 [SCSI] libsas: Convert sas_proto users to sas_protocol sparse complains about the mixing of enums in libsas. Since the underlying numeric values of both enums are the same, combine them to get rid of the warning. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit cdbdfa93aa581d8d60587e43842aa407388ae2b5 Author: Matthias Kaehlcke Date: Sat Oct 27 09:48:46 2007 +0200 [SCSI] megaraid_sas: Convert aen_mutex to the mutex API Signed-off-by: Matthias Kaehlcke Acked-by: Bo Yang Signed-off-by: James Bottomley commit b3cbdb94578897356855abc486663edc3608c159 Author: Boaz Harrosh Date: Sun Sep 9 21:13:42 2007 +0300 [SCSI] imm: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup - Not ready for sg-chaining Signed-off-by: Boaz Harrosh Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: James Bottomley commit 559552ae6407101cd0a9f378aaeae900fe29b051 Author: Boaz Harrosh Date: Sun Sep 9 21:16:58 2007 +0300 [SCSI] ppa: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup Signed-off-by: Boaz Harrosh Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: James Bottomley commit 566bbc7ab257a4a3138fc6b561cfb877b9c5c997 Author: James Bottomley Date: Wed Nov 14 18:01:21 2007 -0600 [SCSI] DocBook scsi_midlayer.tmpl->scsi.tmpl Signed-off-by: James Bottomley commit 064a5e5c388c64dd98924abbf2a294a60b00bdf3 Author: Rob Landley Date: Sat Nov 3 13:30:39 2007 -0500 [SCSI] Add Documentation and integrate into docbook build Add Documentation/DocBook/scsi_midlayer.tmpl, add to Makefile, and update lots of kerneldoc comments in drivers/scsi/*. Updated with comments from Stefan Richter, Stephen M. Cameron, James Bottomley and Randy Dunlap. Signed-off-by: Rob Landley Signed-off-by: James Bottomley commit be376c7b2d5e6ba400645b5938025358ddc14ec1 Author: Christof Schmitt Date: Mon Nov 5 12:37:48 2007 +0100 [SCSI] zfcp: Reduce flood on hba trace Remove tracing for request with a "qualifier" field set in the response. The protocol status qualifier now contains measurement data for "good" commands, so this check would trace every response by default. The fix is to simply remove the "qual" tracing: The responses with an interesting status are also traced as "ferr" or "perr" and all responses can be traced as "norm" with a higher trace level. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit d858b526c5e638b0f29d05eb885df65e18ec6cc8 Author: Christof Schmitt Date: Mon Nov 5 12:37:47 2007 +0100 [SCSI] zfcp: Fix deadlock when adding invalid LUN When adding an invalid LUN, there is a deadlock between the add via scsi_scan_target and the slave_destroy handler: The handler waits for the scan to complete, but for an invalid unit, scsi_scan_target directly calls the slave_destroy handler. Fix the deadlock by removing the wait in the slave_destroy handler, it was not necessary anyway. Signed-off-by: Christof Schmitt Signed-off-by: Martin Schwidefsky Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit 4528dcd61845523fee0c6313abd7919976e5d820 Author: Christof Schmitt Date: Mon Nov 5 12:37:46 2007 +0100 [SCSI] zfcp: Remove SCSI devices when removing complete adapter The common I/O layer can call remove a handler to inform zfcp that a device disappeared. The handler zfcp_ccw_remove then removes all unit, port and the adapter data structures. Removing the units requires that the SCSI devices are removed first. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit 0d23c4e20b5d3c9a7f039f9060ee50701063b484 Author: Christof Schmitt Date: Mon Nov 5 12:37:45 2007 +0100 [SCSI] zfcp: Specify waiting times in ERP in seconds It is not necessary to use jiffies or milliseconds to specify waiting times that last a couple of seconds. Signed-off-by: Christof Schmitt Signed-off-by: Martin Schwidefsky Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit 86d6cadaf221d823aabcb8f9a0813ac22ad2b8c7 Author: Christof Schmitt Date: Mon Nov 5 12:37:44 2007 +0100 [SCSI] zfcp: Use also port and adapter to identify unit in messages. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit 4e12aba94b88f36e021cea2d05709e7e952a8510 Author: Christof Schmitt Date: Mon Nov 5 12:37:43 2007 +0100 [SCSI] zfcp: Remove unnecessary eh_bus_reset_handler callback The callback function used by zfcp always returns success, which is an indication for the SCSI midlayer to stop error handling. Remove the bus_reset callback, since the same function will be called via the host_reset callback. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit 450ce1653bfb1ff22bf9c684050c9f036a19ca29 Author: Salyzyn, Mark Date: Tue Oct 30 15:50:49 2007 -0400 [SCSI] aacraid: forced reset override Some of our vendors have requested that our adapters ignore the hardware reset attempts during recovery and have enforced this with changes in Adapter Firmware. Some of our customers have requested the option to be able to reset the adapter under adverse adapter failure, we even had a few defects reported here considering it a regression that the Adapter could not be reset. This patch addresses this dichotomy. The user can force the adapter to be reset if it supports the IOP_RESET_ALWAYS command, in cases where the adapter has been programmed to ignore the reset, by setting the aacraid.check_reset parameter to a value of -1. The driver will not reset an Adapter that does not support the reset command(s). This patch also fixes and cleans up some of the logic associated with resetting the adapter. Signed-off-by: Mark Salyzyn Signed-off-by: James Signed-off-by: James Bottomley commit 2f64a04c5a0d42c6d46262a7cfc6af2cd98f6c32 Author: Boaz Harrosh Date: Mon Nov 5 11:23:35 2007 +0200 [SCSI] NCR5380 family: convert to accessors & !use_sg cleanup - This patch depends on: NCR5380: Use scsi_eh API for REQUEST_SENSE invocation - convert to accessors and !use_sg cleanup - FIXME: Not sg-chain ready look for ++cmd->SCp.buffer Signed-off-by: Boaz Harrosh Signed-off-by: James Signed-off-by: James Bottomley commit 279d8605e0dc7c5e88d8533e2482f6b746beaee9 Author: Boaz Harrosh Date: Mon Nov 5 11:21:40 2007 +0200 [SCSI] wd7000: proper fix for boards without sg support - code used to set sg_tablesize to zero for board revision less than 6. This is no longer supported, therefore I use sg_tablesize=1 and open code the sg handling for that case. - Get rid of use of SG_NONE which will be removed soon. Signed-off-by: Boaz Harrosh Signed-off-by: James Signed-off-by: James Bottomley commit 5eb3b8fa3c2bb4d7539375320a9338abc62125ce Author: Boaz Harrosh Date: Sun Sep 9 21:06:23 2007 +0300 [SCSI] atp870u: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup - Probably not ready for sg-chaining Signed-off-by: Boaz Harrosh Acked-by: Christoph Hellwig Cc: jameshsu Signed-off-by: James Bottomley commit d4ae88063552c6bd46de04a1a76c8be7a49a7ffe Author: Boaz Harrosh Date: Fri Sep 7 06:50:20 2007 +0900 [SCSI] scsi_debug: convert to use the data buffer accessors - remove the unnecessary map_single path. - convert to use the new accessors for the sg lists and the parameters. Signed-off-by: Boaz Harrosh Acked-by: Douglas Gilbert Signed-off-by: James Bottomley commit a755da3f981caabc4b7832ec4fb0429e0b20d967 Author: Boaz Harrosh Date: Wed Aug 22 19:10:45 2007 +0300 [SCSI] isd200: use one-element sg list in issuing commands - This patch should be commited before: usb: transport - convert to accessors and !use_sg code path removal - isd200_action() was still using direct liniar pointers in issuing commands to the USB transport level. This is no longer supported, use one-element scatterlist instead. - Adjustment of command's length in the case of scsi-to-ata translation is now restored before return to queuecommand, since other wise it can leak BIOs. - isd200_action() return Error on unknown requests. Used to print an error but still try to send garbage cdb. - convert few places to scsi data accessors. - Todo: This file will need to be changed when scsi_cmnd changes to scsi_data_buffer or any other solution. Signed-off-by: Boaz Harrosh Acked-by: Matthew Dharm Signed-off-by: James Bottomley commit f658820fc827f2b5e23a3937f568c2e6d55a0625 Author: Boaz Harrosh Date: Mon Sep 10 18:01:08 2007 +0300 [SCSI] usb: transport - convert to accessors and !use_sg code path removal - This patch depends on: usb: transport.c use scsi_eh API in REQUEST_SENSE execution - Use scsi data accessors and remove of !use_sg code path. - New usb_stor_bulk_srb() for use by drivers [jejb: updated with corrective fix. had a bug in residual handling in the new usb_stor_bulk_srb() function. Found by Gabriel C. in -mm tree. Tested-by: Gabriel C ] Signed-off-by: Boaz Harrosh Acked-by: Matthew Dharm Signed-off-by: James Bottomley commit fd9fbc9aa8bee59ff8d0788932dafb6f3027a3c8 Author: Boaz Harrosh Date: Sun Sep 9 20:40:56 2007 +0300 [SCSI] usb: shuttle_usbat - convert to accessors and !use_sg code path removal - functions that received char* but where passed scatterlist* mostly were changed to receive void* - Use scsi data accessors and remove of !use_sg code path Signed-off-by: Boaz Harrosh Acked-by: Matthew Dharm Signed-off-by: James Bottomley commit 292f9443a163bce2503200b3e816ceb60438510c Author: Boaz Harrosh Date: Sun Sep 9 20:47:26 2007 +0300 [SCSI] usb: freecom & sddr09 - convert to accessors and !use_sg cleanup - Use scsi data accessors and remove of !use_sg code path - This patch is dependent on cleanup patch to usb transport.c/h Signed-off-by: Boaz Harrosh Acked-by: Matthew Dharm Signed-off-by: James Bottomley commit bb12ea9b78cd287e43ce88473558b30e95d87f6b Author: Boaz Harrosh Date: Sun Sep 9 20:22:23 2007 +0300 [SCSI] usb: protocol - convert to accessors and !use_sg code path removal - Use scsi data accessors and remove of !use_sg code path Signed-off-by: Boaz Harrosh Acked-by: Matthew Dharm Signed-off-by: James Bottomley commit 5982ab0cef55b0712c5430e37814156204a952ff Author: Boaz Harrosh Date: Wed Oct 17 10:43:20 2007 +0200 [SCSI] seagate: Remove driver - Apparently no one wonts this driver, and no one is willing to fix it for future changes to SCSI. So remove it, and if someone wants it in the future He can revive it with the needed fixes. Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 967cc591ced5d0625c1fe57de0de76f7bcfb2248 Author: Boaz Harrosh Date: Thu Jul 12 19:49:15 2007 +0300 [SCSI] psi240i: remove driver The psi240i driver is still written for cmnd->request_buffer as a char pointer to actual data. There was never any attempt to use the scatterlist option. - remove all source files (3) from drivers/scsi - Remove from Makefile and Kconfig Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit bb44aeb1141660ce2aa14a98bd0dc507e4c5f906 Author: Boaz Harrosh Date: Sun Sep 9 21:14:41 2007 +0300 [SCSI] in2000: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit e8a198483308c16b40fb9ed027f1d26f714d8463 Author: Boaz Harrosh Date: Sun Sep 9 21:21:35 2007 +0300 [SCSI] qlogicpti: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit b2caefffb3a826828ef2cc993d4195cdb08a4325 Author: Boaz Harrosh Date: Sun Sep 9 21:25:11 2007 +0300 [SCSI] wd33c93: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 254fc10f2503a393e68215947a764496e7bacf0d Author: Boaz Harrosh Date: Sun Sep 9 21:12:24 2007 +0300 [SCSI] fd_mcs: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup - Not ready for sg-chaining Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 6f9c2a086714559d027e13bff42d1c0c250f91ed Author: Boaz Harrosh Date: Sun Sep 9 21:02:45 2007 +0300 [SCSI] aha1542: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 4b2123baa3ca5257d61e35335690906523dff2f3 Author: Boaz Harrosh Date: Sun Sep 9 20:59:32 2007 +0300 [SCSI] a3000: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 46ed9254c3f3604b92c65f9f2261c2b7a3338d33 Author: Boaz Harrosh Date: Sun Sep 9 20:57:05 2007 +0300 [SCSI] a2091: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 80db3482294c11404f1351ee95e3d9406926eeb1 Author: Boaz Harrosh Date: Sun Sep 9 21:10:27 2007 +0300 [SCSI] eata_pio: convert to accessors and !use_sg cleanup - convert to accessors and !use_sg cleanup Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 5b09fc62219e1efbbc22baacded706c23f6430e5 Author: Boaz Harrosh Date: Thu Aug 16 13:01:05 2007 +0300 [SCSI] nsp_cs: convert to data accessors and !use_sg cleanup - use scsi data accessors - cleanup !use_sg code paths - TODO: use next_sg() for Jens's sglist branch. Look for 2 places with "SCp.buffer++" Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 14af9f8c30b05c9b5c8a1a9b4c47fb7f441ad4df Author: Boaz Harrosh Date: Thu Nov 1 18:54:44 2007 +0200 [SCSI] aha152x: Use scsi_eh API for REQUEST_SENSE invocation - Use new scsi_eh_prep/restor_cmnd() for synchronous REQUEST_SENSE invocation. Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley commit 4675bc21e52c5ab8027f4bae817c5689abd43b7c Author: Mike Christie Date: Wed Oct 31 20:59:56 2007 -0500 [SCSI] add DID_REQUEUE string to scsi_show_result host table I was working on patches which add new transport error values, when I noticed that DID_REQUEUE was not in the hostbyte_table. I do not think there is any way to hit the code path where scsi_show_result is called and where you return DID_REQUEUE, because DID_REQUEUE causes scsi-ml to always requeue the command. However, for completeness and because I want to one day send a patch that tries to add new host bytes values, I am sending this patch. Signed-off-by: Mike Christie Signed-off-by: James Bottomley commit 767471e88b4a0f4840fd3a7e0911895e09dc22b2 Author: James Smart Date: Sat Oct 27 13:38:20 2007 -0400 [SCSI] lpfc 8.2.3 : Change version number to 8.2.3 Change version number to 8.2.3 Signed-off-by: James Smart Signed-off-by: James Bottomley commit 3c6f5a6c3c72b11c0c68208dbb632ad8020ebf2a Author: James Smart Date: Sat Oct 27 13:38:11 2007 -0400 [SCSI] lpfc 8.2.3 : Temperature handling fix Temperature handling fix - return proper error code indicator for applications Signed-off-by: James Smart Signed-off-by: James Bottomley commit 338fc723f6b7a2301310957813bf2df4371dce5d Author: James Smart Date: Sat Oct 27 13:38:00 2007 -0400 [SCSI] lpfc 8.2.3 : Internal loopback fixes Internal loopback fixes: - Use HBQs rather than Q_RING_BUFF - Correct HBQs continuation entries - Update CT handler to SLI3 iocbs Signed-off-by: James Smart Signed-off-by: James Bottomley commit 33c9f98653032d9b0105b4c2cdc6e4c78f453977 Author: James Smart Date: Sat Oct 27 13:37:53 2007 -0400 [SCSI] lpfc 8.2.3 : Miscellaneous Small Fixes - part 2 Miscellaneous Small Fixes - part 2 - Fix ndlp left in PLOGI state after link up - Fix cannot rcv unsol ELS frames after running HBA resets for a few minutes - Fix HBQ buffer_count implemention - Fix RPI leak - Fix crash while deleting vports while HBA is reset - Revert the FCP Fbits offset back to 7 - Fix panic when deleting vports - Remove unused code in switch statement outside of a case - Reject PLOGI from invalid PName or NName of 0 - Ignore PLOGI responses from WWPName or WWNName of 0 - Fix debugfs hbqinfo display for ppc - Added 8G to list of supported speeds for sysfs parameter - Defer ndlp cleanup to dev-loss timeout handler - Added support for WRITE_VPARMS mailbox command by applications Signed-off-by: James Smart Signed-off-by: James Bottomley commit a460ea6adf23d2ff2a35dc9be4a30e65f81a4bf6 Author: James Smart Date: Sat Oct 27 13:37:43 2007 -0400 [SCSI] lpfc 8.2.3 : FC Discovery Fixes FC Discovery Fixes: - Fix up lpfc_drop_node() vs lpfc_nlp_not_used() usage - Clear ADISC flag when unregistering RPI and REMOVE ndlps if in recovery. - Fix usage of UNUSED list and ndlps - Fix PLOGI race conditions - Reset link if NameServer PLOGI errors occur - Synchronize GID_FT queries with PLOGI receptions Signed-off-by: James Smart Signed-off-by: James Bottomley commit 1328602d822bb6258989b1f39d1efa65fde12d7b Author: James Smart Date: Sat Oct 27 13:37:33 2007 -0400 [SCSI] lpfc 8.2.3 : Miscellaneous Small Fixes - part 1 Miscellaneous Small Fixes - part 1 - Fix typo kmzlloc -> kzalloc - Fix discovery ndlp use after free panic - Fix link event causing flood of 0108 messages - Relieve some mbox congestion on link up with 100 vports - Fix broken vport parameters - Prevent lock recursion in logo_reglogin_issue - Split uses of error variable in lpfc_pci_probe_one into retval and error - Remove completion code related to dev_loss_tmo - Remove unused LPFC_MAX_HBQ #define - Don't compare pointers to 0 for sparse - Make 2 functions static for sparse - Fix default rpi cleanup code causing rogue ndlps to remain on the NPR list - Remove annoying ELS messages when driver is unloaded - Fix Cannot issue Register Fabric login problems on link up - Remove LPFC_EVT_DEV_LOSS_DELAY - Fix FC port swap test leads to device going offline - Fix vport CT flags to only be set when accepted - Add code to handle signals during vport_create - Fix too many retries in FC-AL mode - Pull lpfc_port_link_failure out of lpfc_linkdown_port Signed-off-by: James Smart Signed-off-by: James Bottomley commit d15d790df8857dcccff705232317de92bc185933 Author: James Smart Date: Sat Oct 27 13:37:25 2007 -0400 [SCSI] lpfc 8.2.3 : Remove flawed MBX_STOP_IOCB logic Remove flawed MBX_STOP_IOCB logic Signed-off-by: James Smart Signed-off-by: James Bottomley commit e4f2aa5ac3e933de08e35d013b649d2d14270f90 Author: James Smart Date: Sat Oct 27 13:37:17 2007 -0400 [SCSI] lpfc 8.2.3 : NPIV bug fixes NPIV bug fixes: - Remove vport params on physical hba when npiv is disabled - Implement new DA_ID CT command to remove vport information from the switch after delete. Some switches didn't clean this up unless the physical link dropped. Signed-off-by: James Smart Signed-off-by: James Bottomley commit 96999b81be60fa1b8caf105506db4d7a13032820 Author: James Smart Date: Sat Oct 27 13:37:05 2007 -0400 [SCSI] lpfc 8.2.3 : Added support for ASICs that report temperature Added support for ASICs that report temperature. Temperature notices are reported as events and logged. Temperature can be read via sysfs. Signed-off-by: James Smart Signed-off-by: James Bottomley commit d6ef203591c71b1d30b93fb42ba989df062a7df5 Author: Brian King Date: Thu Oct 25 16:06:34 2007 -0500 [SCSI] ibmvscsi: Set default command timeout Set the default command timeout for ibmvscsi disks to 60 seconds to ensure we don't prematurely timeout commands. This fixes a problem seen where the default 30 seconds was not long enough due to congestion on the server. Signed-off-by: Brian King Signed-off-by: James Bottomley commit f07ddb1bcbdcdfd832ea622d0373fe5b6c195d49 Author: Adrian Bunk Date: Wed Oct 24 18:26:22 2007 +0200 [SCSI] 53c7xx: fix removal fallout This patch does some additional cleanups after the 53c7xx removal. Signed-off-by: Adrian Bunk Acked-by: Geert Uytterhoeven Signed-off-by: James Bottomley commit d24c1e05c00a33451798fb2a7c59ace2757fa89a Author: FUJITA Tomonori Date: Thu Oct 25 01:21:30 2007 +0900 [SCSI] tgt: convert to use the data buffer accessors - convert to use the new accessors for the sg lists and the parameters. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley commit 44f1797f76ac2b1023fca14e353e22186f1d3198 Author: Gilbert Wu Date: Mon Oct 22 15:19:11 2007 -0700 [SCSI] aic94xx: update BIOS image from user space. 1. Create a file "update_bios" in sysfs to allow user to update bios from user space. 2. The BIOS image file can be downloaded from web site "http://www.adaptec.com/en-US/downloads/bios_fw/bios_fw_ver?productId=SAS-48300&dn=Adaptec+Serial+Attached+SCSI+48300" and copy the BIOS image into /lib/firmware folder. 3. The aic994xx will accept "update bios_file" and "verify bios_file" commands to perform update and verify BIOS image . For example: Type "echo "update asc483c01.ufi" > /sys/devices/.../update_bios" to update BIOS image from /lib/firmware/as483c01.ufi file into HBA's flash memory. Type "echo "verify asc483c01.ufi" > /sys/devices/.../update_bios" to verify BIOS image between /lib/firmware/asc48c01.ufi file and HBA's flash memory. 4. Type "cat /sys/devices/.../update_bios" to view the status or result of updating BIOS. Signed-off-by: Gilbert Wu Signed-off-by: James Bottomley commit b302b64bbcc90d29d5b0bbd08569ab93da309998 Author: Kay Sievers Date: Tue Aug 14 14:10:39 2007 +0200 [SCSI] sr,sd: send media state change modification events This will send for a card reader slot (remove/add media): UEVENT[1187091572.155884] change /devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/host7/target7:0:0/7:0:0:0 (scsi) UEVENT[1187091572.162314] remove /block/sdb/sdb1 (block) UEVENT[1187091572.172464] add /block/sdb/sdb1 (block) UEVENT[1187091572.175408] change /devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/host7/target7:0:0/7:0:0:0 (scsi) and for a DVD drive (add/eject media): UEVENT[1187091590.189159] change /devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0 (scsi) UEVENT[1187091590.957124] add /module/isofs (module) UEVENT[1187091604.468207] change /devices/pci0000:00/0000:00:1f.1/host4/target4:0:0/4:0:0:0 (scsi) Userspace gets events, even for unpartitioned media. This unifies the event handling for asynchronoous events (AN) and events caused by perodical polling the device from userspace. Signed-off-by: Kay Sievers [jejb: modified for new event API] Signed-off-by: James Bottomley Signed-off-by: Andrew Morton --- Documentation/DocBook/scsi.tmpl | 409 ++++ Documentation/dontdiff | 2 Documentation/kernel-parameters.txt | 8 Documentation/m68k/kernel-options.txt | 60 Documentation/scsi/00-INDEX | 2 Documentation/scsi/ChangeLog.megaraid_sas | 159 + Documentation/scsi/ncr53c7xx.txt | 40 drivers/s390/scsi/zfcp_aux.c | 2 drivers/s390/scsi/zfcp_ccw.c | 3 drivers/s390/scsi/zfcp_dbf.c | 6 drivers/s390/scsi/zfcp_def.h | 8 drivers/s390/scsi/zfcp_erp.c | 9 drivers/s390/scsi/zfcp_scsi.c | 16 drivers/scsi/.gitignore | 2 drivers/scsi/3w-9xxx.c | 1 drivers/scsi/Kconfig | 26 drivers/scsi/Makefile | 3 drivers/scsi/NCR5380.c | 14 drivers/scsi/a2091.c | 36 drivers/scsi/a3000.c | 15 drivers/scsi/aacraid/aachba.c | 8 drivers/scsi/aacraid/commsup.c | 13 drivers/scsi/aacraid/linit.c | 7 drivers/scsi/aacraid/rx.c | 4 drivers/scsi/aha152x.c | 38 drivers/scsi/aha1542.c | 45 drivers/scsi/aic94xx/aic94xx_dev.c | 6 drivers/scsi/aic94xx/aic94xx_dump.c | 4 drivers/scsi/aic94xx/aic94xx_hwi.c | 2 drivers/scsi/aic94xx/aic94xx_hwi.h | 3 drivers/scsi/aic94xx/aic94xx_init.c | 184 ++ drivers/scsi/aic94xx/aic94xx_scb.c | 6 drivers/scsi/aic94xx/aic94xx_sds.c | 389 ++++ drivers/scsi/aic94xx/aic94xx_sds.h | 121 + drivers/scsi/aic94xx/aic94xx_task.c | 30 drivers/scsi/aic94xx/aic94xx_tmf.c | 12 drivers/scsi/atari_NCR5380.c | 22 drivers/scsi/atp870u.c | 102 - drivers/scsi/constants.c | 3 drivers/scsi/eata_pio.c | 12 drivers/scsi/fd_mcs.c | 36 drivers/scsi/hosts.c | 4 drivers/scsi/ibmvscsi/ibmvscsi.c | 155 + drivers/scsi/ibmvscsi/ibmvstgt.c | 2 drivers/scsi/imm.c | 13 drivers/scsi/in2000.c | 10 drivers/scsi/libsas/sas_discover.c | 2 drivers/scsi/libsas/sas_expander.c | 6 drivers/scsi/libsas/sas_internal.h | 2 drivers/scsi/libsas/sas_scsi_host.c | 6 drivers/scsi/libsrp.c | 23 drivers/scsi/lpfc/lpfc.h | 38 drivers/scsi/lpfc/lpfc_attr.c | 51 drivers/scsi/lpfc/lpfc_crtn.h | 13 drivers/scsi/lpfc/lpfc_ct.c | 114 + drivers/scsi/lpfc/lpfc_debugfs.c | 13 drivers/scsi/lpfc/lpfc_disc.h | 2 drivers/scsi/lpfc/lpfc_els.c | 377 ++-- drivers/scsi/lpfc/lpfc_hbadisc.c | 291 ++- drivers/scsi/lpfc/lpfc_hw.h | 77 drivers/scsi/lpfc/lpfc_init.c | 196 +- drivers/scsi/lpfc/lpfc_logmsg.h | 1 drivers/scsi/lpfc/lpfc_mbox.c | 30 drivers/scsi/lpfc/lpfc_nportdisc.c | 116 + drivers/scsi/lpfc/lpfc_sli.c | 282 ++- drivers/scsi/lpfc/lpfc_sli.h | 9 drivers/scsi/lpfc/lpfc_version.h | 2 drivers/scsi/lpfc/lpfc_vport.c | 84 - drivers/scsi/megaraid/megaraid_sas.c | 572 +++++- drivers/scsi/megaraid/megaraid_sas.h | 18 drivers/scsi/pcmcia/nsp_cs.c | 54 drivers/scsi/ppa.c | 12 drivers/scsi/psi240i.c | 689 -------- drivers/scsi/psi240i.h | 315 --- drivers/scsi/psi_chip.h | 195 -- drivers/scsi/qla2xxx/qla_attr.c | 2 drivers/scsi/qla2xxx/qla_def.h | 10 drivers/scsi/qla2xxx/qla_fw.h | 16 drivers/scsi/qla2xxx/qla_init.c | 19 drivers/scsi/qla2xxx/qla_isr.c | 11 drivers/scsi/qla2xxx/qla_mbx.c | 4 drivers/scsi/qla2xxx/qla_mid.c | 33 drivers/scsi/qla2xxx/qla_version.h | 2 drivers/scsi/qlogicpti.c | 29 drivers/scsi/scsi.c | 189 +- drivers/scsi/scsi_debug.c | 37 drivers/scsi/scsi_devinfo.c | 34 drivers/scsi/scsi_error.c | 125 - drivers/scsi/scsi_ioctl.c | 24 drivers/scsi/scsi_lib.c | 88 - drivers/scsi/scsi_netlink.c | 19 drivers/scsi/scsi_proc.c | 110 + drivers/scsi/scsi_scan.c | 34 drivers/scsi/scsi_tgt_if.c | 2 drivers/scsi/scsi_tgt_lib.c | 11 drivers/scsi/scsi_transport_fc.c | 102 - drivers/scsi/scsi_transport_iscsi.c | 17 drivers/scsi/scsi_transport_sas.c | 40 drivers/scsi/scsi_transport_srp.c | 13 drivers/scsi/scsicam.c | 35 drivers/scsi/sd.c | 24 drivers/scsi/seagate.c | 1667 -------------------- drivers/scsi/sr.c | 14 drivers/scsi/sr.h | 1 drivers/scsi/sun3_NCR5380.c | 22 drivers/scsi/wd33c93.c | 10 drivers/scsi/wd7000.c | 12 drivers/usb/storage/freecom.c | 14 drivers/usb/storage/isd200.c | 66 drivers/usb/storage/protocol.c | 122 - drivers/usb/storage/sddr09.c | 9 drivers/usb/storage/shuttle_usbat.c | 68 drivers/usb/storage/transport.c | 45 drivers/usb/storage/transport.h | 2 include/scsi/libsas.h | 22 include/scsi/sas.h | 13 include/scsi/scsi_device.h | 6 include/scsi/scsi_transport_sas.h | 8 include/scsi/sd.h | 1 119 files changed, 4074 insertions(+), 4700 deletions(-) diff -puN Documentation/DocBook/Makefile~git-scsi-misc Documentation/DocBook/Makefile diff -puN /dev/null Documentation/DocBook/scsi.tmpl --- /dev/null +++ a/Documentation/DocBook/scsi.tmpl @@ -0,0 +1,409 @@ + + + + + + SCSI Interfaces Guide + + + + James + Bottomley + +
+ James.Bottomley@steeleye.com +
+
+
+ + + Rob + Landley + +
+ rob@landley.net +
+
+
+ +
+ + + 2007 + Linux Foundation + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License version 2. + + + + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + Protocol vs bus + + Once upon a time, the Small Computer Systems Interface defined both + a parallel I/O bus and a data protocol to connect a wide variety of + peripherals (disk drives, tape drives, modems, printers, scanners, + optical drives, test equipment, and medical devices) to a host + computer. + + + Although the old parallel (fast/wide/ultra) SCSI bus has largely + fallen out of use, the SCSI command set is more widely used than ever + to communicate with devices over a number of different busses. + + + The SCSI protocol + is a big-endian peer-to-peer packet based protocol. SCSI commands + are 6, 10, 12, or 16 bytes long, often followed by an associated data + payload. + + + SCSI commands can be transported over just about any kind of bus, and + are the default protocol for storage devices attached to USB, SATA, + SAS, Fibre Channel, FireWire, and ATAPI devices. SCSI packets are + also commonly exchanged over Infiniband, + I20, TCP/IP + (iSCSI), even + Parallel + ports. + + + + Design of the Linux SCSI subsystem + + The SCSI subsystem uses a three layer design, with upper, mid, and low + layers. Every operation involving the SCSI subsystem (such as reading + a sector from a disk) uses one driver at each of the 3 levels: one + upper layer driver, one lower layer driver, and the SCSI midlayer. + + + The SCSI upper layer provides the interface between userspace and the + kernel, in the form of block and char device nodes for I/O and + ioctl(). The SCSI lower layer contains drivers for specific hardware + devices. + + + In between is the SCSI mid-layer, analogous to a network routing + layer such as the IPv4 stack. The SCSI mid-layer routes a packet + based data protocol between the upper layer's /dev nodes and the + corresponding devices in the lower layer. It manages command queues, + provides error handling and power management functions, and responds + to ioctl() requests. + + + + + + SCSI upper layer + + The upper layer supports the user-kernel interface by providing + device nodes. + + + sd (SCSI Disk) + sd (sd_mod.o) + + + + sr (SCSI CD-ROM) + sr (sr_mod.o) + + + st (SCSI Tape) + st (st.o) + + + sg (SCSI Generic) + sg (sg.o) + + + ch (SCSI Media Changer) + ch (ch.c) + + + + + SCSI mid layer + + + SCSI midlayer implementation + + include/scsi/scsi_device.h + + +!Iinclude/scsi/scsi_device.h + + + + drivers/scsi/scsi.c + Main file for the SCSI midlayer. +!Edrivers/scsi/scsi.c + + + drivers/scsi/scsicam.c + + SCSI + Common Access Method support functions, for use with + HDIO_GETGEO, etc. + +!Edrivers/scsi/scsicam.c + + + drivers/scsi/scsi_error.c + Common SCSI error/timeout handling routines. +!Edrivers/scsi/scsi_error.c + + + drivers/scsi/scsi_devinfo.c + + Manage scsi_dev_info_list, which tracks blacklisted and whitelisted + devices. + +!Idrivers/scsi/scsi_devinfo.c + + + drivers/scsi/scsi_ioctl.c + + Handle ioctl() calls for SCSI devices. + +!Edrivers/scsi/scsi_ioctl.c + + + drivers/scsi/scsi_lib.c + + SCSI queuing library. + +!Edrivers/scsi/scsi_lib.c + + + drivers/scsi/scsi_lib_dma.c + + SCSI library functions depending on DMA + (map and unmap scatter-gather lists). + +!Edrivers/scsi/scsi_lib_dma.c + + + drivers/scsi/scsi_module.c + + The file drivers/scsi/scsi_module.c contains legacy support for + old-style host templates. It should never be used by any new driver. + + + + drivers/scsi/scsi_proc.c + + The functions in this file provide an interface between + the PROC file system and the SCSI device drivers + It is mainly used for debugging, statistics and to pass + information directly to the lowlevel driver. + + I.E. plumbing to manage /proc/scsi/* + +!Idrivers/scsi/scsi_proc.c + + + drivers/scsi/scsi_netlink.c + + Infrastructure to provide async events from transports to userspace + via netlink, using a single NETLINK_SCSITRANSPORT protocol for all + transports. + + See the + original patch submission for more details. + +!Idrivers/scsi/scsi_netlink.c + + + drivers/scsi/scsi_scan.c + + Scan a host to determine which (if any) devices are attached. + + The general scanning/probing algorithm is as follows, exceptions are + made to it depending on device specific flags, compilation options, + and global variable (boot or module load time) settings. + + A specific LUN is scanned via an INQUIRY command; if the LUN has a + device attached, a scsi_device is allocated and setup for it. + + For every id of every channel on the given host, start by scanning + LUN 0. Skip hosts that don't respond at all to a scan of LUN 0. + Otherwise, if LUN 0 has a device attached, allocate and setup a + scsi_device for it. If target is SCSI-3 or up, issue a REPORT LUN, + and scan all of the LUNs returned by the REPORT LUN; else, + sequentially scan LUNs up until some maximum is reached, or a LUN is + seen that cannot have a device attached to it. + +!Idrivers/scsi/scsi_scan.c + + + drivers/scsi/scsi_sysctl.c + + Set up the sysctl entry: "/dev/scsi/logging_level" + (DEV_SCSI_LOGGING_LEVEL) which sets/returns scsi_logging_level. + + + + drivers/scsi/scsi_sysfs.c + + SCSI sysfs interface routines. + +!Edrivers/scsi/scsi_sysfs.c + + + drivers/scsi/hosts.c + + mid to lowlevel SCSI driver interface + +!Edrivers/scsi/hosts.c + + + drivers/scsi/constants.c + + mid to lowlevel SCSI driver interface + +!Edrivers/scsi/constants.c + + + + + Transport classes + + Transport classes are service libraries for drivers in the SCSI + lower layer, which expose transport attributes in sysfs. + + + Fibre Channel transport + + The file drivers/scsi/scsi_transport_fc.c defines transport attributes + for Fibre Channel. + +!Edrivers/scsi/scsi_transport_fc.c + + + iSCSI transport class + + The file drivers/scsi/scsi_transport_iscsi.c defines transport + attributes for the iSCSI class, which sends SCSI packets over TCP/IP + connections. + +!Edrivers/scsi/scsi_transport_iscsi.c + + + Serial Attached SCSI (SAS) transport class + + The file drivers/scsi/scsi_transport_sas.c defines transport + attributes for Serial Attached SCSI, a variant of SATA aimed at + large high-end systems. + + + The SAS transport class contains common code to deal with SAS HBAs, + an aproximated representation of SAS topologies in the driver model, + and various sysfs attributes to expose these topologies and managment + interfaces to userspace. + + + In addition to the basic SCSI core objects this transport class + introduces two additional intermediate objects: The SAS PHY + as represented by struct sas_phy defines an "outgoing" PHY on + a SAS HBA or Expander, and the SAS remote PHY represented by + struct sas_rphy defines an "incoming" PHY on a SAS Expander or + end device. Note that this is purely a software concept, the + underlying hardware for a PHY and a remote PHY is the exactly + the same. + + + There is no concept of a SAS port in this code, users can see + what PHYs form a wide port based on the port_identifier attribute, + which is the same for all PHYs in a port. + +!Edrivers/scsi/scsi_transport_sas.c + + + SATA transport class + + The SATA transport is handled by libata, which has its own book of + documentation in this directory. + + + + Parallel SCSI (SPI) transport class + + The file drivers/scsi/scsi_transport_spi.c defines transport + attributes for traditional (fast/wide/ultra) SCSI busses. + +!Edrivers/scsi/scsi_transport_spi.c + + + SCSI RDMA (SRP) transport class + + The file drivers/scsi/scsi_transport_srp.c defines transport + attributes for SCSI over Remote Direct Memory Access. + +!Edrivers/scsi/scsi_transport_srp.c + + + + + + + SCSI lower layer + + Host Bus Adapter transport types + + Many modern device controllers use the SCSI command set as a protocol to + communicate with their devices through many different types of physical + connections. + + + In SCSI language a bus capable of carrying SCSI commands is + called a "transport", and a controller connecting to such a bus is + called a "host bus adapter" (HBA). + + + Debug transport + + The file drivers/scsi/scsi_debug.c simulates a host adapter with a + variable number of disks (or disk like devices) attached, sharing a + common amount of RAM. Does a lot of checking to make sure that we are + not getting blocks mixed up, and panics the kernel if anything out of + the ordinary is seen. + + + To be more realistic, the simulated devices have the transport + attributes of SAS disks. + + + For documentation see + http://www.torque.net/sg/sdebug26.html + + + + + todo + Parallel (fast/wide/ultra) SCSI, USB, SATA, + SAS, Fibre Channel, FireWire, ATAPI devices, Infiniband, + I20, iSCSI, Parallel ports, netlink... + + + + +
diff -puN Documentation/dontdiff~git-scsi-misc Documentation/dontdiff --- a/Documentation/dontdiff~git-scsi-misc +++ a/Documentation/dontdiff @@ -46,8 +46,6 @@ .mailmap .mm 53c700_d.h -53c7xx_d.h -53c7xx_u.h 53c8xx_d.h* BitKeeper COPYING diff -puN Documentation/kernel-parameters.txt~git-scsi-misc Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt~git-scsi-misc +++ a/Documentation/kernel-parameters.txt @@ -1591,7 +1591,13 @@ and is between 256 and 4096 characters. Format: :: (flags are integer value) - scsi_logging= [SCSI] + scsi_logging_level= [SCSI] a bit mask of logging levels + See drivers/scsi/scsi_logging.h for bits. Also + settable via sysctl at dev.scsi.logging_level + (/proc/sys/dev/scsi/logging_level). + There is also a nice 'scsi_logging_level' script in the + S390-tools package, available for download at + http://www-128.ibm.com/developerworks/linux/linux390/s390-tools-1.5.4.html scsi_mod.scan= [SCSI] sync (default) scans SCSI busses as they are discovered. async scans them in kernel threads, diff -puN Documentation/m68k/kernel-options.txt~git-scsi-misc Documentation/m68k/kernel-options.txt --- a/Documentation/m68k/kernel-options.txt~git-scsi-misc +++ a/Documentation/m68k/kernel-options.txt @@ -867,66 +867,6 @@ controller and should be autodetected by 24 bit region which is specified by a mask of 0x00fffffe. -5.5) 53c7xx= ------------- - -Syntax: 53c7xx= - -These options affect the A4000T, A4091, WarpEngine, Blizzard 603e+, -and GForce 040/060 SCSI controllers on the Amiga, as well as the -builtin MVME 16x SCSI controller. - -The is a comma-separated list of the sub-options listed -below. - -5.5.1) nosync -------------- - -Syntax: nosync:0 - - Disables sync negotiation for all devices. Any value after the - colon is acceptable (and has the same effect). - -5.5.2) noasync --------------- - -[OBSOLETE, REMOVED] - -5.5.3) nodisconnect -------------------- - -Syntax: nodisconnect:0 - - Disables SCSI disconnects. Any value after the colon is acceptable - (and has the same effect). - -5.5.4) validids ---------------- - -Syntax: validids:0xNN - - Specify which SCSI ids the driver should pay attention to. This is - a bitmask (i.e. to only pay attention to ID#4, you'd use 0x10). - Default is 0x7f (devices 0-6). - -5.5.5) opthi -5.5.6) optlo ------------- - -Syntax: opthi:M,optlo:N - - Specify options for "hostdata->options". The acceptable definitions - are listed in drivers/scsi/53c7xx.h; the 32 high bits should be in - opthi and the 32 low bits in optlo. They must be specified in the - order opthi=M,optlo=N. - -5.5.7) next ------------ - - No argument. Used to separate blocks of keywords when there's more - than one 53c7xx host adapter in the system. - - /* Local Variables: */ /* mode: text */ /* End: */ diff -puN Documentation/scsi/00-INDEX~git-scsi-misc Documentation/scsi/00-INDEX --- a/Documentation/scsi/00-INDEX~git-scsi-misc +++ a/Documentation/scsi/00-INDEX @@ -64,8 +64,6 @@ lpfc.txt - LPFC driver release notes megaraid.txt - Common Management Module, shared code handling ioctls for LSI drivers -ncr53c7xx.txt - - info on driver for NCR53c7xx based adapters ncr53c8xx.txt - info on driver for NCR53c8xx based adapters osst.txt diff -puN Documentation/scsi/ChangeLog.megaraid_sas~git-scsi-misc Documentation/scsi/ChangeLog.megaraid_sas --- a/Documentation/scsi/ChangeLog.megaraid_sas~git-scsi-misc +++ a/Documentation/scsi/ChangeLog.megaraid_sas @@ -1,3 +1,162 @@ +1 Release Date : Thur. Nov. 07 16:30:43 PST 2007 - + (emaild-id:megaraidlinux@lsi.com) + Sumant Patro + Bo Yang + +2 Current Version : 00.00.03.16 +3 Older Version : 00.00.03.15 + +1. Increased MFI_POLL_TIMEOUT_SECS to 60 seconds from 10. FW may take + a max of 60 seconds to respond to the INIT cmd. + +1 Release Date : Fri. Sep. 07 16:30:43 PST 2007 - + (emaild-id:megaraidlinux@lsi.com) + Sumant Patro + Bo Yang + +2 Current Version : 00.00.03.15 +3 Older Version : 00.00.03.14 + +1. Added module parameter "poll_mode_io" to support for "polling" + (reduced interrupt operation). In this mode, IO completion + interrupts are delayed. At the end of initiating IOs, the + driver schedules for cmd completion if there are pending cmds + to be completed. A timer-based interrupt has also been added + to prevent IO completion processing from being delayed + indefinitely in the case that no new IOs are initiated. + +1 Release Date : Fri. Sep. 07 16:30:43 PST 2007 - + (emaild-id:megaraidlinux@lsi.com) + Sumant Patro + Bo Yang + +2 Current Version : 00.00.03.14 +3 Older Version : 00.00.03.13 + +1. Setting the max_sectors_per_req based on max SGL supported by the + FW. Prior versions calculated this value from controller info + (max_sectors_1, max_sectors_2). For certain controllers/FW, + this was resulting in a value greater than max SGL supported + by the FW. Issue was first reported by users running LUKS+XFS + with megaraid_sas. Thanks to RB for providing the logs and + duplication steps that helped to get to the root cause of the + issue. 2. Increased MFI_POLL_TIMEOUT_SECS to 60 seconds from + 10. FW may take a max of 60 seconds to respond to the INIT + cmd. + +1 Release Date : Fri. June. 15 16:30:43 PST 2007 - + (emaild-id:megaraidlinux@lsi.com) + Sumant Patro + Bo Yang + +2 Current Version : 00.00.03.13 +3 Older Version : 00.00.03.12 + +1. Added the megasas_reset_timer routine to intercept cmd timeout and throttle io. + +On Fri, 2007-03-16 at 16:44 -0600, James Bottomley wrote: +It looks like megaraid_sas at least needs this to throttle its commands +> as they begin to time out. The code keeps the existing transport +> template use of eh_timed_out (and allows the transport to override the +> host if they both have this callback). +> +> James + +1 Release Date : Sat May. 12 16:30:43 PST 2007 - + (emaild-id:megaraidlinux@lsi.com) + Sumant Patro + Bo Yang + +2 Current Version : 00.00.03.12 +3 Older Version : 00.00.03.11 + +1. When MegaSAS driver receives reset call from OS, driver waits in reset +routine for max 3 minutes for all pending command completion. Now driver will +call completion routine every 5 seconds from the reset routine instead of +waiting for depending on cmd completion from isr path. + +1 Release Date : Mon Apr. 30 10:25:52 PST 2007 - + (emaild-id:megaraidlinux@lsi.com) + Sumant Patro + Bo Yang + +2 Current Version : 00.00.03.11 +3 Older Version : 00.00.03.09 + + 1. Memory Manager for IOCTL removed for 2.6 kernels. + pci_alloc_consistent replaced by dma_alloc_coherent. With this + change there is no need of memory manager in the driver code + + On Wed, 2007-02-07 at 13:30 -0800, Andrew Morton wrote: + > I suspect all this horror is due to stupidity in the DMA API. + > + > pci_alloc_consistent() just goes and assumes GFP_ATOMIC, whereas + > the caller (megasas_mgmt_fw_ioctl) would have been perfectly happy + > to use GFP_KERNEL. + > + > I bet this fixes it + + It does, but the DMA API was expanded to cope with this exact case, so + use dma_alloc_coherent() directly in the megaraid code instead. The dev + is just &pci_dev->dev. + + James + + 3. SYNCHRONIZE_CACHE is not supported by FW and thus blocked by driver. + 4. Hibernation support added + 5. Performing diskdump while running IO in RHEL 4 was failing. Fixed. + +1 Release Date : Fri Feb. 09 14:36:28 PST 2007 - + (emaild-id:megaraidlinux@lsi.com) + Sumant Patro + Bo Yang + +2 Current Version : 00.00.03.09 +3 Older Version : 00.00.03.08 + +i. Under heavy IO mid-layer prints "DRIVER_TIMEOUT" errors + + The driver now waits for 10 seconds to elapse instead of 5 (as in + previous release) to resume IO. + +1 Release Date : Mon Feb. 05 11:35:24 PST 2007 - + (emaild-id:megaraidlinux@lsi.com) + Sumant Patro + Bo Yang +2 Current Version : 00.00.03.08 +3 Older Version : 00.00.03.07 + +i. Under heavy IO mid-layer prints "DRIVER_TIMEOUT" errors + + Fix: The driver is now throttling IO. + Checks added in megasas_queue_command to know if FW is able to + process commands within timeout period. If number of retries + is 2 or greater,the driver stops sending cmd to FW temporarily. IO is + resumed if pending cmd count reduces to 16 or 5 seconds has elapsed + from the time cmds were last sent to FW. + +ii. FW enables WCE bit in Mode Sense cmd for drives that are configured + as WriteBack. The OS may send "SYNCHRONIZE_CACHE" cmd when Logical + Disks are exposed with WCE=1. User is advised to enable Write Back + mode only when the controller has battery backup. At this time + Synhronize cache is not supported by the FW. Driver will short-cycle + the cmd and return sucess without sending down to FW. + +1 Release Date : Sun Jan. 14 11:21:32 PDT 2007 - + Sumant Patro /Bo Yang +2 Current Version : 00.00.03.07 +3 Older Version : 00.00.03.06 + +i. bios_param entry added in scsi_host_template that returns disk geometry + information. + +1 Release Date : Fri Oct 20 11:21:32 PDT 2006 - Sumant Patro /Bo Yang +2 Current Version : 00.00.03.06 +3 Older Version : 00.00.03.05 + +1. Added new memory management module to support the IOCTL memory allocation. For IOCTL we try to allocate from the memory pool created during driver initialization. If mem pool is empty then we allocate at run time. +2. Added check in megasas_queue_command and dpc/isr routine to see if we have already declared adapter dead + (hw_crit_error=1). If hw_crit_error==1, now we donot accept any processing of pending cmds/accept any cmd from OS 1 Release Date : Mon Oct 02 11:21:32 PDT 2006 - Sumant Patro 2 Current Version : 00.00.03.05 diff -puN Documentation/scsi/ncr53c7xx.txt~git-scsi-misc /dev/null --- a/Documentation/scsi/ncr53c7xx.txt +++ /dev/null @@ -1,40 +0,0 @@ -README for WarpEngine/A4000T/A4091 SCSI kernels. - -Use the following options to disable options in the SCSI driver. - -Using amiboot for example..... - -To disable Synchronous Negotiation.... - - amiboot -k kernel 53c7xx=nosync:0 - -To disable Disconnection.... - - amiboot -k kernel 53c7xx=nodisconnect:0 - -To disable certain SCSI devices... - - amiboot -k kernel 53c7xx=validids:0x3F - - this allows only device ID's 0,1,2,3,4 and 5 for linux to handle. - (this is a bitmasked field - i.e. each bit represents a SCSI ID) - -These commands work on a per controller basis and use the option 'next' to -move to the next controller in the system. - -e.g. - amiboot -k kernel 53c7xx=nodisconnect:0,next,nosync:0 - - this uses No Disconnection on the first controller and Asynchronous - SCSI on the second controller. - -Known Issues: - -Two devices are known not to function with the default settings of using -synchronous SCSI. These are the Archive Viper 150 Tape Drive and the -SyQuest SQ555 removeable hard drive. When using these devices on a controller -use the 'nosync:0' option. - -Please try these options and post any problems/successes to me. - -Alan Hourihane diff -puN drivers/s390/scsi/zfcp_aux.c~git-scsi-misc drivers/s390/scsi/zfcp_aux.c --- a/drivers/s390/scsi/zfcp_aux.c~git-scsi-misc +++ a/drivers/s390/scsi/zfcp_aux.c @@ -844,8 +844,6 @@ zfcp_unit_enqueue(struct zfcp_port *port unit->sysfs_device.release = zfcp_sysfs_unit_release; dev_set_drvdata(&unit->sysfs_device, unit); - init_waitqueue_head(&unit->scsi_scan_wq); - /* mark unit unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); diff -puN drivers/s390/scsi/zfcp_ccw.c~git-scsi-misc drivers/s390/scsi/zfcp_ccw.c --- a/drivers/s390/scsi/zfcp_ccw.c~git-scsi-misc +++ a/drivers/s390/scsi/zfcp_ccw.c @@ -120,6 +120,9 @@ zfcp_ccw_remove(struct ccw_device *ccw_d list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) { list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) { + if (atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED, + &unit->status)) + scsi_remove_device(unit->device); zfcp_unit_dequeue(unit); } zfcp_port_dequeue(port); diff -puN drivers/s390/scsi/zfcp_dbf.c~git-scsi-misc drivers/s390/scsi/zfcp_dbf.c --- a/drivers/s390/scsi/zfcp_dbf.c~git-scsi-misc +++ a/drivers/s390/scsi/zfcp_dbf.c @@ -161,12 +161,6 @@ void zfcp_hba_dbf_event_fsf_response(str (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) { strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE); level = 4; - } else if ((prot_status_qual->doubleword[0] != 0) || - (prot_status_qual->doubleword[1] != 0) || - (fsf_status_qual->doubleword[0] != 0) || - (fsf_status_qual->doubleword[1] != 0)) { - strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE); - level = 3; } else { strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE); level = 6; diff -puN drivers/s390/scsi/zfcp_def.h~git-scsi-misc drivers/s390/scsi/zfcp_def.h --- a/drivers/s390/scsi/zfcp_def.h~git-scsi-misc +++ a/drivers/s390/scsi/zfcp_def.h @@ -118,7 +118,7 @@ zfcp_address_to_sg(void *address, struct #define ZFCP_SBAL_TIMEOUT (5*HZ) -#define ZFCP_TYPE2_RECOVERY_TIME (8*HZ) +#define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */ /* queue polling (values in microseconds) */ #define ZFCP_MAX_INPUT_THRESHOLD 5000 /* FIXME: tune */ @@ -139,7 +139,7 @@ zfcp_address_to_sg(void *address, struct #define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM /* Do 1st retry in 1 second, then double the timeout for each following retry */ -#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 100 +#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 1 #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7 /* timeout value for "default timer" for fsf requests */ @@ -983,10 +983,6 @@ struct zfcp_unit { struct scsi_device *device; /* scsi device struct pointer */ struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; - wait_queue_head_t scsi_scan_wq; /* can be used to wait until - all scsi_scan_target - requests have been - completed. */ }; /* FSF request */ diff -puN drivers/s390/scsi/zfcp_erp.c~git-scsi-misc drivers/s390/scsi/zfcp_erp.c --- a/drivers/s390/scsi/zfcp_erp.c~git-scsi-misc +++ a/drivers/s390/scsi/zfcp_erp.c @@ -131,7 +131,7 @@ static void zfcp_close_qdio(struct zfcp_ debug_text_event(adapter->erp_dbf, 3, "qdio_down2a"); while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) - msleep(1000); + ssleep(1); debug_text_event(adapter->erp_dbf, 3, "qdio_down2b"); /* cleanup used outbound sbals */ @@ -1609,7 +1609,6 @@ static void zfcp_erp_scsi_scan(struct wo scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, unit->scsi_lun, 0); atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); - wake_up(&unit->scsi_scan_wq); zfcp_unit_put(unit); kfree(p); } @@ -1900,7 +1899,7 @@ zfcp_erp_adapter_strategy(struct zfcp_er ZFCP_LOG_INFO("Waiting to allow the adapter %s " "to recover itself\n", zfcp_get_busid_by_adapter(adapter)); - msleep(jiffies_to_msecs(ZFCP_TYPE2_RECOVERY_TIME)); + ssleep(ZFCP_TYPE2_RECOVERY_TIME); } return retval; @@ -2080,7 +2079,7 @@ zfcp_erp_adapter_strategy_open_qdio(stru debug_text_event(adapter->erp_dbf, 3, "qdio_down1a"); while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) - msleep(1000); + ssleep(1); debug_text_event(adapter->erp_dbf, 3, "qdio_down1b"); failed_qdio_establish: @@ -2165,7 +2164,7 @@ zfcp_erp_adapter_strategy_open_fsf_xconf ZFCP_LOG_DEBUG("host connection still initialising... " "waiting and retrying...\n"); /* sleep a little bit before retry */ - msleep(jiffies_to_msecs(sleep)); + ssleep(sleep); sleep *= 2; } diff -puN drivers/s390/scsi/zfcp_scsi.c~git-scsi-misc drivers/s390/scsi/zfcp_scsi.c --- a/drivers/s390/scsi/zfcp_scsi.c~git-scsi-misc +++ a/drivers/s390/scsi/zfcp_scsi.c @@ -51,7 +51,6 @@ struct zfcp_data zfcp_data = { .queuecommand = zfcp_scsi_queuecommand, .eh_abort_handler = zfcp_scsi_eh_abort_handler, .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, - .eh_bus_reset_handler = zfcp_scsi_eh_host_reset_handler, .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, .can_queue = 4096, .this_id = -1, @@ -181,9 +180,6 @@ static void zfcp_scsi_slave_destroy(stru if (unit) { zfcp_erp_wait(unit->port->adapter); - wait_event(unit->scsi_scan_wq, - atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, - &unit->status) == 0); atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); sdpnt->hostdata = NULL; unit->device = NULL; @@ -459,7 +455,9 @@ zfcp_scsi_eh_device_reset_handler(struct retval = SUCCESS; goto out; } - ZFCP_LOG_NORMAL("resetting unit 0x%016Lx\n", unit->fcp_lun); + ZFCP_LOG_NORMAL("resetting unit 0x%016Lx on port 0x%016Lx, adapter %s\n", + unit->fcp_lun, unit->port->wwpn, + zfcp_get_busid_by_adapter(unit->port->adapter)); /* * If we do not know whether the unit supports 'logical unit reset' @@ -542,7 +540,7 @@ zfcp_task_management_function(struct zfc } /** - * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset + * zfcp_scsi_eh_host_reset_handler - handler for host reset */ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { @@ -552,8 +550,10 @@ static int zfcp_scsi_eh_host_reset_handl unit = (struct zfcp_unit*) scpnt->device->hostdata; adapter = unit->port->adapter; - ZFCP_LOG_NORMAL("host/bus reset because of problems with " - "unit 0x%016Lx\n", unit->fcp_lun); + ZFCP_LOG_NORMAL("host reset because of problems with " + "unit 0x%016Lx on port 0x%016Lx, adapter %s\n", + unit->fcp_lun, unit->port->wwpn, + zfcp_get_busid_by_adapter(unit->port->adapter)); zfcp_erp_adapter_reopen(adapter, 0); zfcp_erp_wait(adapter); diff -puN drivers/scsi/.gitignore~git-scsi-misc drivers/scsi/.gitignore --- a/drivers/scsi/.gitignore~git-scsi-misc +++ a/drivers/scsi/.gitignore @@ -1,3 +1 @@ 53c700_d.h -53c7xx_d.h -53c7xx_u.h diff -puN drivers/scsi/3w-9xxx.c~git-scsi-misc drivers/scsi/3w-9xxx.c --- a/drivers/scsi/3w-9xxx.c~git-scsi-misc +++ a/drivers/scsi/3w-9xxx.c @@ -2010,6 +2010,7 @@ static int __devinit twa_probe(struct pc } pci_set_master(pdev); + pci_try_set_mwi(pdev); if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) diff -puN drivers/scsi/Kconfig~git-scsi-misc drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig~git-scsi-misc +++ a/drivers/scsi/Kconfig @@ -1288,17 +1288,6 @@ config SCSI_PAS16 To compile this driver as a module, choose M here: the module will be called pas16. -config SCSI_PSI240I - tristate "PSI240i support" - depends on ISA && SCSI - help - This is support for the PSI240i EIDE interface card which acts as a - SCSI host adapter. Please read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called psi240i. - config SCSI_QLOGIC_FAS tristate "Qlogic FAS SCSI support" depends on ISA && SCSI @@ -1359,21 +1348,6 @@ config SCSI_LPFC This lpfc driver supports the Emulex LightPulse Family of Fibre Channel PCI host adapters. -config SCSI_SEAGATE - tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support" - depends on X86 && ISA && SCSI - select CHECK_SIGNATURE - ---help--- - These are 8-bit SCSI controllers; the ST-01 is also supported by - this driver. It is explained in section 3.9 of the SCSI-HOWTO, - available from . If it - doesn't work out of the box, you may have to change some macros at - compiletime, which are described in . - - To compile this driver as a module, choose M here: the - module will be called seagate. - -# definitely looks not 64bit safe: config SCSI_SIM710 tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" depends on (EISA || MCA) && SCSI diff -puN drivers/scsi/Makefile~git-scsi-misc drivers/scsi/Makefile --- a/drivers/scsi/Makefile~git-scsi-misc +++ a/drivers/scsi/Makefile @@ -16,7 +16,6 @@ CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS -CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM subdir-$(CONFIG_PCMCIA) += pcmcia @@ -59,7 +58,6 @@ obj-$(CONFIG_MVME16x_SCSI) += 53c700.o m obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o -obj-$(CONFIG_SCSI_PSI240I) += psi240i.o obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o @@ -90,7 +88,6 @@ obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/ obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/ obj-$(CONFIG_SCSI_LPFC) += lpfc/ obj-$(CONFIG_SCSI_PAS16) += pas16.o -obj-$(CONFIG_SCSI_SEAGATE) += seagate.o obj-$(CONFIG_SCSI_T128) += t128.o obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o obj-$(CONFIG_SCSI_DTC3280) += dtc.o diff -puN drivers/scsi/NCR5380.c~git-scsi-misc drivers/scsi/NCR5380.c --- a/drivers/scsi/NCR5380.c~git-scsi-misc +++ a/drivers/scsi/NCR5380.c @@ -295,16 +295,16 @@ static __inline__ void initialize_SCp(Sc * various queues are valid. */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } } @@ -975,14 +975,14 @@ static int NCR5380_queue_command(Scsi_Cm case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingw++; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingr++; break; } diff -puN drivers/scsi/a2091.c~git-scsi-misc drivers/scsi/a2091.c --- a/drivers/scsi/a2091.c~git-scsi-misc +++ a/drivers/scsi/a2091.c @@ -73,18 +73,9 @@ static int dma_setup(struct scsi_cmnd *c } if (!dir_in) { - /* copy to bounce buffer for a write */ - if (cmd->use_sg) -#if 0 - panic ("scsi%ddma: incomplete s/g support", - instance->host_no); -#else + /* copy to bounce buffer for a write */ memcpy (HDATA(instance)->dma_bounce_buffer, cmd->SCp.ptr, cmd->SCp.this_residual); -#endif - else - memcpy (HDATA(instance)->dma_bounce_buffer, - cmd->request_buffer, cmd->request_bufflen); } } @@ -144,30 +135,13 @@ static void dma_stop(struct Scsi_Host *i /* copy from a bounce buffer, if necessary */ if (status && HDATA(instance)->dma_bounce_buffer) { - if (SCpnt && SCpnt->use_sg) { -#if 0 - panic ("scsi%d: incomplete s/g support", - instance->host_no); -#else - if( HDATA(instance)->dma_dir ) + if( HDATA(instance)->dma_dir ) memcpy (SCpnt->SCp.ptr, HDATA(instance)->dma_bounce_buffer, SCpnt->SCp.this_residual); - kfree (HDATA(instance)->dma_bounce_buffer); - HDATA(instance)->dma_bounce_buffer = NULL; - HDATA(instance)->dma_bounce_len = 0; - -#endif - } else { - if (HDATA(instance)->dma_dir && SCpnt) - memcpy (SCpnt->request_buffer, - HDATA(instance)->dma_bounce_buffer, - SCpnt->request_bufflen); - - kfree (HDATA(instance)->dma_bounce_buffer); - HDATA(instance)->dma_bounce_buffer = NULL; - HDATA(instance)->dma_bounce_len = 0; - } + kfree (HDATA(instance)->dma_bounce_buffer); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; } } diff -puN drivers/scsi/a3000.c~git-scsi-misc drivers/scsi/a3000.c --- a/drivers/scsi/a3000.c~git-scsi-misc +++ a/drivers/scsi/a3000.c @@ -70,12 +70,8 @@ static int dma_setup(struct scsi_cmnd *c if (!dir_in) { /* copy to bounce buffer for a write */ - if (cmd->use_sg) { - memcpy (HDATA(a3000_host)->dma_bounce_buffer, - cmd->SCp.ptr, cmd->SCp.this_residual); - } else - memcpy (HDATA(a3000_host)->dma_bounce_buffer, - cmd->request_buffer, cmd->request_bufflen); + memcpy (HDATA(a3000_host)->dma_bounce_buffer, + cmd->SCp.ptr, cmd->SCp.this_residual); } addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer); @@ -146,7 +142,7 @@ static void dma_stop(struct Scsi_Host *i /* copy from a bounce buffer, if necessary */ if (status && HDATA(instance)->dma_bounce_buffer) { - if (SCpnt && SCpnt->use_sg) { + if (SCpnt) { if (HDATA(instance)->dma_dir && SCpnt) memcpy (SCpnt->SCp.ptr, HDATA(instance)->dma_bounce_buffer, @@ -155,11 +151,6 @@ static void dma_stop(struct Scsi_Host *i HDATA(instance)->dma_bounce_buffer = NULL; HDATA(instance)->dma_bounce_len = 0; } else { - if (HDATA(instance)->dma_dir && SCpnt) - memcpy (SCpnt->request_buffer, - HDATA(instance)->dma_bounce_buffer, - SCpnt->request_bufflen); - kfree (HDATA(instance)->dma_bounce_buffer); HDATA(instance)->dma_bounce_buffer = NULL; HDATA(instance)->dma_bounce_len = 0; diff -puN drivers/scsi/aacraid/aachba.c~git-scsi-misc drivers/scsi/aacraid/aachba.c --- a/drivers/scsi/aacraid/aachba.c~git-scsi-misc +++ a/drivers/scsi/aacraid/aachba.c @@ -179,7 +179,7 @@ MODULE_PARM_DESC(check_interval, "Interv int aac_check_reset = 1; module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter."); +MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter. a value of -1 forces the reset to adapters programmed to ignore it."); int expose_physicals = -1; module_param(expose_physicals, int, S_IRUGO|S_IWUSR); @@ -1305,9 +1305,9 @@ int aac_get_adapter_info(struct aac_dev* (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid), dev->supplement_adapter_info.VpdInfo.Tsid); } - if (!aac_check_reset || + if (!aac_check_reset || ((aac_check_reset != 1) && (dev->supplement_adapter_info.SupportedOptions2 & - le32_to_cpu(AAC_OPTION_IGNORE_RESET))) { + le32_to_cpu(AAC_OPTION_IGNORE_RESET)))) { printk(KERN_INFO "%s%d: Reset Adapter Ignored\n", dev->name, dev->id); } @@ -1798,7 +1798,7 @@ static int aac_synchronize(struct scsi_c if (active) return SCSI_MLQUEUE_DEVICE_BUSY; - aac = (struct aac_dev *)scsicmd->device->host->hostdata; + aac = (struct aac_dev *)sdev->host->hostdata; if (aac->in_reset) return SCSI_MLQUEUE_HOST_BUSY; diff -puN drivers/scsi/aacraid/commsup.c~git-scsi-misc drivers/scsi/aacraid/commsup.c --- a/drivers/scsi/aacraid/commsup.c~git-scsi-misc +++ a/drivers/scsi/aacraid/commsup.c @@ -1217,12 +1217,13 @@ int aac_reset_adapter(struct aac_dev * a } /* Quiesce build, flush cache, write through mode */ - aac_send_shutdown(aac); + if (forced < 2) + aac_send_shutdown(aac); spin_lock_irqsave(host->host_lock, flagv); - retval = _aac_reset_adapter(aac, forced); + retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1))); spin_unlock_irqrestore(host->host_lock, flagv); - if (retval == -ENODEV) { + if ((forced < 2) && (retval == -ENODEV)) { /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */ struct fib * fibctx = aac_fib_alloc(aac); if (fibctx) { @@ -1372,14 +1373,14 @@ int aac_check_health(struct aac_dev * aa printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED); - if (!aac_check_reset || + if (!aac_check_reset || ((aac_check_reset != 1) && (aac->supplement_adapter_info.SupportedOptions2 & - le32_to_cpu(AAC_OPTION_IGNORE_RESET))) + le32_to_cpu(AAC_OPTION_IGNORE_RESET)))) goto out; host = aac->scsi_host_ptr; if (aac->thread->pid != current->pid) spin_lock_irqsave(host->host_lock, flagv); - BlinkLED = _aac_reset_adapter(aac, 0); + BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1); if (aac->thread->pid != current->pid) spin_unlock_irqrestore(host->host_lock, flagv); return BlinkLED; diff -puN drivers/scsi/aacraid/linit.c~git-scsi-misc drivers/scsi/aacraid/linit.c --- a/drivers/scsi/aacraid/linit.c~git-scsi-misc +++ a/drivers/scsi/aacraid/linit.c @@ -584,8 +584,11 @@ static int aac_eh_reset(struct scsi_cmnd * support a register, instead of a commanded, reset. */ if ((aac->supplement_adapter_info.SupportedOptions2 & - le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) == - le32_to_cpu(AAC_OPTION_MU_RESET)) + le32_to_cpu(AAC_OPTION_MU_RESET)) && + aac_check_reset && + ((aac_check_reset != 1) || + (aac->supplement_adapter_info.SupportedOptions2 & + le32_to_cpu(AAC_OPTION_IGNORE_RESET)))) aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */ return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ } diff -puN drivers/scsi/aacraid/rx.c~git-scsi-misc drivers/scsi/aacraid/rx.c --- a/drivers/scsi/aacraid/rx.c~git-scsi-misc +++ a/drivers/scsi/aacraid/rx.c @@ -549,7 +549,9 @@ int _aac_rx_init(struct aac_dev *dev) dev->OIMR = status = rx_readb (dev, MUnit.OIMR); if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) && !aac_rx_restart_adapter(dev, 0)) - ++restart; + /* Make sure the Hardware FIFO is empty */ + while ((++restart < 512) && + (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL)); /* * Check to see if the board panic'd while booting. */ diff -puN drivers/scsi/aha152x.c~git-scsi-misc drivers/scsi/aha152x.c --- a/drivers/scsi/aha152x.c~git-scsi-misc +++ a/drivers/scsi/aha152x.c @@ -260,6 +260,7 @@ #include #include #include +#include #include "aha152x.h" static LIST_HEAD(aha152x_host_list); @@ -558,9 +559,7 @@ struct aha152x_hostdata { struct aha152x_scdata { Scsi_Cmnd *next; /* next sc in queue */ struct completion *done;/* semaphore to block on */ - unsigned char aha_orig_cmd_len; - unsigned char aha_orig_cmnd[MAX_COMMAND_SIZE]; - int aha_orig_resid; + struct scsi_eh_save ses; }; /* access macros for hostdata */ @@ -1017,16 +1016,10 @@ static int aha152x_internal_queue(Scsi_C SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ - if ((phase & (check_condition|resetting)) || !scsi_sglist(SCpnt)) { - if (phase & check_condition) { - SCpnt->SCp.ptr = SCpnt->sense_buffer; - SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer); - scsi_set_resid(SCpnt, sizeof(SCpnt->sense_buffer)); - } else { - SCpnt->SCp.ptr = NULL; - SCpnt->SCp.this_residual = 0; - scsi_set_resid(SCpnt, 0); - } + if ((phase & resetting) || !scsi_sglist(SCpnt)) { + SCpnt->SCp.ptr = NULL; + SCpnt->SCp.this_residual = 0; + scsi_set_resid(SCpnt, 0); SCpnt->SCp.buffer = NULL; SCpnt->SCp.buffers_residual = 0; } else { @@ -1561,10 +1554,7 @@ static void busfree_run(struct Scsi_Host } #endif - /* restore old command */ - memcpy(cmd->cmnd, sc->aha_orig_cmnd, sizeof(cmd->cmnd)); - cmd->cmd_len = sc->aha_orig_cmd_len; - scsi_set_resid(cmd, sc->aha_orig_resid); + scsi_eh_restore_cmnd(cmd, &sc->ses); cmd->SCp.Status = SAM_STAT_CHECK_CONDITION; @@ -1587,22 +1577,10 @@ static void busfree_run(struct Scsi_Host DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr)); #endif - /* save old command */ sc = SCDATA(ptr); /* It was allocated in aha152x_internal_queue? */ BUG_ON(!sc); - memcpy(sc->aha_orig_cmnd, ptr->cmnd, - sizeof(ptr->cmnd)); - sc->aha_orig_cmd_len = ptr->cmd_len; - sc->aha_orig_resid = scsi_get_resid(ptr); - - ptr->cmnd[0] = REQUEST_SENSE; - ptr->cmnd[1] = 0; - ptr->cmnd[2] = 0; - ptr->cmnd[3] = 0; - ptr->cmnd[4] = sizeof(ptr->sense_buffer); - ptr->cmnd[5] = 0; - ptr->cmd_len = 6; + scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0); DO_UNLOCK(flags); aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done); diff -puN drivers/scsi/aha1542.c~git-scsi-misc drivers/scsi/aha1542.c --- a/drivers/scsi/aha1542.c~git-scsi-misc +++ a/drivers/scsi/aha1542.c @@ -51,15 +51,6 @@ #define SCSI_BUF_PA(address) isa_virt_to_bus(address) #define SCSI_SG_PA(sgent) (isa_page_to_bus(sg_page((sgent))) + (sgent)->offset) -static void BAD_DMA(void *address, unsigned int length) -{ - printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n", - address, - SCSI_BUF_PA(address), - length); - panic("Buffer at physical address > 16Mb used for aha1542"); -} - static void BAD_SG_DMA(Scsi_Cmnd * SCpnt, struct scatterlist *sgp, int nseg, @@ -597,8 +588,7 @@ static int aha1542_queuecommand(Scsi_Cmn unchar target = SCpnt->device->id; unchar lun = SCpnt->device->lun; unsigned long flags; - void *buff = SCpnt->request_buffer; - int bufflen = SCpnt->request_bufflen; + int bufflen = scsi_bufflen(SCpnt); int mbo; struct mailbox *mb; struct ccb *ccb; @@ -689,42 +679,29 @@ static int aha1542_queuecommand(Scsi_Cmn memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); - if (SCpnt->use_sg) { + if (bufflen) { struct scatterlist *sg; struct chain *cptr; #ifdef DEBUG unsigned char *ptr; #endif - int i; + int i, sg_count = scsi_sg_count(SCpnt); ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ - SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA); + SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count, + GFP_KERNEL | GFP_DMA); cptr = (struct chain *) SCpnt->host_scribble; if (cptr == NULL) { /* free the claimed mailbox slot */ HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL; return SCSI_MLQUEUE_HOST_BUSY; } - scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) { - if (sg->length == 0 || SCpnt->use_sg > 16 || - (((int) sg->offset) & 1) || (sg->length & 1)) { - unsigned char *ptr; - printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i); - scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) { - printk(KERN_CRIT "%d: %p %d\n", i, - sg_virt(sg), sg->length); - }; - printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr); - ptr = (unsigned char *) &cptr[i]; - for (i = 0; i < 18; i++) - printk("%02x ", ptr[i]); - panic("Foooooooood fight!"); - }; + scsi_for_each_sg(SCpnt, sg, sg_count, i) { any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg)); if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD) - BAD_SG_DMA(SCpnt, sg, SCpnt->use_sg, i); + BAD_SG_DMA(SCpnt, scsi_sglist(SCpnt), sg_count, i); any2scsi(cptr[i].datalen, sg->length); }; - any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain)); + any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr)); #ifdef DEBUG printk("cptr %x: ", cptr); @@ -735,10 +712,8 @@ static int aha1542_queuecommand(Scsi_Cmn } else { ccb[mbo].op = 0; /* SCSI Initiator Command */ SCpnt->host_scribble = NULL; - any2scsi(ccb[mbo].datalen, bufflen); - if (buff && SCSI_BUF_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD) - BAD_DMA(buff, bufflen); - any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(buff)); + any2scsi(ccb[mbo].datalen, 0); + any2scsi(ccb[mbo].dataptr, 0); }; ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */ ccb[mbo].rsalen = 16; diff -puN drivers/scsi/aic94xx/aic94xx_dev.c~git-scsi-misc drivers/scsi/aic94xx/aic94xx_dev.c --- a/drivers/scsi/aic94xx/aic94xx_dev.c~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_dev.c @@ -165,7 +165,7 @@ static int asd_init_target_ddb(struct do if (dev->port->oob_mode != SATA_OOB_MODE) { flags |= OPEN_REQUIRED; if ((dev->dev_type == SATA_DEV) || - (dev->tproto & SAS_PROTO_STP)) { + (dev->tproto & SAS_PROTOCOL_STP)) { struct smp_resp *rps_resp = &dev->sata_dev.rps_resp; if (rps_resp->frame_type == SMP_RESPONSE && rps_resp->function == SMP_REPORT_PHY_SATA && @@ -193,7 +193,7 @@ static int asd_init_target_ddb(struct do asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags); flags = 0; - if (dev->tproto & SAS_PROTO_STP) + if (dev->tproto & SAS_PROTOCOL_STP) flags |= STP_CL_POL_NO_TX; asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags); @@ -201,7 +201,7 @@ static int asd_init_target_ddb(struct do asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF); asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF); - if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) { + if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { i = asd_init_sata(dev); if (i < 0) { asd_free_ddb(asd_ha, ddb); diff -puN drivers/scsi/aic94xx/aic94xx_dump.c~git-scsi-misc drivers/scsi/aic94xx/aic94xx_dump.c --- a/drivers/scsi/aic94xx/aic94xx_dump.c~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_dump.c @@ -903,11 +903,11 @@ void asd_dump_frame_rcvd(struct asd_phy int i; switch ((dl->status_block[1] & 0x70) >> 3) { - case SAS_PROTO_STP: + case SAS_PROTOCOL_STP: ASD_DPRINTK("STP proto device-to-host FIS:\n"); break; default: - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: ASD_DPRINTK("SAS proto IDENTIFY:\n"); break; } diff -puN drivers/scsi/aic94xx/aic94xx_hwi.c~git-scsi-misc drivers/scsi/aic94xx/aic94xx_hwi.c --- a/drivers/scsi/aic94xx/aic94xx_hwi.c~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -91,7 +91,7 @@ static int asd_init_phy(struct asd_phy * sas_phy->enabled = 1; sas_phy->class = SAS; - sas_phy->iproto = SAS_PROTO_ALL; + sas_phy->iproto = SAS_PROTOCOL_ALL; sas_phy->tproto = 0; sas_phy->type = PHY_TYPE_PHYSICAL; sas_phy->role = PHY_ROLE_INITIATOR; diff -puN drivers/scsi/aic94xx/aic94xx_hwi.h~git-scsi-misc drivers/scsi/aic94xx/aic94xx_hwi.h --- a/drivers/scsi/aic94xx/aic94xx_hwi.h~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_hwi.h @@ -72,6 +72,7 @@ struct flash_struct { u8 manuf; u8 dev_id; u8 sec_prot; + u8 method; u32 dir_offs; }; @@ -216,6 +217,8 @@ struct asd_ha_struct { struct dma_pool *scb_pool; struct asd_seq_data seq; /* sequencer related */ + u32 bios_status; + const struct firmware *bios_image; }; /* ---------- Common macros ---------- */ diff -puN drivers/scsi/aic94xx/aic94xx_init.c~git-scsi-misc drivers/scsi/aic94xx/aic94xx_init.c --- a/drivers/scsi/aic94xx/aic94xx_init.c~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_init.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -36,6 +37,7 @@ #include "aic94xx_reg.h" #include "aic94xx_hwi.h" #include "aic94xx_seq.h" +#include "aic94xx_sds.h" /* The format is "version.release.patchlevel" */ #define ASD_DRIVER_VERSION "1.0.3" @@ -313,6 +315,181 @@ static ssize_t asd_show_dev_pcba_sn(stru } static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL); +#define FLASH_CMD_NONE 0x00 +#define FLASH_CMD_UPDATE 0x01 +#define FLASH_CMD_VERIFY 0x02 + +struct flash_command { + u8 command[8]; + int code; +}; + +static struct flash_command flash_command_table[] = +{ + {"verify", FLASH_CMD_VERIFY}, + {"update", FLASH_CMD_UPDATE}, + {"", FLASH_CMD_NONE} /* Last entry should be NULL. */ +}; + +struct error_bios { + char *reason; + int err_code; +}; + +static struct error_bios flash_error_table[] = +{ + {"Failed to open bios image file", FAIL_OPEN_BIOS_FILE}, + {"PCI ID mismatch", FAIL_CHECK_PCI_ID}, + {"Checksum mismatch", FAIL_CHECK_SUM}, + {"Unknown Error", FAIL_UNKNOWN}, + {"Failed to verify.", FAIL_VERIFY}, + {"Failed to reset flash chip.", FAIL_RESET_FLASH}, + {"Failed to find flash chip type.", FAIL_FIND_FLASH_ID}, + {"Failed to erash flash chip.", FAIL_ERASE_FLASH}, + {"Failed to program flash chip.", FAIL_WRITE_FLASH}, + {"Flash in progress", FLASH_IN_PROGRESS}, + {"Image file size Error", FAIL_FILE_SIZE}, + {"Input parameter error", FAIL_PARAMETERS}, + {"Out of memory", FAIL_OUT_MEMORY}, + {"OK", 0} /* Last entry err_code = 0. */ +}; + +static ssize_t asd_store_update_bios(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); + char *cmd_ptr, *filename_ptr; + struct bios_file_header header, *hdr_ptr; + int res, i; + u32 csum = 0; + int flash_command = FLASH_CMD_NONE; + int err = 0; + + cmd_ptr = kzalloc(count*2, GFP_KERNEL); + + if (!cmd_ptr) { + err = FAIL_OUT_MEMORY; + goto out; + } + + filename_ptr = cmd_ptr + count; + res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); + if (res != 2) { + err = FAIL_PARAMETERS; + goto out1; + } + + for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { + if (!memcmp(flash_command_table[i].command, + cmd_ptr, strlen(cmd_ptr))) { + flash_command = flash_command_table[i].code; + break; + } + } + if (flash_command == FLASH_CMD_NONE) { + err = FAIL_PARAMETERS; + goto out1; + } + + if (asd_ha->bios_status == FLASH_IN_PROGRESS) { + err = FLASH_IN_PROGRESS; + goto out1; + } + err = request_firmware(&asd_ha->bios_image, + filename_ptr, + &asd_ha->pcidev->dev); + if (err) { + asd_printk("Failed to load bios image file %s, error %d\n", + filename_ptr, err); + err = FAIL_OPEN_BIOS_FILE; + goto out1; + } + + hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data; + + if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor || + hdr_ptr->contrl_id.device != asd_ha->pcidev->device) && + (hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor || + hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) { + + ASD_DPRINTK("The PCI vendor or device id does not match\n"); + ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x" + " pci vendor=%x pci dev=%x\n", + hdr_ptr->contrl_id.vendor, + hdr_ptr->contrl_id.device, + hdr_ptr->contrl_id.sub_vendor, + hdr_ptr->contrl_id.sub_device, + asd_ha->pcidev->vendor, + asd_ha->pcidev->device); + err = FAIL_CHECK_PCI_ID; + goto out2; + } + + if (hdr_ptr->filelen != asd_ha->bios_image->size) { + err = FAIL_FILE_SIZE; + goto out2; + } + + /* calculate checksum */ + for (i = 0; i < hdr_ptr->filelen; i++) + csum += asd_ha->bios_image->data[i]; + + if ((csum & 0x0000ffff) != hdr_ptr->checksum) { + ASD_DPRINTK("BIOS file checksum mismatch\n"); + err = FAIL_CHECK_SUM; + goto out2; + } + if (flash_command == FLASH_CMD_UPDATE) { + asd_ha->bios_status = FLASH_IN_PROGRESS; + err = asd_write_flash_seg(asd_ha, + &asd_ha->bios_image->data[sizeof(*hdr_ptr)], + 0, hdr_ptr->filelen-sizeof(*hdr_ptr)); + if (!err) + err = asd_verify_flash_seg(asd_ha, + &asd_ha->bios_image->data[sizeof(*hdr_ptr)], + 0, hdr_ptr->filelen-sizeof(*hdr_ptr)); + } else { + asd_ha->bios_status = FLASH_IN_PROGRESS; + err = asd_verify_flash_seg(asd_ha, + &asd_ha->bios_image->data[sizeof(header)], + 0, hdr_ptr->filelen-sizeof(header)); + } + +out2: + release_firmware(asd_ha->bios_image); +out1: + kfree(cmd_ptr); +out: + asd_ha->bios_status = err; + + if (!err) + return count; + else + return -err; +} + +static ssize_t asd_show_update_bios(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i; + struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); + + for (i = 0; flash_error_table[i].err_code != 0; i++) { + if (flash_error_table[i].err_code == asd_ha->bios_status) + break; + } + if (asd_ha->bios_status != FLASH_IN_PROGRESS) + asd_ha->bios_status = FLASH_OK; + + return snprintf(buf, PAGE_SIZE, "status=%x %s\n", + flash_error_table[i].err_code, + flash_error_table[i].reason); +} + +static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO, + asd_show_update_bios, asd_store_update_bios); + static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha) { int err; @@ -328,9 +505,14 @@ static int asd_create_dev_attrs(struct a err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); if (err) goto err_biosb; + err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios); + if (err) + goto err_update_bios; return 0; +err_update_bios: + device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); err_biosb: device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); err_rev: @@ -343,6 +525,7 @@ static void asd_remove_dev_attrs(struct device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision); device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); + device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios); } /* The first entry, 0, is used for dynamic ids, the rest for devices @@ -589,6 +772,7 @@ static int __devinit asd_pci_probe(struc asd_ha->sas_ha.dev = &asd_ha->pcidev->dev; asd_ha->sas_ha.lldd_ha = asd_ha; + asd_ha->bios_status = FLASH_OK; asd_ha->name = asd_dev->name; asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev)); diff -puN drivers/scsi/aic94xx/aic94xx_scb.c~git-scsi-misc drivers/scsi/aic94xx/aic94xx_scb.c --- a/drivers/scsi/aic94xx/aic94xx_scb.c~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_scb.c @@ -788,12 +788,12 @@ void asd_build_control_phy(struct asd_as /* initiator port settings are in the hi nibble */ if (phy->sas_phy.role == PHY_ROLE_INITIATOR) - control_phy->port_type = SAS_PROTO_ALL << 4; + control_phy->port_type = SAS_PROTOCOL_ALL << 4; else if (phy->sas_phy.role == PHY_ROLE_TARGET) - control_phy->port_type = SAS_PROTO_ALL; + control_phy->port_type = SAS_PROTOCOL_ALL; else control_phy->port_type = - (SAS_PROTO_ALL << 4) | SAS_PROTO_ALL; + (SAS_PROTOCOL_ALL << 4) | SAS_PROTOCOL_ALL; /* link reset retries, this should be nominal */ control_phy->link_reset_retries = 10; diff -puN drivers/scsi/aic94xx/aic94xx_sds.c~git-scsi-misc drivers/scsi/aic94xx/aic94xx_sds.c --- a/drivers/scsi/aic94xx/aic94xx_sds.c~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_sds.c @@ -30,6 +30,7 @@ #include "aic94xx.h" #include "aic94xx_reg.h" +#include "aic94xx_sds.h" /* ---------- OCM stuff ---------- */ @@ -1083,3 +1084,391 @@ out: kfree(flash_dir); return err; } + +/** + * asd_verify_flash_seg - verify data with flash memory + * @asd_ha: pointer to the host adapter structure + * @src: pointer to the source data to be verified + * @dest_offset: offset from flash memory + * @bytes_to_verify: total bytes to verify + */ +int asd_verify_flash_seg(struct asd_ha_struct *asd_ha, + void *src, u32 dest_offset, u32 bytes_to_verify) +{ + u8 *src_buf; + u8 flash_char; + int err; + u32 nv_offset, reg, i; + + reg = asd_ha->hw_prof.flash.bar; + src_buf = NULL; + + err = FLASH_OK; + nv_offset = dest_offset; + src_buf = (u8 *)src; + for (i = 0; i < bytes_to_verify; i++) { + flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i); + if (flash_char != src_buf[i]) { + err = FAIL_VERIFY; + break; + } + } + return err; +} + +/** + * asd_write_flash_seg - write data into flash memory + * @asd_ha: pointer to the host adapter structure + * @src: pointer to the source data to be written + * @dest_offset: offset from flash memory + * @bytes_to_write: total bytes to write + */ +int asd_write_flash_seg(struct asd_ha_struct *asd_ha, + void *src, u32 dest_offset, u32 bytes_to_write) +{ + u8 *src_buf; + u32 nv_offset, reg, i; + int err; + + reg = asd_ha->hw_prof.flash.bar; + src_buf = NULL; + + err = asd_check_flash_type(asd_ha); + if (err) { + ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err); + return err; + } + + nv_offset = dest_offset; + err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write); + if (err) { + ASD_DPRINTK("Erase failed at offset:0x%x\n", + nv_offset); + return err; + } + + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + + src_buf = (u8 *)src; + for (i = 0; i < bytes_to_write; i++) { + /* Setup program command sequence */ + switch (asd_ha->hw_prof.flash.method) { + case FLASH_METHOD_A: + { + asd_write_reg_byte(asd_ha, + (reg + 0xAAA), 0xAA); + asd_write_reg_byte(asd_ha, + (reg + 0x555), 0x55); + asd_write_reg_byte(asd_ha, + (reg + 0xAAA), 0xA0); + asd_write_reg_byte(asd_ha, + (reg + nv_offset + i), + (*(src_buf + i))); + break; + } + case FLASH_METHOD_B: + { + asd_write_reg_byte(asd_ha, + (reg + 0x555), 0xAA); + asd_write_reg_byte(asd_ha, + (reg + 0x2AA), 0x55); + asd_write_reg_byte(asd_ha, + (reg + 0x555), 0xA0); + asd_write_reg_byte(asd_ha, + (reg + nv_offset + i), + (*(src_buf + i))); + break; + } + default: + break; + } + if (asd_chk_write_status(asd_ha, + (nv_offset + i), 0) != 0) { + ASD_DPRINTK("aicx: Write failed at offset:0x%x\n", + reg + nv_offset + i); + return FAIL_WRITE_FLASH; + } + } + + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + return 0; +} + +int asd_chk_write_status(struct asd_ha_struct *asd_ha, + u32 sector_addr, u8 erase_flag) +{ + u32 reg; + u32 loop_cnt; + u8 nv_data1, nv_data2; + u8 toggle_bit1; + + /* + * Read from DQ2 requires sector address + * while it's dont care for DQ6 + */ + reg = asd_ha->hw_prof.flash.bar; + + for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) { + nv_data1 = asd_read_reg_byte(asd_ha, reg); + nv_data2 = asd_read_reg_byte(asd_ha, reg); + + toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6) + ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6)); + + if (toggle_bit1 == 0) { + return 0; + } else { + if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) { + nv_data1 = asd_read_reg_byte(asd_ha, + reg); + nv_data2 = asd_read_reg_byte(asd_ha, + reg); + toggle_bit1 = + ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6) + ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6)); + + if (toggle_bit1 == 0) + return 0; + } + } + + /* + * ERASE is a sector-by-sector operation and requires + * more time to finish while WRITE is byte-byte-byte + * operation and takes lesser time to finish. + * + * For some strange reason a reduced ERASE delay gives different + * behaviour across different spirit boards. Hence we set + * a optimum balance of 50mus for ERASE which works well + * across all boards. + */ + if (erase_flag) { + udelay(FLASH_STATUS_ERASE_DELAY_COUNT); + } else { + udelay(FLASH_STATUS_WRITE_DELAY_COUNT); + } + } + return -1; +} + +/** + * asd_hwi_erase_nv_sector - Erase the flash memory sectors. + * @asd_ha: pointer to the host adapter structure + * @flash_addr: pointer to offset from flash memory + * @size: total bytes to erase. + */ +int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size) +{ + u32 reg; + u32 sector_addr; + + reg = asd_ha->hw_prof.flash.bar; + + /* sector staring address */ + sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK; + + /* + * Erasing an flash sector needs to be done in six consecutive + * write cyles. + */ + while (sector_addr < flash_addr+size) { + switch (asd_ha->hw_prof.flash.method) { + case FLASH_METHOD_A: + asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55); + asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80); + asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55); + asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30); + break; + case FLASH_METHOD_B: + asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); + asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30); + break; + default: + break; + } + + if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0) + return FAIL_ERASE_FLASH; + + sector_addr += FLASH_SECTOR_SIZE; + } + + return 0; +} + +int asd_check_flash_type(struct asd_ha_struct *asd_ha) +{ + u8 manuf_id; + u8 dev_id; + u8 sec_prot; + u32 inc; + u32 reg; + int err; + + /* get Flash memory base address */ + reg = asd_ha->hw_prof.flash.bar; + + /* Determine flash info */ + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + + asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN; + asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN; + asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN; + + /* Get flash info. This would most likely be AMD Am29LV family flash. + * First try the sequence for word mode. It is the same as for + * 008B (byte mode only), 160B (word mode) and 800D (word mode). + */ + inc = asd_ha->hw_prof.flash.wide ? 2 : 1; + asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA); + asd_write_reg_byte(asd_ha, reg + 0x555, 0x55); + asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90); + manuf_id = asd_read_reg_byte(asd_ha, reg); + dev_id = asd_read_reg_byte(asd_ha, reg + inc); + sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc); + /* Get out of autoselect mode. */ + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) " + "sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot); + err = asd_reset_flash(asd_ha); + if (err != 0) + return err; + + switch (manuf_id) { + case FLASH_MANUF_ID_AMD: + switch (sec_prot) { + case FLASH_DEV_ID_AM29LV800DT: + case FLASH_DEV_ID_AM29LV640MT: + case FLASH_DEV_ID_AM29F800B: + asd_ha->hw_prof.flash.method = FLASH_METHOD_A; + break; + default: + break; + } + break; + case FLASH_MANUF_ID_ST: + switch (sec_prot) { + case FLASH_DEV_ID_STM29W800DT: + case FLASH_DEV_ID_STM29LV640: + asd_ha->hw_prof.flash.method = FLASH_METHOD_A; + break; + default: + break; + } + break; + case FLASH_MANUF_ID_FUJITSU: + switch (sec_prot) { + case FLASH_DEV_ID_MBM29LV800TE: + case FLASH_DEV_ID_MBM29DL800TA: + asd_ha->hw_prof.flash.method = FLASH_METHOD_A; + break; + } + break; + case FLASH_MANUF_ID_MACRONIX: + switch (sec_prot) { + case FLASH_DEV_ID_MX29LV800BT: + asd_ha->hw_prof.flash.method = FLASH_METHOD_A; + break; + } + break; + } + + if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) { + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + + /* Issue Unlock sequence for AM29LV008BT */ + asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90); + manuf_id = asd_read_reg_byte(asd_ha, reg); + dev_id = asd_read_reg_byte(asd_ha, reg + inc); + sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc); + + ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot" + "(0x%x)\n", manuf_id, dev_id, sec_prot); + + err = asd_reset_flash(asd_ha); + if (err != 0) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + + switch (manuf_id) { + case FLASH_MANUF_ID_AMD: + switch (dev_id) { + case FLASH_DEV_ID_AM29LV008BT: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + default: + break; + } + break; + case FLASH_MANUF_ID_ST: + switch (dev_id) { + case FLASH_DEV_ID_STM29008: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + default: + break; + } + break; + case FLASH_MANUF_ID_FUJITSU: + switch (dev_id) { + case FLASH_DEV_ID_MBM29LV008TA: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + } + break; + case FLASH_MANUF_ID_INTEL: + switch (dev_id) { + case FLASH_DEV_ID_I28LV00TAT: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + } + break; + case FLASH_MANUF_ID_MACRONIX: + switch (dev_id) { + case FLASH_DEV_ID_I28LV00TAT: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + } + break; + default: + return FAIL_FIND_FLASH_ID; + } + } + + if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) + return FAIL_FIND_FLASH_ID; + + asd_ha->hw_prof.flash.manuf = manuf_id; + asd_ha->hw_prof.flash.dev_id = dev_id; + asd_ha->hw_prof.flash.sec_prot = sec_prot; + return 0; +} diff -puN /dev/null drivers/scsi/aic94xx/aic94xx_sds.h --- /dev/null +++ a/drivers/scsi/aic94xx/aic94xx_sds.h @@ -0,0 +1,121 @@ +/* + * Aic94xx SAS/SATA driver hardware interface header file. + * + * Copyright (C) 2005 Adaptec, Inc. All rights reserved. + * Copyright (C) 2005 Gilbert Wu + * + * This file is licensed under GPLv2. + * + * This file is part of the aic94xx driver. + * + * The aic94xx driver is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * The aic94xx driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the aic94xx driver; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef _AIC94XX_SDS_H_ +#define _AIC94XX_SDS_H_ + +enum { + FLASH_METHOD_UNKNOWN, + FLASH_METHOD_A, + FLASH_METHOD_B +}; + +#define FLASH_MANUF_ID_AMD 0x01 +#define FLASH_MANUF_ID_ST 0x20 +#define FLASH_MANUF_ID_FUJITSU 0x04 +#define FLASH_MANUF_ID_MACRONIX 0xC2 +#define FLASH_MANUF_ID_INTEL 0x89 +#define FLASH_MANUF_ID_UNKNOWN 0xFF + +#define FLASH_DEV_ID_AM29LV008BT 0x3E +#define FLASH_DEV_ID_AM29LV800DT 0xDA +#define FLASH_DEV_ID_STM29W800DT 0xD7 +#define FLASH_DEV_ID_STM29LV640 0xDE +#define FLASH_DEV_ID_STM29008 0xEA +#define FLASH_DEV_ID_MBM29LV800TE 0xDA +#define FLASH_DEV_ID_MBM29DL800TA 0x4A +#define FLASH_DEV_ID_MBM29LV008TA 0x3E +#define FLASH_DEV_ID_AM29LV640MT 0x7E +#define FLASH_DEV_ID_AM29F800B 0xD6 +#define FLASH_DEV_ID_MX29LV800BT 0xDA +#define FLASH_DEV_ID_MX29LV008CT 0xDA +#define FLASH_DEV_ID_I28LV00TAT 0x3E +#define FLASH_DEV_ID_UNKNOWN 0xFF + +/* status bit mask values */ +#define FLASH_STATUS_BIT_MASK_DQ6 0x40 +#define FLASH_STATUS_BIT_MASK_DQ5 0x20 +#define FLASH_STATUS_BIT_MASK_DQ2 0x04 + +/* minimum value in micro seconds needed for checking status */ +#define FLASH_STATUS_ERASE_DELAY_COUNT 50 +#define FLASH_STATUS_WRITE_DELAY_COUNT 25 + +#define FLASH_SECTOR_SIZE 0x010000 +#define FLASH_SECTOR_SIZE_MASK 0xffff0000 + +#define FLASH_OK 0x000000 +#define FAIL_OPEN_BIOS_FILE 0x000100 +#define FAIL_CHECK_PCI_ID 0x000200 +#define FAIL_CHECK_SUM 0x000300 +#define FAIL_UNKNOWN 0x000400 +#define FAIL_VERIFY 0x000500 +#define FAIL_RESET_FLASH 0x000600 +#define FAIL_FIND_FLASH_ID 0x000700 +#define FAIL_ERASE_FLASH 0x000800 +#define FAIL_WRITE_FLASH 0x000900 +#define FAIL_FILE_SIZE 0x000a00 +#define FAIL_PARAMETERS 0x000b00 +#define FAIL_OUT_MEMORY 0x000c00 +#define FLASH_IN_PROGRESS 0x001000 + +struct controller_id { + u32 vendor; /* PCI Vendor ID */ + u32 device; /* PCI Device ID */ + u32 sub_vendor; /* PCI Subvendor ID */ + u32 sub_device; /* PCI Subdevice ID */ +}; + +struct image_info { + u32 ImageId; /* Identifies the image */ + u32 ImageOffset; /* Offset the beginning of the file */ + u32 ImageLength; /* length of the image */ + u32 ImageChecksum; /* Image checksum */ + u32 ImageVersion; /* Version of the image, could be build number */ +}; + +struct bios_file_header { + u8 signature[32]; /* Signature/Cookie to identify the file */ + u32 checksum; /*Entire file checksum with this field zero */ + u32 antidote; /* Entire file checksum with this field 0xFFFFFFFF */ + struct controller_id contrl_id; /*PCI id to identify the controller */ + u32 filelen; /*Length of the entire file*/ + u32 chunk_num; /*The chunk/part number for multiple Image files */ + u32 total_chunks; /*Total number of chunks/parts in the image file */ + u32 num_images; /* Number of images in the file */ + u32 build_num; /* Build number of this image */ + struct image_info image_header; +}; + +int asd_verify_flash_seg(struct asd_ha_struct *asd_ha, + void *src, u32 dest_offset, u32 bytes_to_verify); +int asd_write_flash_seg(struct asd_ha_struct *asd_ha, + void *src, u32 dest_offset, u32 bytes_to_write); +int asd_chk_write_status(struct asd_ha_struct *asd_ha, + u32 sector_addr, u8 erase_flag); +int asd_check_flash_type(struct asd_ha_struct *asd_ha); +int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, + u32 flash_addr, u32 size); +#endif diff -puN drivers/scsi/aic94xx/aic94xx_task.c~git-scsi-misc drivers/scsi/aic94xx/aic94xx_task.c --- a/drivers/scsi/aic94xx/aic94xx_task.c~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_task.c @@ -187,7 +187,7 @@ static void asd_get_response_tasklet(str ts->buf_valid_size = 0; edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index]; r = edb->vaddr; - if (task->task_proto == SAS_PROTO_SSP) { + if (task->task_proto == SAS_PROTOCOL_SSP) { struct ssp_response_iu *iu = r + 16 + sizeof(struct ssp_frame_hdr); @@ -341,14 +341,14 @@ Again: } switch (task->task_proto) { - case SATA_PROTO: - case SAS_PROTO_STP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: asd_unbuild_ata_ascb(ascb); break; - case SAS_PROTO_SMP: + case SAS_PROTOCOL_SMP: asd_unbuild_smp_ascb(ascb); break; - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: asd_unbuild_ssp_ascb(ascb); default: break; @@ -586,17 +586,17 @@ int asd_execute_task(struct sas_task *ta list_for_each_entry(a, &alist, list) { t = a->uldd_task; a->uldd_timer = 1; - if (t->task_proto & SAS_PROTO_STP) - t->task_proto = SAS_PROTO_STP; + if (t->task_proto & SAS_PROTOCOL_STP) + t->task_proto = SAS_PROTOCOL_STP; switch (t->task_proto) { - case SATA_PROTO: - case SAS_PROTO_STP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: res = asd_build_ata_ascb(a, t, gfp_flags); break; - case SAS_PROTO_SMP: + case SAS_PROTOCOL_SMP: res = asd_build_smp_ascb(a, t, gfp_flags); break; - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: res = asd_build_ssp_ascb(a, t, gfp_flags); break; default: @@ -633,14 +633,14 @@ out_err_unmap: t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&t->task_state_lock, flags); switch (t->task_proto) { - case SATA_PROTO: - case SAS_PROTO_STP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: asd_unbuild_ata_ascb(a); break; - case SAS_PROTO_SMP: + case SAS_PROTOCOL_SMP: asd_unbuild_smp_ascb(a); break; - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: asd_unbuild_ssp_ascb(a); default: break; diff -puN drivers/scsi/aic94xx/aic94xx_tmf.c~git-scsi-misc drivers/scsi/aic94xx/aic94xx_tmf.c --- a/drivers/scsi/aic94xx/aic94xx_tmf.c~git-scsi-misc +++ a/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -372,21 +372,21 @@ int asd_abort_task(struct sas_task *task scb->header.opcode = ABORT_TASK; switch (task->task_proto) { - case SATA_PROTO: - case SAS_PROTO_STP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: scb->abort_task.proto_conn_rate = (1 << 5); /* STP */ break; - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: scb->abort_task.proto_conn_rate = (1 << 4); /* SSP */ scb->abort_task.proto_conn_rate |= task->dev->linkrate; break; - case SAS_PROTO_SMP: + case SAS_PROTOCOL_SMP: break; default: break; } - if (task->task_proto == SAS_PROTO_SSP) { + if (task->task_proto == SAS_PROTOCOL_SSP) { scb->abort_task.ssp_frame.frame_type = SSP_TASK; memcpy(scb->abort_task.ssp_frame.hashed_dest_addr, task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); @@ -512,7 +512,7 @@ static int asd_initiate_ssp_tmf(struct d int res = 1; struct scb *scb; - if (!(dev->tproto & SAS_PROTO_SSP)) + if (!(dev->tproto & SAS_PROTOCOL_SSP)) return TMF_RESP_FUNC_ESUPP; ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); diff -puN drivers/scsi/atari_NCR5380.c~git-scsi-misc drivers/scsi/atari_NCR5380.c --- a/drivers/scsi/atari_NCR5380.c~git-scsi-misc +++ a/drivers/scsi/atari_NCR5380.c @@ -511,9 +511,9 @@ static inline void initialize_SCp(Scsi_C * various queues are valid. */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; /* ++roman: Try to merge some scatter-buffers if they are at @@ -523,8 +523,8 @@ static inline void initialize_SCp(Scsi_C } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *)cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } } @@ -936,21 +936,21 @@ static int NCR5380_queue_command(Scsi_Cm } # endif # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) # endif switch (cmd->cmnd[0]) { case WRITE: case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingw++; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingr++; break; } @@ -1352,21 +1352,21 @@ static irqreturn_t NCR5380_intr(int irq, static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd) { # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) # endif switch (cmd->cmnd[0]) { case WRITE: case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ + /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/ hostdata->pendingw--; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ + /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/ hostdata->pendingr--; break; } diff -puN drivers/scsi/atp870u.c~git-scsi-misc drivers/scsi/atp870u.c --- a/drivers/scsi/atp870u.c~git-scsi-misc +++ a/drivers/scsi/atp870u.c @@ -471,18 +471,8 @@ go_42: /* * Complete the command */ - if (workreq->use_sg) { - pci_unmap_sg(dev->pdev, - (struct scatterlist *)workreq->request_buffer, - workreq->use_sg, - workreq->sc_data_direction); - } else if (workreq->request_bufflen && - workreq->sc_data_direction != DMA_NONE) { - pci_unmap_single(dev->pdev, - workreq->SCp.dma_handle, - workreq->request_bufflen, - workreq->sc_data_direction); - } + scsi_dma_unmap(workreq); + spin_lock_irqsave(dev->host->host_lock, flags); (*workreq->scsi_done) (workreq); #ifdef ED_DBGP @@ -624,7 +614,7 @@ static int atp870u_queuecommand(struct s c = scmd_channel(req_p); req_p->sense_buffer[0]=0; - req_p->resid = 0; + scsi_set_resid(req_p, 0); if (scmd_channel(req_p) > 1) { req_p->result = 0x00040000; done(req_p); @@ -722,7 +712,6 @@ static void send_s870(struct atp_unit *d unsigned short int tmpcip, w; unsigned long l, bttl = 0; unsigned int workport; - struct scatterlist *sgpnt; unsigned long sg_count; if (dev->in_snd[c] != 0) { @@ -793,6 +782,8 @@ oktosend: } printk("\n"); #endif + l = scsi_bufflen(workreq); + if (dev->dev_id == ATP885_DEVID) { j = inb(dev->baseport + 0x29) & 0xfe; outb(j, dev->baseport + 0x29); @@ -800,12 +791,11 @@ oktosend: } if (workreq->cmnd[0] == READ_CAPACITY) { - if (workreq->request_bufflen > 8) { - workreq->request_bufflen = 0x08; - } + if (l > 8) + l = 8; } if (workreq->cmnd[0] == 0x00) { - workreq->request_bufflen = 0; + l = 0; } tmport = workport + 0x1b; @@ -852,40 +842,8 @@ oktosend: #ifdef ED_DBGP printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp); #endif - /* - * Figure out the transfer size - */ - if (workreq->use_sg) { -#ifdef ED_DBGP - printk("Using SGL\n"); -#endif - l = 0; - - sgpnt = (struct scatterlist *) workreq->request_buffer; - sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg, - workreq->sc_data_direction); - - for (i = 0; i < workreq->use_sg; i++) { - if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) { - panic("Foooooooood fight!"); - } - l += sgpnt[i].length; - } -#ifdef ED_DBGP - printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l); -#endif - } else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) { -#ifdef ED_DBGP - printk("Not using SGL\n"); -#endif - workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer, - workreq->request_bufflen, - workreq->sc_data_direction); - l = workreq->request_bufflen; -#ifdef ED_DBGP - printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l); -#endif - } else l = 0; + + sg_count = scsi_dma_map(workreq); /* * Write transfer size */ @@ -938,16 +896,16 @@ oktosend: * a linear chain. */ - if (workreq->use_sg) { - sgpnt = (struct scatterlist *) workreq->request_buffer; + if (l) { + struct scatterlist *sgpnt; i = 0; - for (j = 0; j < workreq->use_sg; j++) { - bttl = sg_dma_address(&sgpnt[j]); - l=sg_dma_len(&sgpnt[j]); + scsi_for_each_sg(workreq, sgpnt, sg_count, j) { + bttl = sg_dma_address(sgpnt); + l=sg_dma_len(sgpnt); #ifdef ED_DBGP - printk("1. bttl %x, l %x\n",bttl, l); + printk("1. bttl %x, l %x\n",bttl, l); #endif - while (l > 0x10000) { + while (l > 0x10000) { (((u16 *) (prd))[i + 3]) = 0x0000; (((u16 *) (prd))[i + 2]) = 0x0000; (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); @@ -965,32 +923,6 @@ oktosend: printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); printk("2. bttl %x, l %x\n",bttl, l); #endif - } else { - /* - * For a linear request write a chain of blocks - */ - bttl = workreq->SCp.dma_handle; - l = workreq->request_bufflen; - i = 0; -#ifdef ED_DBGP - printk("3. bttl %x, l %x\n",bttl, l); -#endif - while (l > 0x10000) { - (((u16 *) (prd))[i + 3]) = 0x0000; - (((u16 *) (prd))[i + 2]) = 0x0000; - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); - l -= 0x10000; - bttl += 0x10000; - i += 0x04; - } - (((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000); - (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); -#ifdef ED_DBGP - printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); - printk("4. bttl %x, l %x\n",bttl, l); -#endif - } tmpcip += 4; #ifdef ED_DBGP diff -puN drivers/scsi/constants.c~git-scsi-misc drivers/scsi/constants.c --- a/drivers/scsi/constants.c~git-scsi-misc +++ a/drivers/scsi/constants.c @@ -362,7 +362,6 @@ void scsi_print_command(struct scsi_cmnd EXPORT_SYMBOL(scsi_print_command); /** - * * scsi_print_status - print scsi status description * @scsi_status: scsi status value * @@ -1369,7 +1368,7 @@ EXPORT_SYMBOL(scsi_print_sense); static const char * const hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", -"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"}; +"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"}; #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table) static const char * const driverbyte_table[]={ diff -puN drivers/scsi/eata_pio.c~git-scsi-misc drivers/scsi/eata_pio.c --- a/drivers/scsi/eata_pio.c~git-scsi-misc +++ a/drivers/scsi/eata_pio.c @@ -385,7 +385,7 @@ static int eata_pio_queue(struct scsi_cm cp->DataIn = 0; /* Input mode */ cp->Interpret = (cmd->device->id == hd->hostid); - cp->cp_datalen = cpu_to_be32(cmd->request_bufflen); + cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd)); cp->Auto_Req_Sen = 0; cp->cp_reqDMA = 0; cp->reqlen = 0; @@ -402,14 +402,14 @@ static int eata_pio_queue(struct scsi_cm cp->cmd = cmd; cmd->host_scribble = (char *) &hd->ccb[y]; - if (cmd->use_sg == 0) { + if (!scsi_bufflen(cmd)) { cmd->SCp.buffers_residual = 1; - cmd->SCp.ptr = cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; cmd->SCp.buffer = NULL; } else { - cmd->SCp.buffer = cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg; + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd); cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } diff -puN drivers/scsi/fd_mcs.c~git-scsi-misc drivers/scsi/fd_mcs.c --- a/drivers/scsi/fd_mcs.c~git-scsi-misc +++ a/drivers/scsi/fd_mcs.c @@ -1017,24 +1017,6 @@ static irqreturn_t fd_mcs_intr(int irq, printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in); #endif -#if ERRORS_ONLY - if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) { - if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) { - unsigned char key; - unsigned char code; - unsigned char qualifier; - - key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f; - code = (unsigned char) (*((char *) current_SC->request_buffer + 12)); - qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13)); - - if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01)) - && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code))) - - printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier); - } - } -#endif #if EVERY_ACCESS printk("BEFORE MY_DONE. . ."); #endif @@ -1097,7 +1079,9 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpn panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n"); } #if EVERY_ACCESS - printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen); + printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", + SCpnt->target, *(unsigned char *) SCpnt->cmnd, + scsi_sg_count(SCpnt), scsi_bufflen(SCpnt)); #endif fd_mcs_make_bus_idle(shpnt); @@ -1107,14 +1091,14 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpn /* Initialize static data */ - if (current_SC->use_sg) { - current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer; + if (scsi_bufflen(current_SC)) { + current_SC->SCp.buffer = scsi_sglist(current_SC); current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - current_SC->SCp.buffers_residual = current_SC->use_sg - 1; + current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1; } else { - current_SC->SCp.ptr = (char *) current_SC->request_buffer; - current_SC->SCp.this_residual = current_SC->request_bufflen; + current_SC->SCp.ptr = NULL; + current_SC->SCp.this_residual = 0; current_SC->SCp.buffer = NULL; current_SC->SCp.buffers_residual = 0; } @@ -1166,7 +1150,9 @@ static void fd_mcs_print_info(Scsi_Cmnd break; } - printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen); + printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", + SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, + scsi_sg_count(SCpnt), scsi_bufflen(SCpnt)); printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout); #if DEBUG_RACE printk("in_interrupt_flag = %d\n", in_interrupt_flag); diff -puN drivers/scsi/hosts.c~git-scsi-misc drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c~git-scsi-misc +++ a/drivers/scsi/hosts.c @@ -54,8 +54,7 @@ static struct class shost_class = { }; /** - * scsi_host_set_state - Take the given host through the host - * state model. + * scsi_host_set_state - Take the given host through the host state model. * @shost: scsi host to change the state of. * @state: state to change to. * @@ -431,7 +430,6 @@ EXPORT_SYMBOL(scsi_unregister); /** * scsi_host_lookup - get a reference to a Scsi_Host by host no - * * @hostnum: host number to locate * * Return value: diff -puN drivers/scsi/ibmvscsi/ibmvscsi.c~git-scsi-misc drivers/scsi/ibmvscsi/ibmvscsi.c --- a/drivers/scsi/ibmvscsi/ibmvscsi.c~git-scsi-misc +++ a/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struc list_del(&evt_struct->list); del_timer(&evt_struct->timer); + /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. + * Firmware will send a CRQ with a transport event (0xFF) to + * tell this client what has happened to the transport. This + * will be handled in ibmvscsi_handle_crq() + */ + if (rc == H_CLOSED) { + dev_warn(hostdata->dev, "send warning. " + "Receive queue closed, will retry.\n"); + goto send_busy; + } dev_err(hostdata->dev, "send error %d\n", rc); atomic_inc(&hostdata->request_limit); goto send_error; @@ -976,58 +986,74 @@ static int ibmvscsi_eh_abort_handler(str int rsp_rc; unsigned long flags; u16 lun = lun_from_dev(cmd->device); + unsigned long wait_switch = 0; /* First, find this command in our sent list so we can figure * out the correct tag */ spin_lock_irqsave(hostdata->host->host_lock, flags); - found_evt = NULL; - list_for_each_entry(tmp_evt, &hostdata->sent, list) { - if (tmp_evt->cmnd == cmd) { - found_evt = tmp_evt; - break; + wait_switch = jiffies + (init_timeout * HZ); + do { + found_evt = NULL; + list_for_each_entry(tmp_evt, &hostdata->sent, list) { + if (tmp_evt->cmnd == cmd) { + found_evt = tmp_evt; + break; + } } - } - if (!found_evt) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - return SUCCESS; - } + if (!found_evt) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + return SUCCESS; + } - evt = get_event_struct(&hostdata->pool); - if (evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n"); - return FAILED; - } + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + sdev_printk(KERN_ERR, cmd->device, + "failed to allocate abort event\n"); + return FAILED; + } - init_event_struct(evt, - sync_completion, - VIOSRP_SRP_FORMAT, - init_timeout); + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout); - tsk_mgmt = &evt->iu.srp.tsk_mgmt; + tsk_mgmt = &evt->iu.srp.tsk_mgmt; - /* Set up an abort SRP command */ - memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK; - tsk_mgmt->task_tag = (u64) found_evt; - - sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n", - tsk_mgmt->lun, tsk_mgmt->task_tag); - - evt->sync_srp = &srp_rsp; - init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + /* Set up an abort SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->opcode = SRP_TSK_MGMT; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK; + tsk_mgmt->task_tag = (u64) found_evt; + + evt->sync_srp = &srp_rsp; + + init_completion(&evt->comp); + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + + if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) + break; + + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + msleep(10); + spin_lock_irqsave(hostdata->host->host_lock, flags); + } while (time_before(jiffies, wait_switch)); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { sdev_printk(KERN_ERR, cmd->device, "failed to send abort() event. rc=%d\n", rsp_rc); return FAILED; } + sdev_printk(KERN_INFO, cmd->device, + "aborting command. lun 0x%lx, tag 0x%lx\n", + (((u64) lun) << 48), (u64) found_evt); + wait_for_completion(&evt->comp); /* make sure we got a good response */ @@ -1099,41 +1125,56 @@ static int ibmvscsi_eh_device_reset_hand int rsp_rc; unsigned long flags; u16 lun = lun_from_dev(cmd->device); + unsigned long wait_switch = 0; spin_lock_irqsave(hostdata->host->host_lock, flags); - evt = get_event_struct(&hostdata->pool); - if (evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n"); - return FAILED; - } + wait_switch = jiffies + (init_timeout * HZ); + do { + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + sdev_printk(KERN_ERR, cmd->device, + "failed to allocate reset event\n"); + return FAILED; + } - init_event_struct(evt, - sync_completion, - VIOSRP_SRP_FORMAT, - init_timeout); + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout); - tsk_mgmt = &evt->iu.srp.tsk_mgmt; + tsk_mgmt = &evt->iu.srp.tsk_mgmt; - /* Set up a lun reset SRP command */ - memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; + /* Set up a lun reset SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->opcode = SRP_TSK_MGMT; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; - sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n", - tsk_mgmt->lun); + evt->sync_srp = &srp_rsp; + + init_completion(&evt->comp); + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + + if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) + break; + + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + msleep(10); + spin_lock_irqsave(hostdata->host->host_lock, flags); + } while (time_before(jiffies, wait_switch)); - evt->sync_srp = &srp_rsp; - init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { sdev_printk(KERN_ERR, cmd->device, "failed to send reset event. rc=%d\n", rsp_rc); return FAILED; } + sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n", + (((u64) lun) << 48)); + wait_for_completion(&evt->comp); /* make sure we got a good response */ @@ -1386,8 +1427,10 @@ static int ibmvscsi_slave_configure(stru unsigned long lock_flags = 0; spin_lock_irqsave(shost->host_lock, lock_flags); - if (sdev->type == TYPE_DISK) + if (sdev->type == TYPE_DISK) { sdev->allow_restart = 1; + sdev->timeout = 60 * HZ; + } scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun); spin_unlock_irqrestore(shost->host_lock, lock_flags); return 0; diff -puN drivers/scsi/ibmvscsi/ibmvstgt.c~git-scsi-misc drivers/scsi/ibmvscsi/ibmvstgt.c --- a/drivers/scsi/ibmvscsi/ibmvstgt.c~git-scsi-misc +++ a/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -292,7 +292,7 @@ static int ibmvstgt_cmd_done(struct scsi dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0], cmd->usg_sg); - if (sc->use_sg) + if (scsi_sg_count(sc)) err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); spin_lock_irqsave(&target->lock, flags); diff -puN drivers/scsi/imm.c~git-scsi-misc drivers/scsi/imm.c --- a/drivers/scsi/imm.c~git-scsi-misc +++ a/drivers/scsi/imm.c @@ -837,19 +837,16 @@ static int imm_engine(imm_struct *dev, s /* Phase 4 - Setup scatter/gather buffers */ case 4: - if (cmd->use_sg) { - /* if many buffers are available, start filling the first */ - cmd->SCp.buffer = - (struct scatterlist *) cmd->request_buffer; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); } else { - /* else fill the only available buffer */ cmd->SCp.buffer = NULL; - cmd->SCp.this_residual = cmd->request_bufflen; - cmd->SCp.ptr = cmd->request_buffer; + cmd->SCp.this_residual = 0; + cmd->SCp.ptr = NULL; } - cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.phase++; if (cmd->SCp.this_residual & 0x01) cmd->SCp.this_residual++; diff -puN drivers/scsi/in2000.c~git-scsi-misc drivers/scsi/in2000.c --- a/drivers/scsi/in2000.c~git-scsi-misc +++ a/drivers/scsi/in2000.c @@ -369,16 +369,16 @@ static int in2000_queuecommand(Scsi_Cmnd * - SCp.phase records this command's SRCID_ER bit setting */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } cmd->SCp.have_data_in = 0; diff -puN drivers/scsi/libsas/sas_discover.c~git-scsi-misc drivers/scsi/libsas/sas_discover.c --- a/drivers/scsi/libsas/sas_discover.c~git-scsi-misc +++ a/drivers/scsi/libsas/sas_discover.c @@ -98,7 +98,7 @@ static int sas_get_port_device(struct as dev->dev_type = SATA_PM; else dev->dev_type = SATA_DEV; - dev->tproto = SATA_PROTO; + dev->tproto = SAS_PROTOCOL_SATA; } else { struct sas_identify_frame *id = (struct sas_identify_frame *) dev->frame_rcvd; diff -puN drivers/scsi/libsas/sas_expander.c~git-scsi-misc drivers/scsi/libsas/sas_expander.c --- a/drivers/scsi/libsas/sas_expander.c~git-scsi-misc +++ a/drivers/scsi/libsas/sas_expander.c @@ -656,9 +656,9 @@ static struct domain_device *sas_ex_disc sas_ex_get_linkrate(parent, child, phy); #ifdef CONFIG_SCSI_SAS_ATA - if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { + if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { child->dev_type = SATA_DEV; - if (phy->attached_tproto & SAS_PROTO_STP) + if (phy->attached_tproto & SAS_PROTOCOL_STP) child->tproto = phy->attached_tproto; if (phy->attached_sata_dev) child->tproto |= SATA_DEV; @@ -695,7 +695,7 @@ static struct domain_device *sas_ex_disc } } else #endif - if (phy->attached_tproto & SAS_PROTO_SSP) { + if (phy->attached_tproto & SAS_PROTOCOL_SSP) { child->dev_type = SAS_END_DEV; rphy = sas_end_device_alloc(phy->port); /* FIXME: error handling */ diff -puN drivers/scsi/libsas/sas_internal.h~git-scsi-misc drivers/scsi/libsas/sas_internal.h --- a/drivers/scsi/libsas/sas_internal.h~git-scsi-misc +++ a/drivers/scsi/libsas/sas_internal.h @@ -45,7 +45,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost); int sas_show_class(enum sas_class class, char *buf); -int sas_show_proto(enum sas_proto proto, char *buf); +int sas_show_proto(enum sas_protocol proto, char *buf); int sas_show_linkrate(enum sas_linkrate linkrate, char *buf); int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf); diff -puN drivers/scsi/libsas/sas_scsi_host.c~git-scsi-misc drivers/scsi/libsas/sas_scsi_host.c --- a/drivers/scsi/libsas/sas_scsi_host.c~git-scsi-misc +++ a/drivers/scsi/libsas/sas_scsi_host.c @@ -200,6 +200,10 @@ int sas_queue_up(struct sas_task *task) */ int sas_queuecommand(struct scsi_cmnd *cmd, void (*scsi_done)(struct scsi_cmnd *)) + __releases(host->host_lock) + __acquires(dev->sata_dev.ap->lock) + __releases(dev->sata_dev.ap->lock) + __acquires(host->host_lock) { int res = 0; struct domain_device *dev = cmd_to_domain_dev(cmd); @@ -410,7 +414,7 @@ static int sas_recover_I_T(struct domain } /* Find the sas_phy that's attached to this device */ -struct sas_phy *find_local_sas_phy(struct domain_device *dev) +static struct sas_phy *find_local_sas_phy(struct domain_device *dev) { struct domain_device *pdev = dev->parent; struct ex_phy *exphy = NULL; diff -puN drivers/scsi/libsrp.c~git-scsi-misc drivers/scsi/libsrp.c --- a/drivers/scsi/libsrp.c~git-scsi-misc +++ a/drivers/scsi/libsrp.c @@ -192,18 +192,18 @@ static int srp_direct_data(struct scsi_c if (dma_map) { iue = (struct iu_entry *) sc->SCp.ptr; - sg = sc->request_buffer; + sg = scsi_sglist(sc); - dprintk("%p %u %u %d\n", iue, sc->request_bufflen, - md->len, sc->use_sg); + dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc), + md->len, scsi_sg_count(sc)); - nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, + nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc), DMA_BIDIRECTIONAL); if (!nsg) { - printk("fail to map %p %d\n", iue, sc->use_sg); + printk("fail to map %p %d\n", iue, scsi_sg_count(sc)); return 0; } - len = min(sc->request_bufflen, md->len); + len = min(scsi_bufflen(sc), md->len); } else len = md->len; @@ -229,10 +229,10 @@ static int srp_indirect_data(struct scsi if (dma_map || ext_desc) { iue = (struct iu_entry *) sc->SCp.ptr; - sg = sc->request_buffer; + sg = scsi_sglist(sc); dprintk("%p %u %u %d %d\n", - iue, sc->request_bufflen, id->len, + iue, scsi_bufflen(sc), id->len, cmd->data_in_desc_cnt, cmd->data_out_desc_cnt); } @@ -268,13 +268,14 @@ static int srp_indirect_data(struct scsi rdma: if (dma_map) { - nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL); + nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc), + DMA_BIDIRECTIONAL); if (!nsg) { - eprintk("fail to map %p %d\n", iue, sc->use_sg); + eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc)); err = -EIO; goto free_mem; } - len = min(sc->request_bufflen, id->len); + len = min(scsi_bufflen(sc), id->len); } else len = id->len; diff -puN drivers/scsi/lpfc/lpfc.h~git-scsi-misc drivers/scsi/lpfc/lpfc.h --- a/drivers/scsi/lpfc/lpfc.h~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc.h @@ -68,6 +68,7 @@ struct lpfc_dmabuf { struct list_head list; void *virt; /* virtual address ptr */ dma_addr_t phys; /* mapped address */ + uint32_t buffer_tag; /* used for tagged queue ring */ }; struct lpfc_dma_pool { @@ -272,10 +273,16 @@ struct lpfc_vport { #define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */ #define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */ #define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */ -#define FC_RFF_NOT_SUPPORTED 0x40000 /* RFF_ID was rejected by switch */ #define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */ #define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */ + uint32_t ct_flags; +#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ +#define FC_CT_RNN_ID 0x2 /* RNN_ID accepted by switch */ +#define FC_CT_RSNN_NN 0x4 /* RSNN_NN accepted by switch */ +#define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */ +#define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */ + struct list_head fc_nodes; /* Keep counters for the number of entries in each list. */ @@ -344,6 +351,7 @@ struct lpfc_vport { uint32_t cfg_discovery_threads; uint32_t cfg_log_verbose; uint32_t cfg_max_luns; + uint32_t cfg_enable_da_id; uint32_t dev_loss_tmo_changed; @@ -360,6 +368,7 @@ struct lpfc_vport { struct hbq_s { uint16_t entry_count; /* Current number of HBQ slots */ + uint16_t buffer_count; /* Current number of buffers posted */ uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */ uint32_t hbqPutIdx; /* HBQ slot to use */ uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */ @@ -377,6 +386,11 @@ struct hbq_s { #define LPFC_ELS_HBQ 0 #define LPFC_EXTRA_HBQ 1 +enum hba_temp_state { + HBA_NORMAL_TEMP, + HBA_OVER_TEMP +}; + struct lpfc_hba { struct lpfc_sli sli; uint32_t sli_rev; /* SLI2 or SLI3 */ @@ -569,10 +583,18 @@ struct lpfc_hba { atomic_t slow_ring_trc_cnt; #endif + uint8_t temp_sensor_support; /* Fields used for heart beat. */ unsigned long last_completion_time; struct timer_list hb_tmofunc; uint8_t hb_outstanding; + /* + * Following bit will be set for all buffer tags which are not + * associated with any HBQ. + */ +#define QUE_BUFTAG_BIT (1<<31) + uint32_t buffer_tag_count; + enum hba_temp_state over_temp_state; }; static inline struct Scsi_Host * @@ -598,5 +620,15 @@ lpfc_is_link_up(struct lpfc_hba *phba) phba->link_state == LPFC_HBA_READY; } -#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ - +#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ +#define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature + event */ + +struct temp_event { + uint32_t event_type; + uint32_t event_code; + uint32_t data; +}; +#define LPFC_CRIT_TEMP 0x1 +#define LPFC_THRESHOLD_TEMP 0x2 +#define LPFC_NORMAL_TEMP 0x3 diff -puN drivers/scsi/lpfc/lpfc_attr.c~git-scsi-misc drivers/scsi/lpfc/lpfc_attr.c --- a/drivers/scsi/lpfc/lpfc_attr.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_attr.c @@ -86,6 +86,15 @@ lpfc_serialnum_show(struct class_device } static ssize_t +lpfc_temp_sensor_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support); +} + +static ssize_t lpfc_modeldesc_show(struct class_device *cdev, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -178,12 +187,9 @@ lpfc_state_show(struct class_device *cde case LPFC_LINK_UP: case LPFC_CLEAR_LA: case LPFC_HBA_READY: - len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n"); + len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - "); switch (vport->port_state) { - len += snprintf(buf + len, PAGE_SIZE-len, - "initializing\n"); - break; case LPFC_LOCAL_CFG_LINK: len += snprintf(buf + len, PAGE_SIZE-len, "Configuring Link\n"); @@ -908,6 +914,8 @@ static CLASS_DEVICE_ATTR(used_rpi, S_IRU static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL); static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); +static CLASS_DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, + NULL); static char *lpfc_soft_wwn_key = "C99G71SL8032A"; @@ -971,6 +979,12 @@ lpfc_soft_wwpn_store(struct class_device unsigned int i, j, cnt=count; u8 wwpn[8]; + spin_lock_irq(&phba->hbalock); + if (phba->over_temp_state == HBA_OVER_TEMP) { + spin_unlock_irq(&phba->hbalock); + return -EPERM; + } + spin_unlock_irq(&phba->hbalock); /* count may include a LF at end of string */ if (buf[cnt-1] == '\n') cnt--; @@ -1102,7 +1116,13 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mod " 2 - select SLI-2 even on SLI-3 capable HBAs," " 3 - select SLI-3"); -LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality"); +int lpfc_enable_npiv = 0; +module_param(lpfc_enable_npiv, int, 0); +MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality"); +lpfc_param_show(enable_npiv); +lpfc_param_init(enable_npiv, 0, 0, 1); +static CLASS_DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, + lpfc_enable_npiv_show, NULL); /* # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear @@ -1248,6 +1268,13 @@ LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, "Verbose logging bit-mask"); /* +# lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters +# objects that have been registered with the nameserver after login. +*/ +LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1, + "Deregister nameserver objects before LOGO"); + +/* # lun_queue_depth: This parameter is used to limit the number of outstanding # commands per FCP LUN. Value range is [1,128]. Default value is 30. */ @@ -1494,6 +1521,7 @@ struct class_device_attribute *lpfc_hba_ &class_device_attr_state, &class_device_attr_num_discovered_ports, &class_device_attr_lpfc_drvr_version, + &class_device_attr_lpfc_temp_sensor, &class_device_attr_lpfc_log_verbose, &class_device_attr_lpfc_lun_queue_depth, &class_device_attr_lpfc_hba_queue_depth, @@ -1552,6 +1580,7 @@ struct class_device_attribute *lpfc_vpor &class_device_attr_lpfc_max_luns, &class_device_attr_nport_evt_cnt, &class_device_attr_npiv_info, + &class_device_attr_lpfc_enable_da_id, NULL, }; @@ -1727,13 +1756,18 @@ sysfs_mbox_read(struct kobject *kobj, st spin_lock_irq(&phba->hbalock); + if (phba->over_temp_state == HBA_OVER_TEMP) { + sysfs_mbox_idle(phba); + spin_unlock_irq(&phba->hbalock); + return -EPERM; + } + if (off == 0 && phba->sysfs_mbox.state == SMBOX_WRITING && phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) { switch (phba->sysfs_mbox.mbox->mb.mbxCommand) { /* Offline only */ - case MBX_WRITE_NV: case MBX_INIT_LINK: case MBX_DOWN_LINK: case MBX_CONFIG_LINK: @@ -1756,6 +1790,8 @@ sysfs_mbox_read(struct kobject *kobj, st spin_unlock_irq(&phba->hbalock); return -EPERM; } + case MBX_WRITE_NV: + case MBX_WRITE_VPARMS: case MBX_LOAD_SM: case MBX_READ_NV: case MBX_READ_CONFIG: @@ -2337,8 +2373,6 @@ struct fc_function_template lpfc_transpo .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk, .terminate_rport_io = lpfc_terminate_rport_io, - .vport_create = lpfc_vport_create, - .vport_delete = lpfc_vport_delete, .dd_fcvport_size = sizeof(struct lpfc_vport *), }; @@ -2448,5 +2482,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vpor lpfc_discovery_threads_init(vport, lpfc_discovery_threads); lpfc_max_luns_init(vport, lpfc_max_luns); lpfc_scan_down_init(vport, lpfc_scan_down); + lpfc_enable_da_id_init(vport, lpfc_enable_da_id); return; } diff -puN drivers/scsi/lpfc/lpfc_crtn.h~git-scsi-misc drivers/scsi/lpfc/lpfc_crtn.h --- a/drivers/scsi/lpfc/lpfc_crtn.h~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_crtn.h @@ -23,6 +23,8 @@ typedef int (*node_filter)(struct lpfc_n struct fc_rport; void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); + void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp); @@ -43,6 +45,7 @@ void lpfc_init_link(struct lpfc_hba *, L struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); int lpfc_linkdown(struct lpfc_hba *); +void lpfc_port_link_failure(struct lpfc_vport *); void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -66,11 +69,13 @@ int lpfc_check_sli_ndlp(struct lpfc_hba void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t); struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *); int lpfc_nlp_put(struct lpfc_nodelist *); +int lpfc_nlp_not_used(struct lpfc_nodelist *ndlp); struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t); void lpfc_disc_list_loopmap(struct lpfc_vport *); void lpfc_disc_start(struct lpfc_vport *); void lpfc_disc_flush_list(struct lpfc_vport *); void lpfc_cleanup_discovery_resources(struct lpfc_vport *); +void lpfc_cleanup(struct lpfc_vport *); void lpfc_disc_timeout(unsigned long); struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); @@ -88,6 +93,8 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hb int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, struct serv_parm *, uint32_t); int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); +void lpfc_more_plogi(struct lpfc_vport *); +void lpfc_end_rscn(struct lpfc_vport *); int lpfc_els_chk_latt(struct lpfc_vport *); int lpfc_els_abort_flogi(struct lpfc_hba *); int lpfc_initial_flogi(struct lpfc_vport *); @@ -204,6 +211,11 @@ int lpfc_sli_ringpostbuf_put(struct lpfc struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, struct lpfc_sli_ring *, dma_addr_t); + +uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *); +struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *, + struct lpfc_sli_ring *, uint32_t ); + int lpfc_sli_hbq_count(void); int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t); int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t); @@ -260,6 +272,7 @@ extern struct scsi_host_template lpfc_vp extern struct fc_function_template lpfc_transport_functions; extern struct fc_function_template lpfc_vport_transport_functions; extern int lpfc_sli_mode; +extern int lpfc_enable_npiv; int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); void lpfc_terminate_rport_io(struct fc_rport *); diff -puN drivers/scsi/lpfc/lpfc_ct.c~git-scsi-misc drivers/scsi/lpfc/lpfc_ct.c --- a/drivers/scsi/lpfc/lpfc_ct.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_ct.c @@ -458,7 +458,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, st ((lpfc_find_vport_by_did(phba, Did) == NULL) || vport->cfg_peer_port_login)) { if ((vport->port_type != LPFC_NPIV_PORT) || - (vport->fc_flag & FC_RFF_NOT_SUPPORTED) || + (!(vport->ct_flags & FC_CT_RFF_ID)) || (!vport->cfg_restrict_login)) { ndlp = lpfc_setup_disc_node(vport, Did); if (ndlp) { @@ -778,8 +778,8 @@ out: static void -lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) +lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; struct lpfc_dmabuf *inp; @@ -809,7 +809,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba /* RFT request completes status CmdRsp */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0209 RFT request completes, latt %d, " + "0209 CT Request completes, latt %d, " "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n", latt, irsp->ulpStatus, CTrsp->CommandResponse.bits.CmdRsp, @@ -848,10 +848,44 @@ out: } static void +lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; + + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RFT_ID; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); + return; +} + +static void lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; + + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RNN_ID; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); return; } @@ -859,7 +893,20 @@ static void lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; + + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RSPN_ID; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); return; } @@ -867,7 +914,32 @@ static void lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; + + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RSNN_NN; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); + return; +} + +static void +lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + + /* even if it fails we will act as though it succeeded. */ + vport->ct_flags = 0; + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); return; } @@ -878,10 +950,17 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba IOCB_t *irsp = &rspiocb->iocb; struct lpfc_vport *vport = cmdiocb->vport; - if (irsp->ulpStatus != IOSTAT_SUCCESS) - vport->fc_flag |= FC_RFF_NOT_SUPPORTED; + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; - lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RFF_ID; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); return; } @@ -1001,6 +1080,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in bpl->tus.f.bdeSize = RSPN_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RSNN_NN) bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; + else if (cmdcode == SLI_CTNS_DA_ID) + bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RFF_ID) bpl->tus.f.bdeSize = RFF_REQUEST_SZ; else @@ -1034,6 +1115,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in break; case SLI_CTNS_RFT_ID: + vport->ct_flags &= ~FC_CT_RFT_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RFT_ID); CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID); @@ -1042,6 +1124,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in break; case SLI_CTNS_RNN_ID: + vport->ct_flags &= ~FC_CT_RNN_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RNN_ID); CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID); @@ -1051,6 +1134,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in break; case SLI_CTNS_RSPN_ID: + vport->ct_flags &= ~FC_CT_RSPN_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RSPN_ID); CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID); @@ -1061,6 +1145,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in cmpl = lpfc_cmpl_ct_cmd_rspn_id; break; case SLI_CTNS_RSNN_NN: + vport->ct_flags &= ~FC_CT_RSNN_NN; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RSNN_NN); memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename, @@ -1071,8 +1156,15 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in CtReq->un.rsnn.symbname, size); cmpl = lpfc_cmpl_ct_cmd_rsnn_nn; break; + case SLI_CTNS_DA_ID: + /* Implement DA_ID Nameserver request */ + CtReq->CommandResponse.bits.CmdRsp = + be16_to_cpu(SLI_CTNS_DA_ID); + CtReq->un.da_id.port_id = be32_to_cpu(vport->fc_myDID); + cmpl = lpfc_cmpl_ct_cmd_da_id; + break; case SLI_CTNS_RFF_ID: - vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED; + vport->ct_flags &= ~FC_CT_RFF_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RFF_ID); CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);; diff -puN drivers/scsi/lpfc/lpfc_debugfs.c~git-scsi-misc drivers/scsi/lpfc/lpfc_debugfs.c --- a/drivers/scsi/lpfc/lpfc_debugfs.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_debugfs.c @@ -243,16 +243,17 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hb raw_index = phba->hbq_get[i]; getidx = le32_to_cpu(raw_index); len += snprintf(buf+len, size-len, - "entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", - hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx, - hbqs->local_hbqGetIdx, getidx); + "entrys:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", + hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx, + hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx); hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; for (j=0; jentry_count; j++) { len += snprintf(buf+len, size-len, "%03d: %08x %04x %05x ", j, - hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag); - + le32_to_cpu(hbqe->bde.addrLow), + le32_to_cpu(hbqe->bde.tus.w), + le32_to_cpu(hbqe->buffer_tag)); i = 0; found = 0; @@ -276,7 +277,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hb list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) { hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); - if (phys == hbqe->bde.addrLow) { + if (phys == le32_to_cpu(hbqe->bde.addrLow)) { len += snprintf(buf+len, size-len, "Buf%d: %p %06x\n", i, hbq_buf->dbuf.virt, hbq_buf->tag); diff -puN drivers/scsi/lpfc/lpfc_disc.h~git-scsi-misc drivers/scsi/lpfc/lpfc_disc.h --- a/drivers/scsi/lpfc/lpfc_disc.h~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_disc.h @@ -36,7 +36,6 @@ enum lpfc_work_type { LPFC_EVT_WARM_START, LPFC_EVT_KILL, LPFC_EVT_ELS_RETRY, - LPFC_EVT_DEV_LOSS_DELAY, LPFC_EVT_DEV_LOSS, }; @@ -92,6 +91,7 @@ struct lpfc_nodelist { #define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */ #define NLP_RNID_SND 0x400 /* sent RNID request for this entry */ #define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */ +#define NLP_DEFER_RM 0x10000 /* Remove this ndlp if no longer used */ #define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */ #define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */ #define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */ diff -puN drivers/scsi/lpfc/lpfc_els.c~git-scsi-misc drivers/scsi/lpfc/lpfc_els.c --- a/drivers/scsi/lpfc/lpfc_els.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_els.c @@ -109,9 +109,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vp /* fill in BDEs for command */ /* Allocate buffer for command payload */ - if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) || - ((pcmd->virt = lpfc_mbuf_alloc(phba, - MEM_PRI, &(pcmd->phys))) == 0)) { + pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (pcmd) + pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); + if (!pcmd || !pcmd->virt) { kfree(pcmd); lpfc_sli_release_iocbq(phba, elsiocb); @@ -126,7 +127,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vp if (prsp) prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &prsp->phys); - if (prsp == 0 || prsp->virt == 0) { + if (!prsp || !prsp->virt) { kfree(prsp); lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); kfree(pcmd); @@ -143,7 +144,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vp if (pbuflist) pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pbuflist->phys); - if (pbuflist == 0 || pbuflist->virt == 0) { + if (!pbuflist || !pbuflist->virt) { lpfc_sli_release_iocbq(phba, elsiocb); lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); lpfc_mbuf_free(phba, prsp->virt, prsp->phys); @@ -234,40 +235,53 @@ lpfc_issue_fabric_reglogin(struct lpfc_v struct lpfc_nodelist *ndlp; struct serv_parm *sp; int rc; + int err = 0; sp = &phba->fc_fabparam; ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) + if (!ndlp) { + err = 1; goto fail; + } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (!mbox) { + err = 2; goto fail; + } vport->port_state = LPFC_FABRIC_CFG_LINK; lpfc_config_link(phba, mbox); mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); - if (rc == MBX_NOT_FINISHED) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + err = 3; goto fail_free_mbox; + } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (!mbox) { + err = 4; goto fail; + } rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0); - if (rc) + if (rc) { + err = 5; goto fail_free_mbox; + } mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; mbox->vport = vport; mbox->context2 = lpfc_nlp_get(ndlp); - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); - if (rc == MBX_NOT_FINISHED) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + err = 6; goto fail_issue_reg_login; + } return 0; @@ -282,7 +296,7 @@ fail_free_mbox: fail: lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0249 Cannot issue Register Fabric login\n"); + "0249 Cannot issue Register Fabric login: Err %d\n", err); return -ENXIO; } @@ -429,8 +443,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vp mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, - MBX_NOWAIT | MBX_STOP_IOCB); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); goto fail; @@ -562,8 +575,13 @@ flogifail: /* Start discovery */ lpfc_disc_start(vport); + } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || + ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) && + (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) && + (phba->link_state != LPFC_CLEAR_LA)) { + /* If FLOGI failed enable link interrupt. */ + lpfc_issue_clear_la(phba, vport); } - out: lpfc_els_free_iocb(phba, cmdiocb); } @@ -685,6 +703,9 @@ lpfc_initial_flogi(struct lpfc_vport *vp struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp; + vport->port_state = LPFC_FLOGI; + lpfc_set_disctmo(vport); + /* First look for the Fabric ndlp */ ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) { @@ -696,6 +717,7 @@ lpfc_initial_flogi(struct lpfc_vport *vp } else { lpfc_dequeue_node(vport, ndlp); } + if (lpfc_issue_els_flogi(vport, ndlp, 0)) { lpfc_nlp_put(ndlp); } @@ -724,7 +746,8 @@ lpfc_initial_fdisc(struct lpfc_vport *vp } return 1; } -static void + +void lpfc_more_plogi(struct lpfc_vport *vport) { int sentplogi; @@ -791,8 +814,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); /* Move this back to NPR state */ - if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) + if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) { + /* The new_ndlp is replacing ndlp totally, so we need + * to put ndlp on UNUSED list and try to free it. + */ lpfc_drop_node(vport, ndlp); + } else { lpfc_unreg_rpi(vport, ndlp); ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */ @@ -801,6 +828,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba return new_ndlp; } +void +lpfc_end_rscn(struct lpfc_vport *vport) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + if (vport->fc_flag & FC_RSCN_MODE) { + /* + * Check to see if more RSCNs came in while we were + * processing this one. + */ + if (vport->fc_rscn_id_cnt || + (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) + lpfc_els_handle_rscn(vport); + else { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_RSCN_MODE; + spin_unlock_irq(shost->host_lock); + } + } +} + static void lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) @@ -871,13 +919,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phb goto out; } /* PLOGI failed */ - if (ndlp->nlp_DID == NameServer_DID) { - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0250 Nameserver login error: " - "0x%x / 0x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4]); - } /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ if (lpfc_error_lost_link(irsp)) { rc = NLP_STE_FREED_NODE; @@ -905,20 +946,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phb spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); - if (vport->fc_flag & FC_RSCN_MODE) { - /* - * Check to see if more RSCNs came in while - * we were processing this one. - */ - if ((vport->fc_rscn_id_cnt == 0) && - (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } else { - lpfc_els_handle_rscn(vport); - } - } + lpfc_end_rscn(vport); } } @@ -933,6 +961,7 @@ lpfc_issue_els_plogi(struct lpfc_vport * struct lpfc_hba *phba = vport->phba; struct serv_parm *sp; IOCB_t *icmd; + struct lpfc_nodelist *ndlp; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; @@ -943,8 +972,11 @@ lpfc_issue_els_plogi(struct lpfc_vport * psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ + ndlp = lpfc_findnode_did(vport, did); + /* If ndlp if not NULL, we will bump the reference count on it */ + cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did, + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, ELS_CMD_PLOGI); if (!elsiocb) return 1; @@ -1134,8 +1166,6 @@ lpfc_more_adisc(struct lpfc_vport *vport static void lpfc_rscn_disc(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - lpfc_can_disctmo(vport); /* RSCN discovery */ @@ -1144,19 +1174,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport) if (lpfc_els_disc_plogi(vport)) return; - if (vport->fc_flag & FC_RSCN_MODE) { - /* Check to see if more RSCNs came in while we were - * processing this one. - */ - if ((vport->fc_rscn_id_cnt == 0) && - (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } else { - lpfc_els_handle_rscn(vport); - } - } + lpfc_end_rscn(vport); } static void @@ -1413,6 +1431,13 @@ lpfc_issue_els_logo(struct lpfc_vport *v psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; + spin_lock_irq(shost->host_lock); + if (ndlp->nlp_flag & NLP_LOGO_SND) { + spin_unlock_irq(shost->host_lock); + return 0; + } + spin_unlock_irq(shost->host_lock); + cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_LOGO); @@ -1599,27 +1624,6 @@ lpfc_issue_els_farpr(struct lpfc_vport * return 0; } -static void -lpfc_end_rscn(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (vport->fc_flag & FC_RSCN_MODE) { - /* - * Check to see if more RSCNs came in while we were - * processing this one. - */ - if (vport->fc_rscn_id_cnt || - (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) - lpfc_els_handle_rscn(vport); - else { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } - } -} - void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) { @@ -1759,6 +1763,7 @@ lpfc_els_retry(struct lpfc_hba *phba, st uint32_t *elscmd; struct ls_rjt stat; int retry = 0, maxretry = lpfc_max_els_tries, delay = 0; + int logerr = 0; uint32_t cmd = 0; uint32_t did; @@ -1815,6 +1820,7 @@ lpfc_els_retry(struct lpfc_hba *phba, st break; case IOERR_NO_RESOURCES: + logerr = 1; /* HBA out of resources */ retry = 1; if (cmdiocb->retry > 100) delay = 100; @@ -1843,6 +1849,7 @@ lpfc_els_retry(struct lpfc_hba *phba, st case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: + logerr = 1; /* Fabric / Remote NPort out of resources */ retry = 1; break; @@ -1923,6 +1930,15 @@ lpfc_els_retry(struct lpfc_hba *phba, st if (did == FDMI_DID) retry = 1; + if ((cmd == ELS_CMD_FLOGI) && + (phba->fc_topology != TOPOLOGY_LOOP)) { + /* FLOGI retry policy */ + retry = 1; + maxretry = 48; + if (cmdiocb->retry >= 32) + delay = 1000; + } + if ((++cmdiocb->retry) >= maxretry) { phba->fc_stat.elsRetryExceeded++; retry = 0; @@ -2006,11 +2022,46 @@ lpfc_els_retry(struct lpfc_hba *phba, st } } /* No retry ELS command to remote NPORT */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + if (logerr) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0137 No retry ELS command x%x to remote " + "NPORT x%x: Out of Resources: Error:x%x/%x\n", + cmd, did, irsp->ulpStatus, + irsp->un.ulpWord[4]); + } + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0108 No retry ELS command x%x to remote " "NPORT x%x Retried:%d Error:x%x/%x\n", cmd, did, cmdiocb->retry, irsp->ulpStatus, irsp->un.ulpWord[4]); + } + return 0; +} + +int +lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1) +{ + struct lpfc_dmabuf *buf_ptr; + + /* Free the response before processing the command. */ + if (!list_empty(&buf_ptr1->list)) { + list_remove_head(&buf_ptr1->list, buf_ptr, + struct lpfc_dmabuf, + list); + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); + } + lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); + kfree(buf_ptr1); + return 0; +} + +int +lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr) +{ + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); return 0; } @@ -2018,30 +2069,36 @@ int lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; + struct lpfc_nodelist *ndlp; - if (elsiocb->context1) { - lpfc_nlp_put(elsiocb->context1); + ndlp = (struct lpfc_nodelist *)elsiocb->context1; + if (ndlp) { + if (ndlp->nlp_flag & NLP_DEFER_RM) { + lpfc_nlp_put(ndlp); + + /* If the ndlp is not being used by another discovery + * thread, free it. + */ + if (!lpfc_nlp_not_used(ndlp)) { + /* If ndlp is being used by another discovery + * thread, just clear NLP_DEFER_RM + */ + ndlp->nlp_flag &= ~NLP_DEFER_RM; + } + } + else + lpfc_nlp_put(ndlp); elsiocb->context1 = NULL; } /* context2 = cmd, context2->next = rsp, context3 = bpl */ if (elsiocb->context2) { buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; - /* Free the response before processing the command. */ - if (!list_empty(&buf_ptr1->list)) { - list_remove_head(&buf_ptr1->list, buf_ptr, - struct lpfc_dmabuf, - list); - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - } - lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); - kfree(buf_ptr1); + lpfc_els_free_data(phba, buf_ptr1); } if (elsiocb->context3) { buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); + lpfc_els_free_bpl(phba, buf_ptr); } lpfc_sli_release_iocbq(phba, elsiocb); return 0; @@ -2065,15 +2122,15 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * "Data: x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - switch (ndlp->nlp_state) { - case NLP_STE_UNUSED_NODE: /* node is just allocated */ - lpfc_drop_node(vport, ndlp); - break; - case NLP_STE_NPR_NODE: /* NPort Recovery mode */ - lpfc_unreg_rpi(vport, ndlp); - break; - default: - break; + + if (ndlp->nlp_state == NLP_STE_NPR_NODE) { + /* NPort Recovery mode or node is just allocated */ + if (!lpfc_nlp_not_used(ndlp)) { + /* If the ndlp is being used by another discovery + * thread, just unregister the RPI. + */ + lpfc_unreg_rpi(vport, ndlp); + } } lpfc_els_free_iocb(phba, cmdiocb); return; @@ -2089,7 +2146,15 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba * lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - lpfc_nlp_put(ndlp); + if (ndlp) { + lpfc_nlp_put(ndlp); + + /* This is the end of the default RPI cleanup logic for this + * ndlp. If no other discovery threads are using this ndlp. + * we should free all resources associated with it. + */ + lpfc_nlp_not_used(ndlp); + } return; } @@ -2100,15 +2165,27 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL; struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL; - IOCB_t *irsp; + IOCB_t *irsp; + uint8_t *pcmd; LPFC_MBOXQ_t *mbox = NULL; struct lpfc_dmabuf *mp = NULL; + uint32_t ls_rjt = 0; irsp = &rspiocb->iocb; if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; + /* First determine if this is a LS_RJT cmpl */ + pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); + if (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT) { + /* A LS_RJT associated with Default RPI cleanup + * has its own seperate code path. + */ + if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI)) + ls_rjt = 1; + } + /* Check to see if link went down during discovery */ if (!ndlp || lpfc_els_chk_latt(vport)) { if (mbox) { @@ -2119,6 +2196,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, } mempool_free(mbox, phba->mbox_mem_pool); } + if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) + if (lpfc_nlp_not_used(ndlp)) + ndlp = NULL; goto out; } @@ -2150,20 +2230,26 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); } - if (lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) != MBX_NOT_FINISHED) { goto out; } - lpfc_nlp_put(ndlp); - /* NOTE: we should have messages for unsuccessful - reglogin */ + + /* ELS rsp: Cannot issue reg_login for */ + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0138 ELS rsp: Cannot issue reg_login for x%x " + "Data: x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi); + + if (lpfc_nlp_not_used(ndlp)) + ndlp = NULL; } else { /* Do not drop node for lpfc_els_abort'ed ELS cmds */ if (!lpfc_error_lost_link(irsp) && ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - lpfc_drop_node(vport, ndlp); - ndlp = NULL; + if (lpfc_nlp_not_used(ndlp)) + ndlp = NULL; } } mp = (struct lpfc_dmabuf *) mbox->context1; @@ -2178,7 +2264,16 @@ out: spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); spin_unlock_irq(shost->host_lock); + + /* If the node is not being used by another discovery thread, + * and we are sending a reject, we are done with it. + * Release driver reference count here and free associated + * resources. + */ + if (ls_rjt) + lpfc_nlp_not_used(ndlp); } + lpfc_els_free_iocb(phba, cmdiocb); return; } @@ -2349,14 +2444,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *v elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); - /* If the node is in the UNUSED state, and we are sending - * a reject, we are done with it. Release driver reference - * count here. The outstanding els will release its reference on - * completion and the node can be freed then. - */ - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_nlp_put(ndlp); - if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); return 1; @@ -2642,7 +2729,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *v } } } - if (sentplogi == 0) { + if (sentplogi) { + lpfc_set_disctmo(vport); + } + else { spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_NLP_MORE; spin_unlock_irq(shost->host_lock); @@ -3022,8 +3112,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vp mbox->mb.un.varInitLnk.lipsr_AL_PA = 0; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; - rc = lpfc_sli_issue_mbox - (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); lpfc_set_loopback_flag(phba); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); @@ -3223,8 +3312,8 @@ lpfc_els_rcv_rps(struct lpfc_vport *vpor mbox->context2 = lpfc_nlp_get(ndlp); mbox->vport = vport; mbox->mbox_cmpl = lpfc_els_rsp_rps_acc; - if (lpfc_sli_issue_mbox (phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) + if (lpfc_sli_issue_mbox (phba, mbox, MBX_NOWAIT) + != MBX_NOT_FINISHED) /* Mbox completion will send ELS Response */ return 0; @@ -3461,6 +3550,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vpor * other NLP_FABRIC logins */ lpfc_drop_node(vport, ndlp); + } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* Fail outstanding I/O now since this * device is marked for PLOGI @@ -3469,8 +3559,6 @@ lpfc_els_rcv_fan(struct lpfc_vport *vpor } } - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); lpfc_initial_flogi(vport); return 0; } @@ -3711,6 +3799,7 @@ static void lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) { + struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; struct ls_rjt stat; uint32_t *payload; @@ -3750,11 +3839,19 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p goto dropit; lpfc_nlp_init(vport, ndlp, did); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); newnode = 1; if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) { ndlp->nlp_type |= NLP_FABRIC; } - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); + } + else { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + /* This is simular to the new node path */ + lpfc_nlp_get(ndlp); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + newnode = 1; + } } phba->fc_stat.elsRcvFrame++; @@ -3783,6 +3880,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p rjt_err = LSRJT_UNABLE_TPC; break; } + + shost = lpfc_shost_from_vport(vport); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_TARGET_REMOVE; + spin_unlock_irq(shost->host_lock); + lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PLOGI); @@ -3795,7 +3898,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p phba->fc_stat.elsRcvFLOGI++; lpfc_els_rcv_flogi(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_LOGO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3825,7 +3928,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p phba->fc_stat.elsRcvRSCN++; lpfc_els_rcv_rscn(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_ADISC: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3897,7 +4000,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p phba->fc_stat.elsRcvLIRR++; lpfc_els_rcv_lirr(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_RPS: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3907,7 +4010,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p phba->fc_stat.elsRcvRPS++; lpfc_els_rcv_rps(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_RPL: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3917,7 +4020,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p phba->fc_stat.elsRcvRPL++; lpfc_els_rcv_rpl(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_RNID: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3927,7 +4030,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p phba->fc_stat.elsRcvRNID++; lpfc_els_rcv_rnid(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3942,7 +4045,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p "0115 Unknown ELS command x%x " "received from NPORT x%x\n", cmd, did); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; } @@ -3958,10 +4061,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p return; dropit: - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + if (vport && !(vport->load_flag & FC_UNLOADING)) + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, "(%d):0111 Dropping received ELS cmd " "Data: x%x x%x x%x\n", - vport ? vport->vpi : 0xffff, icmd->ulpStatus, + vport->vpi, icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout); phba->fc_stat.elsRcvDrop++; } @@ -4162,8 +4266,7 @@ lpfc_register_new_vport(struct lpfc_hba mbox->vport = vport; mbox->context2 = lpfc_nlp_get(ndlp); mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport; - if (lpfc_sli_issue_mbox(phba, mbox, - MBX_NOWAIT | MBX_STOP_IOCB) + if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; diff -puN drivers/scsi/lpfc/lpfc_hbadisc.c~git-scsi-misc drivers/scsi/lpfc/lpfc_hbadisc.c --- a/drivers/scsi/lpfc/lpfc_hbadisc.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -107,8 +107,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport struct lpfc_nodelist * ndlp; struct lpfc_vport *vport; struct lpfc_hba *phba; - struct completion devloss_compl; struct lpfc_work_evt *evtp; + int put_node; + int put_rport; rdata = rport->dd_data; ndlp = rdata->pnode; @@ -129,7 +130,25 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport "rport devlosscb: sid:x%x did:x%x flg:x%x", ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); - init_completion(&devloss_compl); + /* Don't defer this if we are in the process of deleting the vport + * or unloading the driver. The unload will cleanup the node + * appropriately we just need to cleanup the ndlp rport info here. + */ + if (vport->load_flag & FC_UNLOADING) { + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; + rdata->pnode = NULL; + ndlp->rport = NULL; + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); + return; + } + + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) + return; + evtp = &ndlp->dev_loss_evt; if (!list_empty(&evtp->evt_listp)) @@ -137,7 +156,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport spin_lock_irq(&phba->hbalock); evtp->evt_arg1 = ndlp; - evtp->evt_arg2 = &devloss_compl; evtp->evt = LPFC_EVT_DEV_LOSS; list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) @@ -145,8 +163,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport spin_unlock_irq(&phba->hbalock); - wait_for_completion(&devloss_compl); - return; } @@ -162,6 +178,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_no struct lpfc_vport *vport; struct lpfc_hba *phba; uint8_t *name; + int put_node; + int put_rport; int warn_on = 0; rport = ndlp->rport; @@ -178,14 +196,26 @@ lpfc_dev_loss_tmo_handler(struct lpfc_no "rport devlosstmo:did:x%x type:x%x id:x%x", ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); - if (!(vport->load_flag & FC_UNLOADING) && - ndlp->nlp_state == NLP_STE_MAPPED_NODE) + /* Don't defer this if we are in the process of deleting the vport + * or unloading the driver. The unload will cleanup the node + * appropriately we just need to cleanup the ndlp rport info here. + */ + if (vport->load_flag & FC_UNLOADING) { + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; + rdata->pnode = NULL; + ndlp->rport = NULL; + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); return; + } - if (ndlp->nlp_type & NLP_FABRIC) { - int put_node; - int put_rport; + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) + return; + if (ndlp->nlp_type & NLP_FABRIC) { /* We will clean up these Nodes in linkup */ put_node = rdata->pnode != NULL; put_rport = ndlp->rport != NULL; @@ -227,23 +257,20 @@ lpfc_dev_loss_tmo_handler(struct lpfc_no ndlp->nlp_state, ndlp->nlp_rpi); } + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; + rdata->pnode = NULL; + ndlp->rport = NULL; + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); + if (!(vport->load_flag & FC_UNLOADING) && !(ndlp->nlp_flag & NLP_DELAY_TMO) && !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) + (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) { lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); - else { - int put_node; - int put_rport; - - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); } } @@ -260,7 +287,6 @@ lpfc_work_list_done(struct lpfc_hba *phb { struct lpfc_work_evt *evtp = NULL; struct lpfc_nodelist *ndlp; - struct lpfc_vport *vport; int free_evt; spin_lock_irq(&phba->hbalock); @@ -270,24 +296,6 @@ lpfc_work_list_done(struct lpfc_hba *phb spin_unlock_irq(&phba->hbalock); free_evt = 1; switch (evtp->evt) { - case LPFC_EVT_DEV_LOSS_DELAY: - free_evt = 0; /* evt is part of ndlp */ - ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); - vport = ndlp->vport; - if (!vport) - break; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport devlossdly:did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - - if (!(vport->load_flag & FC_UNLOADING) && - !(ndlp->nlp_flag & NLP_DELAY_TMO) && - !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RM); - } - break; case LPFC_EVT_ELS_RETRY: ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); lpfc_els_retry_delay_handler(ndlp); @@ -298,7 +306,6 @@ lpfc_work_list_done(struct lpfc_hba *phb lpfc_nlp_get(ndlp); lpfc_dev_loss_tmo_handler(ndlp); free_evt = 0; - complete((struct completion *)(evtp->evt_arg2)); lpfc_nlp_put(ndlp); break; case LPFC_EVT_ONLINE: @@ -412,7 +419,7 @@ lpfc_work_done(struct lpfc_hba *phba) status >>= (4*LPFC_ELS_RING); if ((status & HA_RXMASK) || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { - if (pring->flag & LPFC_STOP_IOCB_MASK) { + if (pring->flag & LPFC_STOP_IOCB_EVENT) { pring->flag |= LPFC_DEFERRED_RING_EVENT; } else { lpfc_sli_handle_slow_ring_event(phba, pring, @@ -552,7 +559,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vpo if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; - if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) + if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || + ((vport->port_type == LPFC_NPIV_PORT) && + (ndlp->nlp_DID == NameServer_DID))) lpfc_unreg_rpi(vport, ndlp); /* Leave Fabric nodes alone on link down */ @@ -569,10 +578,24 @@ lpfc_cleanup_rpis(struct lpfc_vport *vpo } } +void +lpfc_port_link_failure(struct lpfc_vport *vport) +{ + /* Cleanup any outstanding RSCN activity */ + lpfc_els_flush_rscn(vport); + + /* Cleanup any outstanding ELS commands */ + lpfc_els_flush_cmd(vport); + + lpfc_cleanup_rpis(vport, 0); + + /* Turn off discovery timer if its running */ + lpfc_can_disctmo(vport); +} + static void lpfc_linkdown_port(struct lpfc_vport *vport) { - struct lpfc_nodelist *ndlp, *next_ndlp; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); @@ -581,21 +604,8 @@ lpfc_linkdown_port(struct lpfc_vport *vp "Link Down: state:x%x rtry:x%x flg:x%x", vport->port_state, vport->fc_ns_retry, vport->fc_flag); - /* Cleanup any outstanding RSCN activity */ - lpfc_els_flush_rscn(vport); - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_cmd(vport); - - lpfc_cleanup_rpis(vport, 0); + lpfc_port_link_failure(vport); - /* free any ndlp's on unused list */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_drop_node(vport, ndlp); - - /* Turn off discovery timer if its running */ - lpfc_can_disctmo(vport); } int @@ -629,7 +639,7 @@ lpfc_linkdown(struct lpfc_hba *phba) lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb); mb->vport = vport; mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(mb, phba->mbox_mem_pool); } @@ -643,8 +653,7 @@ lpfc_linkdown(struct lpfc_hba *phba) lpfc_config_link(phba, mb); mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mb->vport = vport; - if (lpfc_sli_issue_mbox(phba, mb, - (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(mb, phba->mbox_mem_pool); } @@ -686,7 +695,6 @@ static void lpfc_linkup_port(struct lpfc_vport *vport) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp, *next_ndlp; struct lpfc_hba *phba = vport->phba; if ((vport->load_flag & FC_UNLOADING) != 0) @@ -713,11 +721,6 @@ lpfc_linkup_port(struct lpfc_vport *vpor if (vport->fc_flag & FC_LBIT) lpfc_linkup_cleanup_nodes(vport); - /* free any ndlp's in unused state */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, - nlp_listp) - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_drop_node(vport, ndlp); } static int @@ -852,8 +855,6 @@ lpfc_mbx_cmpl_local_config_link(struct l * LPFC_FLOGI while waiting for FLOGI cmpl */ if (vport->port_state != LPFC_FLOGI) { - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); lpfc_initial_flogi(vport); } return; @@ -1022,8 +1023,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba lpfc_read_sparam(phba, sparam_mbox, 0); sparam_mbox->vport = vport; sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; - rc = lpfc_sli_issue_mbox(phba, sparam_mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mp = (struct lpfc_dmabuf *) sparam_mbox->context1; lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -1040,8 +1040,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba lpfc_config_link(phba, cfglink_mbox); cfglink_mbox->vport = vport; cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; - rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT); if (rc != MBX_NOT_FINISHED) return; mempool_free(cfglink_mbox, phba->mbox_mem_pool); @@ -1219,7 +1218,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vp lpfc_unreg_vpi(phba, vport->vpi, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi; - rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, "1800 Could not issue unreg_vpi\n"); @@ -1365,7 +1364,9 @@ out: lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - lpfc_drop_node(vport, ndlp); + + /* If no other thread is using the ndlp, free it */ + lpfc_nlp_not_used(ndlp); if (phba->fc_topology == TOPOLOGY_LOOP) { /* @@ -1656,8 +1657,17 @@ lpfc_dequeue_node(struct lpfc_vport *vpo void lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { + /* + * Use of lpfc_drop_node and UNUSED list. lpfc_drop_node should + * be used if we wish to issue the "last" lpfc_nlp_put() to remove + * the ndlp from the vport. The ndlp resides on the UNUSED list + * until ALL other outstanding threads have completed. Thus, if a + * ndlp is on the UNUSED list already, we should never do another + * lpfc_drop_node() on it. + */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); lpfc_nlp_put(ndlp); + return; } /* @@ -1868,8 +1878,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) mempool_free(mbox, phba->mbox_mem_pool); } @@ -1892,8 +1901,7 @@ lpfc_unreg_all_rpis(struct lpfc_vport *v lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); } @@ -1912,8 +1920,7 @@ lpfc_unreg_default_rpis(struct lpfc_vpor lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, "1815 Could not issue " @@ -1981,11 +1988,6 @@ lpfc_cleanup_node(struct lpfc_vport *vpo if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) list_del_init(&ndlp->dev_loss_evt.evt_listp); - if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) { - list_del_init(&ndlp->dev_loss_evt.evt_listp); - complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2)); - } - lpfc_unreg_rpi(vport, ndlp); return 0; @@ -1999,12 +2001,39 @@ lpfc_cleanup_node(struct lpfc_vport *vpo static void lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { + struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata; + LPFC_MBOXQ_t *mbox; + int rc; if (ndlp->nlp_flag & NLP_DELAY_TMO) { lpfc_cancel_retry_delay_tmo(vport, ndlp); } + if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) { + /* For this case we need to cleanup the default rpi + * allocated by the firmware. + */ + if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) + != NULL) { + rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID, + (uint8_t *) &vport->fc_sparam, mbox, 0); + if (rc) { + mempool_free(mbox, phba->mbox_mem_pool); + } + else { + mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; + mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; + mbox->vport = vport; + mbox->context2 = 0; + rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mbox, phba->mbox_mem_pool); + } + } + } + } + lpfc_cleanup_node(vport, ndlp); /* @@ -2132,6 +2161,12 @@ lpfc_setup_disc_node(struct lpfc_vport * } if (vport->fc_flag & FC_RSCN_MODE) { if (lpfc_rscn_payload_check(vport, did)) { + /* If we've already recieved a PLOGI from this NPort + * we don't need to try to discover it again. + */ + if (ndlp->nlp_flag & NLP_RCV_PLOGI) + return NULL; + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); @@ -2144,8 +2179,13 @@ lpfc_setup_disc_node(struct lpfc_vport * } else ndlp = NULL; } else { + /* If we've already recieved a PLOGI from this NPort, + * or we are already in the process of discovery on it, + * we don't need to try to discover it again. + */ if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || - ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) + ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || + ndlp->nlp_flag & NLP_RCV_PLOGI) return NULL; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(shost->host_lock); @@ -2220,8 +2260,7 @@ lpfc_issue_clear_la(struct lpfc_hba *phb lpfc_clear_la(phba, mbox); mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | - MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); lpfc_disc_flush_list(vport); @@ -2244,8 +2283,7 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox); regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi; regvpimbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, regvpimbox, - (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(regvpimbox, phba->mbox_mem_pool); } @@ -2426,7 +2464,6 @@ lpfc_disc_flush_list(struct lpfc_vport * if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { lpfc_free_tx(phba, ndlp); - lpfc_nlp_put(ndlp); } } } @@ -2516,6 +2553,7 @@ lpfc_disc_timeout_handler(struct lpfc_vp if (ndlp->nlp_type & NLP_FABRIC) { /* Clean up the ndlp on Fabric connections */ lpfc_drop_node(vport, ndlp); + } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* Fail outstanding IO now since device * is marked for PLOGI. @@ -2524,8 +2562,6 @@ lpfc_disc_timeout_handler(struct lpfc_vp } } if (vport->port_state != LPFC_FLOGI) { - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); lpfc_initial_flogi(vport); } break; @@ -2536,7 +2572,7 @@ lpfc_disc_timeout_handler(struct lpfc_vp /* Initial FLOGI timeout */ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, "0222 Initial %s timeout\n", - vport->vpi ? "FLOGI" : "FDISC"); + vport->vpi ? "FDISC" : "FLOGI"); /* Assume no Fabric and go on with discovery. * Check for outstanding ELS FLOGI to abort. @@ -2558,10 +2594,10 @@ lpfc_disc_timeout_handler(struct lpfc_vp /* Next look for NameServer ndlp */ ndlp = lpfc_findnode_did(vport, NameServer_DID); if (ndlp) - lpfc_nlp_put(ndlp); - /* Start discovery */ - lpfc_disc_start(vport); - break; + lpfc_els_abort(phba, ndlp); + + /* ReStart discovery */ + goto restart_disc; case LPFC_NS_QRY: /* Check for wait for NameServer Rsp timeout */ @@ -2580,6 +2616,7 @@ lpfc_disc_timeout_handler(struct lpfc_vp } vport->fc_ns_retry = 0; +restart_disc: /* * Discovery is over. * set port_state to PORT_READY if SLI2. @@ -2608,8 +2645,7 @@ lpfc_disc_timeout_handler(struct lpfc_vp initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0; initlinkmbox->vport = vport; initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, initlinkmbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT); lpfc_set_loopback_flag(phba); if (rc == MBX_NOT_FINISHED) mempool_free(initlinkmbox, phba->mbox_mem_pool); @@ -2753,8 +2789,7 @@ __lpfc_find_node(struct lpfc_vport *vpor struct lpfc_nodelist *ndlp; list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (ndlp->nlp_state != NLP_STE_UNUSED_NODE && - filter(ndlp, param)) + if (filter(ndlp, param)) return ndlp; } return NULL; @@ -2837,6 +2872,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, return; } +/* This routine releases all resources associated with a specifc NPort's ndlp + * and mempool_free's the nodelist. + */ static void lpfc_nlp_release(struct kref *kref) { @@ -2851,16 +2889,57 @@ lpfc_nlp_release(struct kref *kref) mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); } +/* This routine bumps the reference count for a ndlp structure to ensure + * that one discovery thread won't free a ndlp while another discovery thread + * is using it. + */ struct lpfc_nodelist * lpfc_nlp_get(struct lpfc_nodelist *ndlp) { - if (ndlp) + if (ndlp) { + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node get: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount)); kref_get(&ndlp->kref); + } return ndlp; } + +/* This routine decrements the reference count for a ndlp structure. If the + * count goes to 0, this indicates the the associated nodelist should be freed. + */ int lpfc_nlp_put(struct lpfc_nodelist *ndlp) { + if (ndlp) { + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node put: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount)); + } return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; } + +/* This routine free's the specified nodelist if it is not in use + * by any other discovery thread. This routine returns 1 if the ndlp + * is not being used by anyone and has been freed. A return value of + * 0 indicates it is being used by another discovery thread and the + * refcount is left unchanged. + */ +int +lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) +{ + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node not used: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount)); + + if (atomic_read(&ndlp->kref.refcount) == 1) { + lpfc_nlp_put(ndlp); + return 1; + } + return 0; +} + diff -puN drivers/scsi/lpfc/lpfc_hw.h~git-scsi-misc drivers/scsi/lpfc/lpfc_hw.h --- a/drivers/scsi/lpfc/lpfc_hw.h~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_hw.h @@ -139,6 +139,9 @@ struct lpfc_sli_ct_request { uint8_t len; uint8_t symbname[255]; } rsnn; + struct da_id { /* For DA_ID requests */ + uint32_t port_id; + } da_id; struct rspn { /* For RSPN_ID requests */ uint32_t PortId; uint8_t len; @@ -150,11 +153,7 @@ struct lpfc_sli_ct_request { struct gff_acc { uint8_t fbits[128]; } gff_acc; -#ifdef __BIG_ENDIAN_BITFIELD #define FCP_TYPE_FEATURE_OFFSET 7 -#else /* __LITTLE_ENDIAN_BITFIELD */ -#define FCP_TYPE_FEATURE_OFFSET 4 -#endif struct rff { uint32_t PortId; uint8_t reserved[2]; @@ -177,6 +176,8 @@ struct lpfc_sli_ct_request { sizeof(struct rnn)) #define RSNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ sizeof(struct rsnn)) +#define DA_ID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ + sizeof(struct da_id)) #define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ sizeof(struct rspn)) @@ -1228,7 +1229,8 @@ typedef struct { /* FireFly BIU registe #define HS_FFER3 0x20000000 /* Bit 29 */ #define HS_FFER2 0x40000000 /* Bit 30 */ #define HS_FFER1 0x80000000 /* Bit 31 */ -#define HS_FFERM 0xFF000000 /* Mask for error bits 31:24 */ +#define HS_CRIT_TEMP 0x00000100 /* Bit 8 */ +#define HS_FFERM 0xFF000100 /* Mask for error bits 31:24 and 8 */ /* Host Control Register */ @@ -1283,6 +1285,8 @@ typedef struct { /* FireFly BIU registe #define MBX_CONFIG_FARP 0x25 #define MBX_BEACON 0x2A #define MBX_HEARTBEAT 0x31 +#define MBX_WRITE_VPARMS 0x32 +#define MBX_ASYNCEVT_ENABLE 0x33 #define MBX_CONFIG_HBQ 0x7C #define MBX_LOAD_AREA 0x81 @@ -1344,6 +1348,7 @@ typedef struct { /* FireFly BIU registe /* SLI_2 IOCB Command Set */ +#define CMD_ASYNC_STATUS 0x7C #define CMD_RCV_SEQUENCE64_CX 0x81 #define CMD_XMIT_SEQUENCE64_CR 0x82 #define CMD_XMIT_SEQUENCE64_CX 0x83 @@ -1368,6 +1373,7 @@ typedef struct { /* FireFly BIU registe #define CMD_FCP_TRECEIVE64_CX 0xA1 #define CMD_FCP_TRSP64_CX 0xA3 +#define CMD_QUE_XRI64_CX 0xB3 #define CMD_IOCB_RCV_SEQ64_CX 0xB5 #define CMD_IOCB_RCV_ELS64_CX 0xB7 #define CMD_IOCB_RCV_CONT64_CX 0xBB @@ -1406,6 +1412,8 @@ typedef struct { /* FireFly BIU registe #define MBX_BUSY 0xffffff /* Attempted cmd to busy Mailbox */ #define MBX_TIMEOUT 0xfffffe /* time-out expired waiting for */ +#define TEMPERATURE_OFFSET 0xB0 /* Slim offset for critical temperature event */ + /* * Begin Structure Definitions for Mailbox Commands */ @@ -2606,6 +2614,18 @@ typedef struct { uint32_t IPAddress; } CONFIG_FARP_VAR; +/* Structure for MB Command MBX_ASYNCEVT_ENABLE (0x33) */ + +typedef struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd:30; + uint32_t ring:2; /* Ring for ASYNC_EVENT iocb Bits 0-1*/ +#else /* __LITTLE_ENDIAN */ + uint32_t ring:2; /* Ring for ASYNC_EVENT iocb Bits 0-1*/ + uint32_t rsvd:30; +#endif +} ASYNCEVT_ENABLE_VAR; + /* Union of all Mailbox Command types */ #define MAILBOX_CMD_WSIZE 32 #define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t)) @@ -2645,6 +2665,7 @@ typedef union { CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */ UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */ + ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */ } MAILVARIANTS; /* @@ -2987,6 +3008,21 @@ typedef struct { uint32_t fcpt_Length; /* transfer ready for IWRITE */ } FCPT_FIELDS64; +/* IOCB Command template for Async Status iocb commands */ +typedef struct { + uint32_t rsvd[4]; + uint32_t param; +#ifdef __BIG_ENDIAN_BITFIELD + uint16_t evt_code; /* High order bits word 5 */ + uint16_t sub_ctxt_tag; /* Low order bits word 5 */ +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint16_t sub_ctxt_tag; /* High order bits word 5 */ + uint16_t evt_code; /* Low order bits word 5 */ +#endif +} ASYNCSTAT_FIELDS; +#define ASYNC_TEMP_WARN 0x100 +#define ASYNC_TEMP_SAFE 0x101 + /* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7) or CMD_IOCB_RCV_SEQ64_CX (0xB5) */ @@ -3004,7 +3040,26 @@ struct rcv_sli3 { struct ulp_bde64 bde2; }; +/* Structure used for a single HBQ entry */ +struct lpfc_hbq_entry { + struct ulp_bde64 bde; + uint32_t buffer_tag; +}; +/* IOCB Command template for QUE_XRI64_CX (0xB3) command */ +typedef struct { + struct lpfc_hbq_entry buff; + uint32_t rsvd; + uint32_t rsvd1; +} QUE_XRI64_CX_FIELDS; + +struct que_xri64cx_ext_fields { + uint32_t iotag64_low; + uint32_t iotag64_high; + uint32_t ebde_count; + uint32_t rsvd; + struct lpfc_hbq_entry buff[5]; +}; typedef struct _IOCB { /* IOCB structure */ union { @@ -3028,6 +3083,8 @@ typedef struct _IOCB { /* IOCB structure XMT_SEQ_FIELDS64 xseq64; /* XMIT / BCAST cmd */ FCPI_FIELDS64 fcpi64; /* FCP 64 bit Initiator template */ FCPT_FIELDS64 fcpt64; /* FCP 64 bit target template */ + ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */ + QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */ uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */ } un; @@ -3085,6 +3142,10 @@ typedef struct _IOCB { /* IOCB structure union { struct rcv_sli3 rcvsli3; /* words 8 - 15 */ + + /* words 8-31 used for que_xri_cx iocb */ + struct que_xri64cx_ext_fields que_xri64cx_ext_words; + uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */ } unsli3; @@ -3124,12 +3185,6 @@ typedef struct _IOCB { /* IOCB structure } IOCB_t; -/* Structure used for a single HBQ entry */ -struct lpfc_hbq_entry { - struct ulp_bde64 bde; - uint32_t buffer_tag; -}; - #define SLI1_SLIM_SIZE (4 * 1024) diff -puN drivers/scsi/lpfc/lpfc_init.c~git-scsi-misc drivers/scsi/lpfc/lpfc_init.c --- a/drivers/scsi/lpfc/lpfc_init.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_init.c @@ -212,6 +212,18 @@ out_free_mbox: return 0; } +/* Completion handler for config async event mailbox command. */ +static void +lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) +{ + if (pmboxq->mb.mbxStatus == MBX_SUCCESS) + phba->temp_sensor_support = 1; + else + phba->temp_sensor_support = 0; + mempool_free(pmboxq, phba->mbox_mem_pool); + return; +} + /************************************************************************/ /* */ /* lpfc_config_port_post */ @@ -234,6 +246,15 @@ lpfc_config_port_post(struct lpfc_hba *p int i, j; int rc; + spin_lock_irq(&phba->hbalock); + /* + * If the Config port completed correctly the HBA is not + * over heated any more. + */ + if (phba->over_temp_state == HBA_OVER_TEMP) + phba->over_temp_state = HBA_NORMAL_TEMP; + spin_unlock_irq(&phba->hbalock); + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { phba->link_state = LPFC_HBA_ERROR; @@ -343,7 +364,7 @@ lpfc_config_port_post(struct lpfc_hba *p phba->link_state = LPFC_LINK_DOWN; - /* Only process IOCBs on ring 0 till hba_state is READY */ + /* Only process IOCBs on ELS ring till hba_state is READY */ if (psli->ring[psli->extra_ring].cmdringaddr) psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT; if (psli->ring[psli->fcp_ring].cmdringaddr) @@ -409,7 +430,21 @@ lpfc_config_port_post(struct lpfc_hba *p return -EIO; } /* MBOX buffer will be freed in mbox compl */ + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + lpfc_config_async(phba, pmb, LPFC_ELS_RING); + pmb->mbox_cmpl = lpfc_config_async_cmpl; + pmb->vport = phba->pport; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { + lpfc_printf_log(phba, + KERN_ERR, + LOG_INIT, + "0456 Adapter failed to issue " + "ASYNCEVT_ENABLE mbox status x%x \n.", + rc); + mempool_free(pmb, phba->mbox_mem_pool); + } return (0); } @@ -601,6 +636,8 @@ lpfc_handle_eratt(struct lpfc_hba *phba) struct lpfc_sli_ring *pring; struct lpfc_vport **vports; uint32_t event_data; + unsigned long temperature; + struct temp_event temp_event_data; struct Scsi_Host *shost; int i; @@ -655,6 +692,36 @@ lpfc_handle_eratt(struct lpfc_hba *phba) return; } lpfc_unblock_mgmt_io(phba); + } else if (phba->work_hs & HS_CRIT_TEMP) { + temperature = readl(phba->MBslimaddr + TEMPERATURE_OFFSET); + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + temp_event_data.event_code = LPFC_CRIT_TEMP; + temp_event_data.data = (uint32_t)temperature; + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0459 Adapter maximum temperature exceeded " + "(%ld), taking this port offline " + "Data: x%x x%x x%x\n", + temperature, phba->work_hs, + phba->work_status[0], phba->work_status[1]); + + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), + (char *) &temp_event_data, + SCSI_NL_VID_TYPE_PCI + | PCI_VENDOR_ID_EMULEX); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + phba->over_temp_state = HBA_OVER_TEMP; + spin_unlock_irq(&phba->hbalock); + lpfc_offline_prep(phba); + lpfc_offline(phba); + lpfc_unblock_mgmt_io(phba); + phba->link_state = LPFC_HBA_ERROR; + lpfc_hba_down_post(phba); + } else { /* The if clause above forces this code path when the status * failure is a value other than FFER6. Do not call the offline @@ -722,7 +789,7 @@ lpfc_handle_latt(struct lpfc_hba *phba) lpfc_read_la(phba, pmb, mp); pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la; pmb->vport = vport; - rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) goto lpfc_handle_latt_free_mbuf; @@ -1088,9 +1155,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, /* Allocate buffer to post */ mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); if (mp1) - mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, - &mp1->phys); - if (mp1 == 0 || mp1->virt == 0) { + mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys); + if (!mp1 || !mp1->virt) { kfree(mp1); lpfc_sli_release_iocbq(phba, iocb); pring->missbufcnt = cnt; @@ -1104,7 +1170,7 @@ lpfc_post_buffer(struct lpfc_hba *phba, if (mp2) mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp2->phys); - if (mp2 == 0 || mp2->virt == 0) { + if (!mp2 || !mp2->virt) { kfree(mp2); lpfc_mbuf_free(phba, mp1->virt, mp1->phys); kfree(mp1); @@ -1280,15 +1346,39 @@ lpfc_hba_init(struct lpfc_hba *phba, uin kfree(HashWorking); } -static void +void lpfc_cleanup(struct lpfc_vport *vport) { + struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; + int i = 0; - /* clean up phba - lpfc specific */ - lpfc_can_disctmo(vport); - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) - lpfc_nlp_put(ndlp); + if (phba->link_state > LPFC_LINK_DOWN) + lpfc_port_link_failure(vport); + + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->nlp_type & NLP_FABRIC) + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RECOVERY); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); + } + + /* At this point, ALL ndlp's should be gone + * because of the previous NLP_EVT_DEVICE_RM. + * Lets wait for this to happen, if needed. + */ + while (!list_empty(&vport->fc_nodes)) { + + if (i++ > 3000) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + "0233 Nodelist not empty\n"); + break; + } + + /* Wait for any activity on ndlps to settle */ + msleep(10); + } return; } @@ -1409,6 +1499,8 @@ lpfc_offline_prep(struct lpfc_hba * phba { struct lpfc_vport *vport = phba->pport; struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_vport **vports; + int i; if (vport->fc_flag & FC_OFFLINE_MODE) return; @@ -1417,10 +1509,34 @@ lpfc_offline_prep(struct lpfc_hba * phba lpfc_linkdown(phba); - /* Issue an unreg_login to all nodes */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) - if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) - lpfc_unreg_rpi(vport, ndlp); + /* Issue an unreg_login to all nodes on all vports */ + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) { + for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + struct Scsi_Host *shost; + + if (vports[i]->load_flag & FC_UNLOADING) + continue; + shost = lpfc_shost_from_vport(vports[i]); + list_for_each_entry_safe(ndlp, next_ndlp, + &vports[i]->fc_nodes, + nlp_listp) { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + continue; + if (ndlp->nlp_type & NLP_FABRIC) { + lpfc_disc_state_machine(vports[i], ndlp, + NULL, NLP_EVT_DEVICE_RECOVERY); + lpfc_disc_state_machine(vports[i], ndlp, + NULL, NLP_EVT_DEVICE_RM); + } + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_NPR_ADISC; + spin_unlock_irq(shost->host_lock); + lpfc_unreg_rpi(vports[i], ndlp); + } + } + } + lpfc_destroy_vport_work_array(vports); lpfc_sli_flush_mbox_queue(phba); } @@ -1454,7 +1570,6 @@ lpfc_offline(struct lpfc_hba *phba) if (vports != NULL) for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); - lpfc_cleanup(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->work_port_events = 0; vports[i]->fc_flag |= FC_OFFLINE_MODE; @@ -1674,6 +1789,8 @@ void lpfc_host_attrib_init(struct Scsi_H fc_host_supported_speeds(shost) = 0; if (phba->lmt & LMT_10Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT; + if (phba->lmt & LMT_8Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_8GBIT; if (phba->lmt & LMT_4Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT; if (phba->lmt & LMT_2Gb) @@ -1707,7 +1824,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, struct Scsi_Host *shost = NULL; void *ptr; unsigned long bar0map_len, bar2map_len; - int error = -ENODEV; + int error = -ENODEV, retval; int i, hbq_count; uint16_t iotag; @@ -1823,9 +1940,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, lpfc_sli_setup(phba); lpfc_sli_queue_setup(phba); - error = lpfc_mem_alloc(phba); - if (error) + retval = lpfc_mem_alloc(phba); + if (retval) { + error = retval; goto out_free_hbqslimp; + } /* Initialize and populate the iocb list per host. */ INIT_LIST_HEAD(&phba->lpfc_iocb_list); @@ -1891,8 +2010,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, pci_set_drvdata(pdev, shost); if (phba->cfg_use_msi) { - error = pci_enable_msi(phba->pcidev); - if (!error) + retval = pci_enable_msi(phba->pcidev); + if (!retval) phba->using_msi = 1; else lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -1900,11 +2019,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, "with IRQ\n"); } - error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED, + retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED, LPFC_DRIVER_NAME, phba); - if (error) { + if (retval) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0451 Enable interrupt handler failed\n"); + error = retval; goto out_disable_msi; } @@ -1914,11 +2034,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; - if (lpfc_alloc_sysfs_attr(vport)) + if (lpfc_alloc_sysfs_attr(vport)) { + error = -ENOMEM; goto out_free_irq; + } - if (lpfc_sli_hba_setup(phba)) + if (lpfc_sli_hba_setup(phba)) { + error = -ENODEV; goto out_remove_device; + } /* * hba setup may have changed the hba_queue_depth so we need to adjust @@ -2000,6 +2124,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev fc_remove_host(shost); scsi_remove_host(shost); + lpfc_cleanup(vport); + /* * Bring down the SLI Layer. This step disable all interrupts, * clears the rings, discards all mailbox commands, and resets @@ -2014,7 +2140,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev spin_unlock_irq(&phba->hbalock); lpfc_debugfs_terminate(vport); - lpfc_cleanup(vport); kthread_stop(phba->worker_thread); @@ -2239,12 +2364,22 @@ lpfc_init(void) printk(LPFC_MODULE_DESC "\n"); printk(LPFC_COPYRIGHT "\n"); + if (lpfc_enable_npiv) { + lpfc_transport_functions.vport_create = lpfc_vport_create; + lpfc_transport_functions.vport_delete = lpfc_vport_delete; + } lpfc_transport_template = fc_attach_transport(&lpfc_transport_functions); - lpfc_vport_transport_template = - fc_attach_transport(&lpfc_vport_transport_functions); - if (!lpfc_transport_template || !lpfc_vport_transport_template) + if (lpfc_transport_template == NULL) return -ENOMEM; + if (lpfc_enable_npiv) { + lpfc_vport_transport_template = + fc_attach_transport(&lpfc_vport_transport_functions); + if (lpfc_vport_transport_template == NULL) { + fc_release_transport(lpfc_transport_template); + return -ENOMEM; + } + } error = pci_register_driver(&lpfc_driver); if (error) { fc_release_transport(lpfc_transport_template); @@ -2259,7 +2394,8 @@ lpfc_exit(void) { pci_unregister_driver(&lpfc_driver); fc_release_transport(lpfc_transport_template); - fc_release_transport(lpfc_vport_transport_template); + if (lpfc_enable_npiv) + fc_release_transport(lpfc_vport_transport_template); } module_init(lpfc_init); diff -puN drivers/scsi/lpfc/lpfc_logmsg.h~git-scsi-misc drivers/scsi/lpfc/lpfc_logmsg.h --- a/drivers/scsi/lpfc/lpfc_logmsg.h~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_logmsg.h @@ -26,6 +26,7 @@ #define LOG_IP 0x20 /* IP traffic history */ #define LOG_FCP 0x40 /* FCP traffic history */ #define LOG_NODE 0x80 /* Node table events */ +#define LOG_TEMP 0x100 /* Temperature sensor events */ #define LOG_MISC 0x400 /* Miscellaneous events */ #define LOG_SLI 0x800 /* SLI events */ #define LOG_FCP_ERROR 0x1000 /* log errors, not underruns */ diff -puN drivers/scsi/lpfc/lpfc_mbox.c~git-scsi-misc drivers/scsi/lpfc/lpfc_mbox.c --- a/drivers/scsi/lpfc/lpfc_mbox.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_mbox.c @@ -82,6 +82,24 @@ lpfc_read_nv(struct lpfc_hba * phba, LPF } /**********************************************/ +/* lpfc_config_async Issue a */ +/* MBX_ASYNC_EVT_ENABLE mailbox command */ +/**********************************************/ +void +lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, + uint32_t ring) +{ + MAILBOX_t *mb; + + mb = &pmb->mb; + memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); + mb->mbxCommand = MBX_ASYNCEVT_ENABLE; + mb->un.varCfgAsyncEvent.ring = ring; + mb->mbxOwner = OWN_HOST; + return; +} + +/**********************************************/ /* lpfc_heart_beat Issue a HEART_BEAT */ /* mailbox command */ /**********************************************/ @@ -270,8 +288,10 @@ lpfc_read_sparam(struct lpfc_hba *phba, /* Get a buffer to hold the HBAs Service Parameters */ - if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) || - ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) { + mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); + if (mp) + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + if (!mp || !mp->virt) { kfree(mp); mb->mbxCommand = MBX_READ_SPARM64; /* READ_SPARAM: no buffers */ @@ -369,8 +389,10 @@ lpfc_reg_login(struct lpfc_hba *phba, ui mb->mbxOwner = OWN_HOST; /* Get a buffer to hold NPorts Service Parameters */ - if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) || - ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) { + mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); + if (mp) + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + if (!mp || !mp->virt) { kfree(mp); mb->mbxCommand = MBX_REG_LOGIN64; /* REG_LOGIN: no buffers */ diff -puN drivers/scsi/lpfc/lpfc_nportdisc.c~git-scsi-misc drivers/scsi/lpfc/lpfc_nportdisc.c --- a/drivers/scsi/lpfc/lpfc_nportdisc.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -287,6 +287,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); + if (wwn_to_u64(sp->portName.u.wwn) == 0) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0140 PLOGI Reject: invalid nname\n"); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, + NULL); + return 0; + } + if (wwn_to_u64(sp->nodeName.u.wwn) == 0) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0141 PLOGI Reject: invalid pname\n"); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, + NULL); + return 0; + } if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) { /* Reject this request because invalid parameters */ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; @@ -343,8 +361,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, lpfc_config_link(phba, mbox); mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; - rc = lpfc_sli_issue_mbox - (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); goto out; @@ -407,6 +424,41 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, ndlp, mbox); return 1; } + + /* If the remote NPort logs into us, before we can initiate + * discovery to them, cleanup the NPort from discovery accordingly. + */ + if (ndlp->nlp_state == NLP_STE_NPR_NODE) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + del_timer_sync(&ndlp->nlp_delayfunc); + ndlp->nlp_last_elscmd = 0; + + if (!list_empty(&ndlp->els_retry_evt.evt_listp)) + list_del_init(&ndlp->els_retry_evt.evt_listp); + + if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(shost->host_lock); + if (vport->num_disc_nodes) { + /* Check to see if there are more + * PLOGIs to be sent + */ + lpfc_more_plogi(vport); + + if (vport->num_disc_nodes == 0) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); + lpfc_end_rscn(vport); + } + } + } + } + lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); return 1; @@ -501,12 +553,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, spin_unlock_irq(shost->host_lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - } else { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); } + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; @@ -594,6 +643,25 @@ lpfc_disc_illegal(struct lpfc_vport *vpo return ndlp->nlp_state; } +static uint32_t +lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + /* This transition is only legal if we previously + * rcv'ed a PLOGI. Since we don't want 2 discovery threads + * working on the same NPortID, do nothing for this thread + * to stop it. + */ + if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + "0253 Illegal State Transition: node x%x " + "event x%x, state x%x Data: x%x x%x\n", + ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, + ndlp->nlp_flag); + } + return ndlp->nlp_state; +} + /* Start of Discovery State Machine routines */ static uint32_t @@ -605,11 +673,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_v cmdiocb = (struct lpfc_iocbq *) arg; if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { - ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } - lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -618,7 +683,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vpo void *arg, uint32_t evt) { lpfc_issue_els_logo(vport, ndlp, 0); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } @@ -633,7 +697,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vp ndlp->nlp_flag |= NLP_LOGO_ACC; spin_unlock_irq(shost->host_lock); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } @@ -642,7 +705,6 @@ static uint32_t lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -650,7 +712,6 @@ static uint32_t lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -778,6 +839,12 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_ lp = (uint32_t *) prsp->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); + if (wwn_to_u64(sp->portName.u.wwn) == 0 || + wwn_to_u64(sp->nodeName.u.wwn) == 0) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0142 PLOGI RSP: Invalid WWN.\n"); + goto out; + } if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3)) goto out; /* PLOGI chkparm OK */ @@ -828,8 +895,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_ } mbox->context2 = lpfc_nlp_get(ndlp); mbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) != MBX_NOT_FINISHED) { lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); @@ -864,9 +930,7 @@ out: "0261 Cannot Register NameServer login\n"); } - /* Free this node since the driver cannot login or has the wrong - sparm */ - lpfc_drop_node(vport, ndlp); + ndlp->nlp_flag |= NLP_DEFER_RM; return NLP_STE_FREED_NODE; } @@ -1137,7 +1201,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc (ndlp == (struct lpfc_nodelist *) mb->context2)) { mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); + __lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } lpfc_nlp_put(ndlp); @@ -1197,8 +1261,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct * retry discovery. */ if (mb->mbxStatus == MBXERR_RPI_FULL) { - ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); + ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); return ndlp->nlp_state; } @@ -1378,7 +1442,7 @@ out: lpfc_issue_els_logo(vport, ndlp, 0); ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); return ndlp->nlp_state; } @@ -1753,7 +1817,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vpo irsp = &rspiocb->iocb; if (irsp->ulpStatus) { - lpfc_drop_node(vport, ndlp); + ndlp->nlp_flag |= NLP_DEFER_RM; return NLP_STE_FREED_NODE; } return ndlp->nlp_state; @@ -1968,7 +2032,7 @@ static uint32_t (*lpfc_disc_action[NLP_S lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */ lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */ lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ + lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ lpfc_disc_illegal, /* CMPL_PRLI */ lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ @@ -1982,7 +2046,7 @@ static uint32_t (*lpfc_disc_action[NLP_S lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */ lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */ lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ + lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */ lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ diff -puN drivers/scsi/lpfc/lpfc_sli.c~git-scsi-misc drivers/scsi/lpfc/lpfc_sli.c --- a/drivers/scsi/lpfc/lpfc_sli.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_sli.c @@ -199,6 +199,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd case CMD_RCV_ELS_REQ_CX: case CMD_RCV_SEQUENCE64_CX: case CMD_RCV_ELS_REQ64_CX: + case CMD_ASYNC_STATUS: case CMD_IOCB_RCV_SEQ64_CX: case CMD_IOCB_RCV_ELS64_CX: case CMD_IOCB_RCV_CONT64_CX: @@ -473,8 +474,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *ph if (pring->txq_cnt && lpfc_is_link_up(phba) && (pring->ringno != phba->sli.fcp_ring || - phba->sli.sli_flag & LPFC_PROCESS_LA) && - !(pring->flag & LPFC_STOP_IOCB_MBX)) { + phba->sli.sli_flag & LPFC_PROCESS_LA)) { while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) && (nextiocb = lpfc_sli_ringtx_get(phba, pring))) @@ -489,31 +489,6 @@ lpfc_sli_resume_iocb(struct lpfc_hba *ph return; } -/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */ -static void -lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno) -{ - struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? - &phba->slim2p->mbx.us.s3_pgp.port[ringno] : - &phba->slim2p->mbx.us.s2.port[ringno]; - unsigned long iflags; - - /* If the ring is active, flag it */ - spin_lock_irqsave(&phba->hbalock, iflags); - if (phba->sli.ring[ringno].cmdringaddr) { - if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) { - phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX; - /* - * Force update of the local copy of cmdGetInx - */ - phba->sli.ring[ringno].local_getidx - = le32_to_cpu(pgp->cmdGetInx); - lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]); - } - } - spin_unlock_irqrestore(&phba->hbalock, iflags); -} - struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno) { @@ -565,6 +540,7 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba list_del(&hbq_buf->dbuf.list); (phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf); } + phba->hbqs[i].buffer_count = 0; } } @@ -633,8 +609,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hb return 0; } - start = lpfc_hbq_defs[hbqno]->buffer_count; - end = count + lpfc_hbq_defs[hbqno]->buffer_count; + start = phba->hbqs[hbqno].buffer_count; + end = count + start; if (end > lpfc_hbq_defs[hbqno]->entry_count) { end = lpfc_hbq_defs[hbqno]->entry_count; } @@ -646,7 +622,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hb return 1; hbq_buffer->tag = (i | (hbqno << 16)); if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) - lpfc_hbq_defs[hbqno]->buffer_count++; + phba->hbqs[hbqno].buffer_count++; else (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); } @@ -686,7 +662,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *ph } lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, "1803 Bad hbq tag. Data: x%x x%x\n", - tag, lpfc_hbq_defs[tag >> 16]->buffer_count); + tag, phba->hbqs[tag >> 16].buffer_count); return NULL; } @@ -712,6 +688,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxComm case MBX_LOAD_SM: case MBX_READ_NV: case MBX_WRITE_NV: + case MBX_WRITE_VPARMS: case MBX_RUN_BIU_DIAG: case MBX_INIT_LINK: case MBX_DOWN_LINK: @@ -754,6 +731,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxComm case MBX_FLASH_WR_ULA: case MBX_SET_DEBUG: case MBX_LOAD_EXP_ROM: + case MBX_ASYNCEVT_ENABLE: case MBX_REG_VPI: case MBX_UNREG_VPI: case MBX_HEARTBEAT: @@ -953,6 +931,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba return &new_hbq_entry->dbuf; } +static struct lpfc_dmabuf * +lpfc_sli_get_buff(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, + uint32_t tag) +{ + if (tag & QUE_BUFTAG_BIT) + return lpfc_sli_ring_taggedbuf_get(phba, pring, tag); + else + return lpfc_sli_replace_hbqbuff(phba, tag); +} + static int lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *saveq) @@ -961,9 +950,26 @@ lpfc_sli_process_unsol_iocb(struct lpfc_ WORD5 * w5p; uint32_t Rctl, Type; uint32_t match, i; + struct lpfc_iocbq *iocbq; match = 0; irsp = &(saveq->iocb); + + if (irsp->ulpCommand == CMD_ASYNC_STATUS) { + if (pring->lpfc_sli_rcv_async_status) + pring->lpfc_sli_rcv_async_status(phba, pring, saveq); + else + lpfc_printf_log(phba, + KERN_WARNING, + LOG_SLI, + "0316 Ring %d handler: unexpected " + "ASYNC_STATUS iocb received evt_code " + "0x%x\n", + pring->ringno, + irsp->un.asyncstat.evt_code); + return 1; + } + if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX) @@ -989,12 +995,69 @@ lpfc_sli_process_unsol_iocb(struct lpfc_ } if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - if (irsp->ulpBdeCount != 0) - saveq->context2 = lpfc_sli_replace_hbqbuff(phba, + struct lpfc_hbq_entry *hbqe_1, *hbqe_2; + hbqe_1 = (struct lpfc_hbq_entry *) &saveq->iocb.un.ulpWord[0]; + hbqe_2 = (struct lpfc_hbq_entry *) &saveq->iocb. + unsli3.sli3Words[4]; + + if (irsp->ulpBdeCount != 0) { + saveq->context2 = lpfc_sli_get_buff(phba, pring, + irsp->un.ulpWord[3]); + if (!saveq->context2) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0341 Ring %d Cannot find buffer for " + "an unsolicited iocb. tag 0x%x\n", + pring->ringno, + irsp->un.ulpWord[3]); + + } + if (irsp->ulpBdeCount == 2) { + saveq->context3 = lpfc_sli_get_buff(phba, pring, + irsp->unsli3.sli3Words[7]); + if (!saveq->context3) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0342 Ring %d Cannot find buffer for an" + " unsolicited iocb. tag 0x%x\n", + pring->ringno, + irsp->unsli3.sli3Words[7]); + } + list_for_each_entry(iocbq, &saveq->list, list) { + hbqe_1 = (struct lpfc_hbq_entry *) &iocbq->iocb. + un.ulpWord[0]; + hbqe_2 = (struct lpfc_hbq_entry *) &iocbq->iocb. + unsli3.sli3Words[4]; + irsp = &(iocbq->iocb); + + if (irsp->ulpBdeCount != 0) { + iocbq->context2 = lpfc_sli_get_buff(phba, pring, + irsp->un.ulpWord[3]); + if (!saveq->context2) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0343 Ring %d Cannot find " + "buffer for an unsolicited iocb" + ". tag 0x%x\n", pring->ringno, irsp->un.ulpWord[3]); - if (irsp->ulpBdeCount == 2) - saveq->context3 = lpfc_sli_replace_hbqbuff(phba, + } + if (irsp->ulpBdeCount == 2) { + iocbq->context3 = lpfc_sli_get_buff(phba, pring, irsp->unsli3.sli3Words[7]); + if (!saveq->context3) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0344 Ring %d Cannot find " + "buffer for an unsolicited " + "iocb. tag 0x%x\n", + pring->ringno, + irsp->unsli3.sli3Words[7]); + } + } } /* unSolicited Responses */ @@ -1921,8 +1984,8 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) "0329 Kill HBA Data: x%x x%x\n", phba->pport->port_state, psli->sli_flag); - if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL)) == 0) + pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmb) return 1; /* Disable the error attention */ @@ -2485,7 +2548,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hb lpfc_sli_abort_iocb_ring(phba, pring); lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0316 Resetting board due to mailbox timeout\n"); + "0345 Resetting board due to mailbox timeout\n"); /* * lpfc_offline calls lpfc_sli_hba_down which will clean up * on oustanding mailbox commands. @@ -2571,21 +2634,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb return MBX_NOT_FINISHED; } - /* Handle STOP IOCB processing flag. This is only meaningful - * if we are not polling for mbox completion. - */ - if (flag & MBX_STOP_IOCB) { - flag &= ~MBX_STOP_IOCB; - /* Now flag each ring */ - for (i = 0; i < psli->num_rings; i++) { - /* If the ring is active, flag it */ - if (psli->ring[i].cmdringaddr) { - psli->ring[i].flag |= - LPFC_STOP_IOCB_MBX; - } - } - } - /* Another mailbox command is still being processed, queue this * command to be processed later. */ @@ -2620,23 +2668,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb return MBX_BUSY; } - /* Handle STOP IOCB processing flag. This is only meaningful - * if we are not polling for mbox completion. - */ - if (flag & MBX_STOP_IOCB) { - flag &= ~MBX_STOP_IOCB; - if (flag == MBX_NOWAIT) { - /* Now flag each ring */ - for (i = 0; i < psli->num_rings; i++) { - /* If the ring is active, flag it */ - if (psli->ring[i].cmdringaddr) { - psli->ring[i].flag |= - LPFC_STOP_IOCB_MBX; - } - } - } - } - psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE; /* If we are not polling, we MUST be in SLI2 mode */ @@ -2848,7 +2879,7 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba /* * Lockless version of lpfc_sli_issue_iocb. */ -int +static int __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb, uint32_t flag) { @@ -2879,9 +2910,9 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *p /* * Check to see if we are blocking IOCB processing because of a - * outstanding mbox command. + * outstanding event. */ - if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX)) + if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT)) goto iocb_busy; if (unlikely(phba->link_state == LPFC_LINK_DOWN)) { @@ -2993,6 +3024,61 @@ lpfc_extra_ring_setup( struct lpfc_hba * return 0; } +static void +lpfc_sli_async_event_handler(struct lpfc_hba * phba, + struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq) +{ + IOCB_t *icmd; + uint16_t evt_code; + uint16_t temp; + struct temp_event temp_event_data; + struct Scsi_Host *shost; + + icmd = &iocbq->iocb; + evt_code = icmd->un.asyncstat.evt_code; + temp = icmd->ulpContext; + + if ((evt_code != ASYNC_TEMP_WARN) && + (evt_code != ASYNC_TEMP_SAFE)) { + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0346 Ring %d handler: unexpected ASYNC_STATUS" + " evt_code 0x%x\n", + pring->ringno, + icmd->un.asyncstat.evt_code); + return; + } + temp_event_data.data = (uint32_t)temp; + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + if (evt_code == ASYNC_TEMP_WARN) { + temp_event_data.event_code = LPFC_THRESHOLD_TEMP; + lpfc_printf_log(phba, + KERN_WARNING, + LOG_TEMP, + "0347 Adapter is very hot, please take " + "corrective action. temperature : %d Celsius\n", + temp); + } + if (evt_code == ASYNC_TEMP_SAFE) { + temp_event_data.event_code = LPFC_NORMAL_TEMP; + lpfc_printf_log(phba, + KERN_INFO, + LOG_TEMP, + "0340 Adapter temperature is OK now. " + "temperature : %d Celsius\n", + temp); + } + + /* Send temperature change event to applications */ + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), (char *) &temp_event_data, + SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); + +} + + int lpfc_sli_setup(struct lpfc_hba *phba) { @@ -3059,6 +3145,8 @@ lpfc_sli_setup(struct lpfc_hba *phba) pring->fast_iotag = 0; pring->iotag_ctr = 0; pring->iotag_max = 4096; + pring->lpfc_sli_rcv_async_status = + lpfc_sli_async_event_handler; pring->num_mask = 4; pring->prt[0].profile = 0; /* Mask 0 */ pring->prt[0].rctl = FC_ELS_REQ; @@ -3294,6 +3382,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba return 0; } +uint32_t +lpfc_sli_get_buffer_tag(struct lpfc_hba *phba) +{ + spin_lock_irq(&phba->hbalock); + phba->buffer_tag_count++; + /* + * Always set the QUE_BUFTAG_BIT to distiguish between + * a tag assigned by HBQ. + */ + phba->buffer_tag_count |= QUE_BUFTAG_BIT; + spin_unlock_irq(&phba->hbalock); + return phba->buffer_tag_count; +} + +struct lpfc_dmabuf * +lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + uint32_t tag) +{ + struct lpfc_dmabuf *mp, *next_mp; + struct list_head *slp = &pring->postbufq; + + /* Search postbufq, from the begining, looking for a match on tag */ + spin_lock_irq(&phba->hbalock); + list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { + if (mp->buffer_tag == tag) { + list_del_init(&mp->list); + pring->postbufq_cnt--; + spin_unlock_irq(&phba->hbalock); + return mp; + } + } + + spin_unlock_irq(&phba->hbalock); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0410 Cannot find virtual addr for buffer tag on " + "ring %d Data x%lx x%p x%p x%x\n", + pring->ringno, (unsigned long) tag, + slp->next, slp->prev, pring->postbufq_cnt); + + return NULL; +} struct lpfc_dmabuf * lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, @@ -3699,7 +3828,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba unsigned long flag; /* The caller must leave context1 empty. */ - if (pmboxq->context1 != 0) + if (pmboxq->context1) return MBX_NOT_FINISHED; /* setup wake call as IOCB callback */ @@ -3771,7 +3900,6 @@ lpfc_intr_handler(int irq, void *dev_id) uint32_t ha_copy; uint32_t work_ha_copy; unsigned long status; - int i; uint32_t control; MAILBOX_t *mbox, *pmbox; @@ -3990,10 +4118,6 @@ send_current_mbox: lpfc_mbox_cmpl_put(phba, pmb); goto send_next_mbox; } - } else { - /* Turn on IOCB processing */ - for (i = 0; i < phba->sli.num_rings; i++) - lpfc_sli_turn_on_ring(phba, i); } } diff -puN drivers/scsi/lpfc/lpfc_sli.h~git-scsi-misc drivers/scsi/lpfc/lpfc_sli.h --- a/drivers/scsi/lpfc/lpfc_sli.h~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_sli.h @@ -92,8 +92,6 @@ typedef struct lpfcMboxq { #define MBX_POLL 1 /* poll mailbox till command done, then return */ #define MBX_NOWAIT 2 /* issue command then return immediately */ -#define MBX_STOP_IOCB 4 /* Stop iocb processing till mbox cmds - complete */ #define LPFC_MAX_RING_MASK 4 /* max num of rctl/type masks allowed per ring */ @@ -129,9 +127,7 @@ struct lpfc_sli_ring { uint16_t flag; /* ring flags */ #define LPFC_DEFERRED_RING_EVENT 0x001 /* Deferred processing a ring event */ #define LPFC_CALL_RING_AVAILABLE 0x002 /* indicates cmd was full */ -#define LPFC_STOP_IOCB_MBX 0x010 /* Stop processing IOCB cmds mbox */ #define LPFC_STOP_IOCB_EVENT 0x020 /* Stop processing IOCB cmds event */ -#define LPFC_STOP_IOCB_MASK 0x030 /* Stop processing IOCB cmds mask */ uint16_t abtsiotag; /* tracks next iotag to use for ABTS */ uint32_t local_getidx; /* last available cmd index (from cmdGetInx) */ @@ -166,6 +162,8 @@ struct lpfc_sli_ring { struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK]; uint32_t num_mask; /* number of mask entries in prt array */ + void (*lpfc_sli_rcv_async_status) (struct lpfc_hba *, + struct lpfc_sli_ring *, struct lpfc_iocbq *); struct lpfc_sli_ring_stat stats; /* SLI statistical info */ @@ -199,9 +197,6 @@ struct lpfc_hbq_init { uint32_t add_count; /* number to allocate when starved */ } ; -#define LPFC_MAX_HBQ 16 - - /* Structure used to hold SLI statistical counters and info */ struct lpfc_sli_stat { uint64_t mbox_stat_err; /* Mbox cmds completed status error */ diff -puN drivers/scsi/lpfc/lpfc_version.h~git-scsi-misc drivers/scsi/lpfc/lpfc_version.h --- a/drivers/scsi/lpfc/lpfc_version.h~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.2.2" +#define LPFC_DRIVER_VERSION "8.2.3" #define LPFC_DRIVER_NAME "lpfc" diff -puN drivers/scsi/lpfc/lpfc_vport.c~git-scsi-misc drivers/scsi/lpfc/lpfc_vport.c --- a/drivers/scsi/lpfc/lpfc_vport.c~git-scsi-misc +++ a/drivers/scsi/lpfc/lpfc_vport.c @@ -125,15 +125,26 @@ lpfc_vport_sparm(struct lpfc_hba *phba, pmb->vport = vport; rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2); if (rc != MBX_SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, - "1818 VPort failed init, mbxCmd x%x " - "READ_SPARM mbxStatus x%x, rc = x%x\n", - mb->mbxCommand, mb->mbxStatus, rc); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - if (rc != MBX_TIMEOUT) - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; + if (signal_pending(current)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, + "1830 Signal aborted mbxCmd x%x\n", + mb->mbxCommand); + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + if (rc != MBX_TIMEOUT) + mempool_free(pmb, phba->mbox_mem_pool); + return -EINTR; + } else { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, + "1818 VPort failed init, mbxCmd x%x " + "READ_SPARM mbxStatus x%x, rc = x%x\n", + mb->mbxCommand, mb->mbxStatus, rc); + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + if (rc != MBX_TIMEOUT) + mempool_free(pmb, phba->mbox_mem_pool); + return -EIO; + } } memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm)); @@ -204,6 +215,7 @@ lpfc_vport_create(struct fc_vport *fc_vp int instance; int vpi; int rc = VPORT_ERROR; + int status; if ((phba->sli_rev < 3) || !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { @@ -248,13 +260,19 @@ lpfc_vport_create(struct fc_vport *fc_vp vport->vpi = vpi; lpfc_debugfs_initialize(vport); - if (lpfc_vport_sparm(phba, vport)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1813 Create VPORT failed. " - "Cannot get sparam\n"); + if ((status = lpfc_vport_sparm(phba, vport))) { + if (status == -EINTR) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + "1831 Create VPORT Interrupted.\n"); + rc = VPORT_ERROR; + } else { + lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + "1813 Create VPORT failed. " + "Cannot get sparam\n"); + rc = VPORT_NORESOURCES; + } lpfc_free_vpi(phba, vpi); destroy_port(vport); - rc = VPORT_NORESOURCES; goto error_out; } @@ -427,7 +445,6 @@ int lpfc_vport_delete(struct fc_vport *fc_vport) { struct lpfc_nodelist *ndlp = NULL; - struct lpfc_nodelist *next_ndlp; struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost; struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct lpfc_hba *phba = vport->phba; @@ -482,8 +499,18 @@ lpfc_vport_delete(struct fc_vport *fc_vp ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && - phba->link_state >= LPFC_LINK_UP) { - + phba->link_state >= LPFC_LINK_UP) { + if (vport->cfg_enable_da_id) { + timeout = msecs_to_jiffies(phba->fc_ratov * 2000); + if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0)) + while (vport->ct_flags && timeout) + timeout = schedule_timeout(timeout); + else + lpfc_printf_log(vport->phba, KERN_WARNING, + LOG_VPORT, + "1829 CT command failed to " + "delete objects on fabric. \n"); + } /* First look for the Fabric ndlp */ ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) { @@ -503,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vp } skip_logo: + lpfc_cleanup(vport); lpfc_sli_host_down(vport); - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RM); - } - lpfc_stop_vport_timers(vport); lpfc_unreg_all_rpis(vport); - lpfc_unreg_default_rpis(vport); - /* - * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the - * scsi_host_put() to release the vport. - */ - lpfc_mbx_unreg_vpi(vport); + + if (!(phba->pport->load_flag & FC_UNLOADING)) { + lpfc_unreg_default_rpis(vport); + /* + * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) + * does the scsi_host_put() to release the vport. + */ + lpfc_mbx_unreg_vpi(vport); + } lpfc_free_vpi(phba, vport->vpi); vport->work_port_events = 0; diff -puN drivers/scsi/megaraid/megaraid_sas.c~git-scsi-misc drivers/scsi/megaraid/megaraid_sas.c --- a/drivers/scsi/megaraid/megaraid_sas.c~git-scsi-misc +++ a/drivers/scsi/megaraid/megaraid_sas.c @@ -2,7 +2,7 @@ * * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2003-2005 LSI Logic Corporation. + * Copyright (c) 2003-2005 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.03.10-rc5 + * Version : v00.00.03.16-rc1 * * Authors: * (email-id : megaraidlinux@lsi.com) @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -46,10 +47,18 @@ #include #include "megaraid_sas.h" +/* + * poll_mode_io:1- schedule complete completion from q cmd + */ +static unsigned int poll_mode_io; +module_param_named(poll_mode_io, poll_mode_io, int, 0); +MODULE_PARM_DESC(poll_mode_io, + "Complete cmds from IO path, (default=0)"); + MODULE_LICENSE("GPL"); MODULE_VERSION(MEGASAS_VERSION); MODULE_AUTHOR("megaraidlinux@lsi.com"); -MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver"); +MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); /* * PCI ID table for all supported controllers @@ -76,6 +85,10 @@ static DEFINE_MUTEX(megasas_async_queue_ static u32 megasas_dbg_lvl; +static void +megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, + u8 alt_status); + /** * megasas_get_cmd - Get a command from the free pool * @instance: Adapter soft state @@ -855,6 +868,12 @@ megasas_queue_command(struct scsi_cmnd * atomic_inc(&instance->fw_outstanding); instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set); + /* + * Check if we have pend cmds to be completed + */ + if (poll_mode_io && atomic_read(&instance->fw_outstanding)) + tasklet_schedule(&instance->isr_tasklet); + return 0; @@ -886,6 +905,64 @@ static int megasas_slave_configure(struc } /** + * megasas_complete_cmd_dpc - Returns FW's controller structure + * @instance_addr: Address of adapter soft state + * + * Tasklet to complete cmds + */ +static void megasas_complete_cmd_dpc(unsigned long instance_addr) +{ + u32 producer; + u32 consumer; + u32 context; + struct megasas_cmd *cmd; + struct megasas_instance *instance = + (struct megasas_instance *)instance_addr; + unsigned long flags; + + /* If we have already declared adapter dead, donot complete cmds */ + if (instance->hw_crit_error) + return; + + spin_lock_irqsave(&instance->completion_lock, flags); + + producer = *instance->producer; + consumer = *instance->consumer; + + while (consumer != producer) { + context = instance->reply_queue[consumer]; + + cmd = instance->cmd_list[context]; + + megasas_complete_cmd(instance, cmd, DID_OK); + + consumer++; + if (consumer == (instance->max_fw_cmds + 1)) { + consumer = 0; + } + } + + *instance->consumer = producer; + + spin_unlock_irqrestore(&instance->completion_lock, flags); + + /* + * Check if we can restore can_queue + */ + if (instance->flag & MEGASAS_FW_BUSY + && time_after(jiffies, instance->last_time + 5 * HZ) + && atomic_read(&instance->fw_outstanding) < 17) { + + spin_lock_irqsave(instance->host->host_lock, flags); + instance->flag &= ~MEGASAS_FW_BUSY; + instance->host->can_queue = + instance->max_fw_cmds - MEGASAS_INT_CMDS; + + spin_unlock_irqrestore(instance->host->host_lock, flags); + } +} + +/** * megasas_wait_for_outstanding - Wait for all outstanding cmds * @instance: Adapter soft state * @@ -908,6 +985,11 @@ static int megasas_wait_for_outstanding( if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { printk(KERN_NOTICE "megasas: [%2d]waiting for %d " "commands to complete\n",i,outstanding); + /* + * Call cmd completion routine. Cmd to be + * be completed directly without depending on isr. + */ + megasas_complete_cmd_dpc((unsigned long)instance); } msleep(1000); @@ -1100,7 +1182,7 @@ megasas_service_aen(struct megasas_insta static struct scsi_host_template megasas_template = { .module = THIS_MODULE, - .name = "LSI Logic SAS based MegaRAID driver", + .name = "LSI SAS based MegaRAID driver", .proc_name = "megaraid_sas", .slave_configure = megasas_slave_configure, .queuecommand = megasas_queue_command, @@ -1749,57 +1831,119 @@ megasas_get_ctrl_info(struct megasas_ins } /** - * megasas_complete_cmd_dpc - Returns FW's controller structure - * @instance_addr: Address of adapter soft state + * megasas_issue_init_mfi - Initializes the FW + * @instance: Adapter soft state * - * Tasklet to complete cmds + * Issues the INIT MFI cmd */ -static void megasas_complete_cmd_dpc(unsigned long instance_addr) +static int +megasas_issue_init_mfi(struct megasas_instance *instance) { - u32 producer; - u32 consumer; u32 context; + struct megasas_cmd *cmd; - struct megasas_instance *instance = (struct megasas_instance *)instance_addr; - unsigned long flags; - /* If we have already declared adapter dead, donot complete cmds */ - if (instance->hw_crit_error) - return; + struct megasas_init_frame *init_frame; + struct megasas_init_queue_info *initq_info; + dma_addr_t init_frame_h; + dma_addr_t initq_info_h; - producer = *instance->producer; - consumer = *instance->consumer; + /* + * Prepare a init frame. Note the init frame points to queue info + * structure. Each frame has SGL allocated after first 64 bytes. For + * this frame - since we don't need any SGL - we use SGL's space as + * queue info structure + * + * We will not get a NULL command below. We just created the pool. + */ + cmd = megasas_get_cmd(instance); - while (consumer != producer) { - context = instance->reply_queue[consumer]; + init_frame = (struct megasas_init_frame *)cmd->frame; + initq_info = (struct megasas_init_queue_info *) + ((unsigned long)init_frame + 64); - cmd = instance->cmd_list[context]; + init_frame_h = cmd->frame_phys_addr; + initq_info_h = init_frame_h + 64; - megasas_complete_cmd(instance, cmd, DID_OK); + context = init_frame->context; + memset(init_frame, 0, MEGAMFI_FRAME_SIZE); + memset(initq_info, 0, sizeof(struct megasas_init_queue_info)); + init_frame->context = context; - consumer++; - if (consumer == (instance->max_fw_cmds + 1)) { - consumer = 0; - } - } + initq_info->reply_queue_entries = instance->max_fw_cmds + 1; + initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h; - *instance->consumer = producer; + initq_info->producer_index_phys_addr_lo = instance->producer_h; + initq_info->consumer_index_phys_addr_lo = instance->consumer_h; + + init_frame->cmd = MFI_CMD_INIT; + init_frame->cmd_status = 0xFF; + init_frame->queue_info_new_phys_addr_lo = initq_info_h; + + init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); /* - * Check if we can restore can_queue + * disable the intr before firing the init frame to FW */ - if (instance->flag & MEGASAS_FW_BUSY - && time_after(jiffies, instance->last_time + 5 * HZ) - && atomic_read(&instance->fw_outstanding) < 17) { + instance->instancet->disable_intr(instance->reg_set); - spin_lock_irqsave(instance->host->host_lock, flags); - instance->flag &= ~MEGASAS_FW_BUSY; - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; + /* + * Issue the init frame in polled mode + */ - spin_unlock_irqrestore(instance->host->host_lock, flags); + if (megasas_issue_polled(instance, cmd)) { + printk(KERN_ERR "megasas: Failed to init firmware\n"); + megasas_return_cmd(instance, cmd); + goto fail_fw_init; } + megasas_return_cmd(instance, cmd); + + return 0; + +fail_fw_init: + return -EINVAL; +} + +/** + * megasas_start_timer - Initializes a timer object + * @instance: Adapter soft state + * @timer: timer object to be initialized + * @fn: timer function + * @interval: time interval between timer function call + */ +static inline void +megasas_start_timer(struct megasas_instance *instance, + struct timer_list *timer, + void *fn, unsigned long interval) +{ + init_timer(timer); + timer->expires = jiffies + interval; + timer->data = (unsigned long)instance; + timer->function = fn; + add_timer(timer); +} + +/** + * megasas_io_completion_timer - Timer fn + * @instance_addr: Address of adapter soft state + * + * Schedules tasklet for cmd completion + * if poll_mode_io is set + */ +static void +megasas_io_completion_timer(unsigned long instance_addr) +{ + struct megasas_instance *instance = + (struct megasas_instance *)instance_addr; + + if (atomic_read(&instance->fw_outstanding)) + tasklet_schedule(&instance->isr_tasklet); + + /* Restart timer */ + if (poll_mode_io) + mod_timer(&instance->io_completion_timer, + jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL); } /** @@ -1814,22 +1958,15 @@ static int megasas_init_mfi(struct megas u32 reply_q_sz; u32 max_sectors_1; u32 max_sectors_2; + u32 tmp_sectors; struct megasas_register_set __iomem *reg_set; - - struct megasas_cmd *cmd; struct megasas_ctrl_info *ctrl_info; - - struct megasas_init_frame *init_frame; - struct megasas_init_queue_info *initq_info; - dma_addr_t init_frame_h; - dma_addr_t initq_info_h; - /* * Map the message registers */ instance->base_addr = pci_resource_start(instance->pdev, 0); - if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) { + if (pci_request_regions(instance->pdev, "megasas: LSI")) { printk(KERN_DEBUG "megasas: IO memory region busy!\n"); return -EBUSY; } @@ -1900,52 +2037,8 @@ static int megasas_init_mfi(struct megas goto fail_reply_queue; } - /* - * Prepare a init frame. Note the init frame points to queue info - * structure. Each frame has SGL allocated after first 64 bytes. For - * this frame - since we don't need any SGL - we use SGL's space as - * queue info structure - * - * We will not get a NULL command below. We just created the pool. - */ - cmd = megasas_get_cmd(instance); - - init_frame = (struct megasas_init_frame *)cmd->frame; - initq_info = (struct megasas_init_queue_info *) - ((unsigned long)init_frame + 64); - - init_frame_h = cmd->frame_phys_addr; - initq_info_h = init_frame_h + 64; - - memset(init_frame, 0, MEGAMFI_FRAME_SIZE); - memset(initq_info, 0, sizeof(struct megasas_init_queue_info)); - - initq_info->reply_queue_entries = instance->max_fw_cmds + 1; - initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h; - - initq_info->producer_index_phys_addr_lo = instance->producer_h; - initq_info->consumer_index_phys_addr_lo = instance->consumer_h; - - init_frame->cmd = MFI_CMD_INIT; - init_frame->cmd_status = 0xFF; - init_frame->queue_info_new_phys_addr_lo = initq_info_h; - - init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); - - /* - * disable the intr before firing the init frame to FW - */ - instance->instancet->disable_intr(instance->reg_set); - - /* - * Issue the init frame in polled mode - */ - if (megasas_issue_polled(instance, cmd)) { - printk(KERN_DEBUG "megasas: Failed to init firmware\n"); + if (megasas_issue_init_mfi(instance)) goto fail_fw_init; - } - - megasas_return_cmd(instance, cmd); ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL); @@ -1958,17 +2051,20 @@ static int megasas_init_mfi(struct megas * Note that older firmwares ( < FW ver 30) didn't report information * to calculate max_sectors_1. So the number ended up as zero always. */ + tmp_sectors = 0; if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) { max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) * ctrl_info->max_strips_per_io; max_sectors_2 = ctrl_info->max_request_size; - instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2) - ? max_sectors_1 : max_sectors_2; - } else - instance->max_sectors_per_req = instance->max_num_sge * - PAGE_SIZE / 512; + tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2); + } + + instance->max_sectors_per_req = instance->max_num_sge * + PAGE_SIZE / 512; + if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) + instance->max_sectors_per_req = tmp_sectors; kfree(ctrl_info); @@ -1976,12 +2072,17 @@ static int megasas_init_mfi(struct megas * Setup tasklet for cmd completion */ - tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, - (unsigned long)instance); + tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, + (unsigned long)instance); + + /* Initialize the cmd completion timer */ + if (poll_mode_io) + megasas_start_timer(instance, &instance->io_completion_timer, + megasas_io_completion_timer, + MEGASAS_COMPLETION_TIMER_INTERVAL); return 0; fail_fw_init: - megasas_return_cmd(instance, cmd); pci_free_consistent(instance->pdev, reply_q_sz, instance->reply_queue, instance->reply_queue_h); @@ -2263,6 +2364,28 @@ static int megasas_io_attach(struct mega return 0; } +static int +megasas_set_dma_mask(struct pci_dev *pdev) +{ + /* + * All our contollers are capable of performing 64-bit DMA + */ + if (IS_DMA64) { + if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) { + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) + goto fail_set_dma_mask; + } + } else { + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) + goto fail_set_dma_mask; + } + return 0; + +fail_set_dma_mask: + return 1; +} + /** * megasas_probe_one - PCI hotplug entry point * @pdev: PCI device structure @@ -2296,19 +2419,8 @@ megasas_probe_one(struct pci_dev *pdev, pci_set_master(pdev); - /* - * All our contollers are capable of performing 64-bit DMA - */ - if (IS_DMA64) { - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) { - - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) - goto fail_set_dma_mask; - } - } else { - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) - goto fail_set_dma_mask; - } + if (megasas_set_dma_mask(pdev)) + goto fail_set_dma_mask; host = scsi_host_alloc(&megasas_template, sizeof(struct megasas_instance)); @@ -2357,8 +2469,9 @@ megasas_probe_one(struct pci_dev *pdev, init_waitqueue_head(&instance->abort_cmd_wait_q); spin_lock_init(&instance->cmd_pool_lock); + spin_lock_init(&instance->completion_lock); - sema_init(&instance->aen_mutex, 1); + mutex_init(&instance->aen_mutex); sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS); /* @@ -2490,8 +2603,10 @@ static void megasas_flush_cache(struct m /** * megasas_shutdown_controller - Instructs FW to shutdown the controller * @instance: Adapter soft state + * @opcode: Shutdown/Hibernate */ -static void megasas_shutdown_controller(struct megasas_instance *instance) +static void megasas_shutdown_controller(struct megasas_instance *instance, + u32 opcode) { struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; @@ -2514,7 +2629,7 @@ static void megasas_shutdown_controller( dcmd->flags = MFI_FRAME_DIR_NONE; dcmd->timeout = 0; dcmd->data_xfer_len = 0; - dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN; + dcmd->opcode = opcode; megasas_issue_blocked_cmd(instance, cmd); @@ -2524,6 +2639,139 @@ static void megasas_shutdown_controller( } /** + * megasas_suspend - driver suspend entry point + * @pdev: PCI device structure + * @state: PCI power state to suspend routine + */ +static int __devinit +megasas_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct Scsi_Host *host; + struct megasas_instance *instance; + + instance = pci_get_drvdata(pdev); + host = instance->host; + + if (poll_mode_io) + del_timer_sync(&instance->io_completion_timer); + + megasas_flush_cache(instance); + megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); + tasklet_kill(&instance->isr_tasklet); + + pci_set_drvdata(instance->pdev, instance); + instance->instancet->disable_intr(instance->reg_set); + free_irq(instance->pdev->irq, instance); + + pci_save_state(pdev); + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +/** + * megasas_resume- driver resume entry point + * @pdev: PCI device structure + */ +static int __devinit +megasas_resume(struct pci_dev *pdev) +{ + int rval; + struct Scsi_Host *host; + struct megasas_instance *instance; + + instance = pci_get_drvdata(pdev); + host = instance->host; + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + + /* + * PCI prepping: enable device set bus mastering and dma mask + */ + rval = pci_enable_device(pdev); + + if (rval) { + printk(KERN_ERR "megasas: Enable device failed\n"); + return rval; + } + + pci_set_master(pdev); + + if (megasas_set_dma_mask(pdev)) + goto fail_set_dma_mask; + + /* + * Initialize MFI Firmware + */ + + *instance->producer = 0; + *instance->consumer = 0; + + atomic_set(&instance->fw_outstanding, 0); + + /* + * We expect the FW state to be READY + */ + if (megasas_transition_to_ready(instance)) + goto fail_ready_state; + + if (megasas_issue_init_mfi(instance)) + goto fail_init_mfi; + + tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, + (unsigned long)instance); + + /* + * Register IRQ + */ + if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, + "megasas", instance)) { + printk(KERN_ERR "megasas: Failed to register IRQ\n"); + goto fail_irq; + } + + instance->instancet->enable_intr(instance->reg_set); + + /* + * Initiate AEN (Asynchronous Event Notification) + */ + if (megasas_start_aen(instance)) + printk(KERN_ERR "megasas: Start AEN failed\n"); + + /* Initialize the cmd completion timer */ + if (poll_mode_io) + megasas_start_timer(instance, &instance->io_completion_timer, + megasas_io_completion_timer, + MEGASAS_COMPLETION_TIMER_INTERVAL); + return 0; + +fail_irq: +fail_init_mfi: + if (instance->evt_detail) + pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), + instance->evt_detail, + instance->evt_detail_h); + + if (instance->producer) + pci_free_consistent(pdev, sizeof(u32), instance->producer, + instance->producer_h); + if (instance->consumer) + pci_free_consistent(pdev, sizeof(u32), instance->consumer, + instance->consumer_h); + scsi_host_put(host); + +fail_set_dma_mask: +fail_ready_state: + + pci_disable_device(pdev); + + return -ENODEV; +} + +/** * megasas_detach_one - PCI hot"un"plug entry point * @pdev: PCI device structure */ @@ -2536,9 +2784,12 @@ static void megasas_detach_one(struct pc instance = pci_get_drvdata(pdev); host = instance->host; + if (poll_mode_io) + del_timer_sync(&instance->io_completion_timer); + scsi_remove_host(instance->host); megasas_flush_cache(instance); - megasas_shutdown_controller(instance); + megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); tasklet_kill(&instance->isr_tasklet); /* @@ -2660,6 +2911,7 @@ megasas_mgmt_fw_ioctl(struct megasas_ins void *sense = NULL; dma_addr_t sense_handle; u32 *sense_ptr; + unsigned long *sense_buff; memset(kbuff_arr, 0, sizeof(kbuff_arr)); @@ -2764,14 +3016,16 @@ megasas_mgmt_fw_ioctl(struct megasas_ins */ if (ioc->sense_len) { /* - * sense_ptr points to the location that has the user + * sense_buff points to the location that has the user * sense buffer address */ - sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw + - ioc->sense_off); + sense_buff = (unsigned long *) ((unsigned long)ioc->frame.raw + + ioc->sense_off); - if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)), - sense, ioc->sense_len)) { + if (copy_to_user((void __user *)(unsigned long)(*sense_buff), + sense, ioc->sense_len)) { + printk(KERN_ERR "megasas: Failed to copy out to user " + "sense data\n"); error = -EFAULT; goto out; } @@ -2874,10 +3128,10 @@ static int megasas_mgmt_ioctl_aen(struct if (!instance) return -ENODEV; - down(&instance->aen_mutex); + mutex_lock(&instance->aen_mutex); error = megasas_register_aen(instance, aen.seq_num, aen.class_locale_word); - up(&instance->aen_mutex); + mutex_unlock(&instance->aen_mutex); return error; } @@ -2977,6 +3231,8 @@ static struct pci_driver megasas_pci_dri .id_table = megasas_pci_table, .probe = megasas_probe_one, .remove = __devexit_p(megasas_detach_one), + .suspend = megasas_suspend, + .resume = megasas_resume, .shutdown = megasas_shutdown, }; @@ -3004,7 +3260,7 @@ static DRIVER_ATTR(release_date, S_IRUGO static ssize_t megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf) { - return sprintf(buf,"%u",megasas_dbg_lvl); + return sprintf(buf, "%u\n", megasas_dbg_lvl); } static ssize_t @@ -3019,7 +3275,65 @@ megasas_sysfs_set_dbg_lvl(struct device_ } static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl, - megasas_sysfs_set_dbg_lvl); + megasas_sysfs_set_dbg_lvl); + +static ssize_t +megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf) +{ + return sprintf(buf, "%u\n", poll_mode_io); +} + +static ssize_t +megasas_sysfs_set_poll_mode_io(struct device_driver *dd, + const char *buf, size_t count) +{ + int retval = count; + int tmp = poll_mode_io; + int i; + struct megasas_instance *instance; + + if (sscanf(buf, "%u", &poll_mode_io) < 1) { + printk(KERN_ERR "megasas: could not set poll_mode_io\n"); + retval = -EINVAL; + } + + /* + * Check if poll_mode_io is already set or is same as previous value + */ + if ((tmp && poll_mode_io) || (tmp == poll_mode_io)) + goto out; + + if (poll_mode_io) { + /* + * Start timers for all adapters + */ + for (i = 0; i < megasas_mgmt_info.max_index; i++) { + instance = megasas_mgmt_info.instance[i]; + if (instance) { + megasas_start_timer(instance, + &instance->io_completion_timer, + megasas_io_completion_timer, + MEGASAS_COMPLETION_TIMER_INTERVAL); + } + } + } else { + /* + * Delete timers for all adapters + */ + for (i = 0; i < megasas_mgmt_info.max_index; i++) { + instance = megasas_mgmt_info.instance[i]; + if (instance) + del_timer_sync(&instance->io_completion_timer); + } + } + +out: + return retval; +} + +static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO, + megasas_sysfs_show_poll_mode_io, + megasas_sysfs_set_poll_mode_io); /** * megasas_init - Driver load entry point @@ -3070,8 +3384,16 @@ static int __init megasas_init(void) &driver_attr_dbg_lvl); if (rval) goto err_dcf_dbg_lvl; + rval = driver_create_file(&megasas_pci_driver.driver, + &driver_attr_poll_mode_io); + if (rval) + goto err_dcf_poll_mode_io; return rval; + +err_dcf_poll_mode_io: + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_dbg_lvl); err_dcf_dbg_lvl: driver_remove_file(&megasas_pci_driver.driver, &driver_attr_release_date); @@ -3090,6 +3412,8 @@ err_pcidrv: static void __exit megasas_exit(void) { driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_poll_mode_io); + driver_remove_file(&megasas_pci_driver.driver, &driver_attr_dbg_lvl); driver_remove_file(&megasas_pci_driver.driver, &driver_attr_release_date); diff -puN drivers/scsi/megaraid/megaraid_sas.h~git-scsi-misc drivers/scsi/megaraid/megaraid_sas.h --- a/drivers/scsi/megaraid/megaraid_sas.h~git-scsi-misc +++ a/drivers/scsi/megaraid/megaraid_sas.h @@ -2,7 +2,7 @@ * * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2003-2005 LSI Logic Corporation. + * Copyright (c) 2003-2005 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,9 +18,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.03.10-rc5" -#define MEGASAS_RELDATE "May 17, 2007" -#define MEGASAS_EXT_VERSION "Thu May 17 10:09:32 PDT 2007" +#define MEGASAS_VERSION "00.00.03.16-rc1" +#define MEGASAS_RELDATE "Nov. 07, 2007" +#define MEGASAS_EXT_VERSION "Thu. Nov. 07 10:09:32 PDT 2007" /* * Device IDs @@ -117,6 +117,7 @@ #define MR_FLUSH_DISK_CACHE 0x02 #define MR_DCMD_CTRL_SHUTDOWN 0x01050000 +#define MR_DCMD_HIBERNATE_SHUTDOWN 0x01060000 #define MR_ENABLE_DRIVE_SPINDOWN 0x01 #define MR_DCMD_CTRL_EVENT_GET_INFO 0x01040100 @@ -570,7 +571,8 @@ struct megasas_ctrl_info { #define IS_DMA64 (sizeof(dma_addr_t) == 8) #define MFI_OB_INTR_STATUS_MASK 0x00000002 -#define MFI_POLL_TIMEOUT_SECS 10 +#define MFI_POLL_TIMEOUT_SECS 60 +#define MEGASAS_COMPLETION_TIMER_INTERVAL (HZ/10) #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 @@ -1083,13 +1085,15 @@ struct megasas_instance { struct megasas_cmd **cmd_list; struct list_head cmd_pool; spinlock_t cmd_pool_lock; + /* used to synch producer, consumer ptrs in dpc */ + spinlock_t completion_lock; struct dma_pool *frame_dma_pool; struct dma_pool *sense_dma_pool; struct megasas_evt_detail *evt_detail; dma_addr_t evt_detail_h; struct megasas_cmd *aen_cmd; - struct semaphore aen_mutex; + struct mutex aen_mutex; struct semaphore ioctl_sem; struct Scsi_Host *host; @@ -1108,6 +1112,8 @@ struct megasas_instance { u8 flag; unsigned long last_time; + + struct timer_list io_completion_timer; }; #define MEGASAS_IS_LOGICAL(scp) \ diff -puN drivers/scsi/pcmcia/nsp_cs.c~git-scsi-misc drivers/scsi/pcmcia/nsp_cs.c --- a/drivers/scsi/pcmcia/nsp_cs.c~git-scsi-misc +++ a/drivers/scsi/pcmcia/nsp_cs.c @@ -135,6 +135,11 @@ static nsp_hw_data nsp_data_base; /* att #define NSP_DEBUG_BUF_LEN 150 +static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc) +{ + scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc); +} + static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...) { va_list args; @@ -192,8 +197,10 @@ static int nsp_queuecommand(struct scsi_ #endif nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d", - SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); + nsp_dbg(NSP_DEBUG_QUEUECOMMAND, + "SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d", + SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt), + scsi_bufflen(SCpnt), scsi_sg_count(SCpnt)); //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC); SCpnt->scsi_done = done; @@ -225,7 +232,7 @@ static int nsp_queuecommand(struct scsi_ SCpnt->SCp.have_data_in = IO_UNKNOWN; SCpnt->SCp.sent_command = 0; SCpnt->SCp.phase = PH_UNDETERMINED; - SCpnt->resid = SCpnt->request_bufflen; + scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); /* setup scratch area SCp.ptr : buffer pointer @@ -233,14 +240,14 @@ static int nsp_queuecommand(struct scsi_ SCp.buffer : next buffer SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ - if (SCpnt->use_sg) { - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + if (scsi_bufflen(SCpnt)) { + SCpnt->SCp.buffer = scsi_sglist(SCpnt); SCpnt->SCp.ptr = BUFFER_ADDR; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; } else { - SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; - SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.ptr = NULL; + SCpnt->SCp.this_residual = 0; SCpnt->SCp.buffer = NULL; SCpnt->SCp.buffers_residual = 0; } @@ -721,7 +728,9 @@ static void nsp_pio_read(struct scsi_cmn ocount = data->FifoCount; nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d", - SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); + SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr, + SCpnt->SCp.this_residual, SCpnt->SCp.buffer, + SCpnt->SCp.buffers_residual); time_out = 1000; @@ -771,7 +780,7 @@ static void nsp_pio_read(struct scsi_cmn return; } - SCpnt->resid -= res; + nsp_inc_resid(SCpnt, -res); SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; @@ -795,10 +804,12 @@ static void nsp_pio_read(struct scsi_cmn if (time_out == 0) { nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d", - SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); + scsi_get_resid(SCpnt), SCpnt->SCp.this_residual, + SCpnt->SCp.buffers_residual); } nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount); - nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid); + nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, + scsi_get_resid(SCpnt)); } /* @@ -816,7 +827,9 @@ static void nsp_pio_write(struct scsi_cm ocount = data->FifoCount; nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x", - data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid); + data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, + SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, + scsi_get_resid(SCpnt)); time_out = 1000; @@ -830,7 +843,7 @@ static void nsp_pio_write(struct scsi_cm nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res); /* Put back pointer */ - SCpnt->resid += res; + nsp_inc_resid(SCpnt, res); SCpnt->SCp.ptr -= res; SCpnt->SCp.this_residual += res; ocount -= res; @@ -866,7 +879,7 @@ static void nsp_pio_write(struct scsi_cm break; } - SCpnt->resid -= res; + nsp_inc_resid(SCpnt, -res); SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; @@ -886,10 +899,12 @@ static void nsp_pio_write(struct scsi_cm data->FifoCount = ocount; if (time_out == 0) { - nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid); + nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", + scsi_get_resid(SCpnt)); } nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount); - nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid); + nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, + scsi_get_resid(SCpnt)); } #undef RFIFO_CRIT #undef WFIFO_CRIT @@ -911,9 +926,8 @@ static int nsp_nexus(struct scsi_cmnd *S nsp_index_write(base, SYNCREG, sync->SyncRegister); nsp_index_write(base, ACKWIDTH, sync->AckWidth); - if (SCpnt->use_sg == 0 || - SCpnt->resid % 4 != 0 || - SCpnt->resid <= PAGE_SIZE ) { + if (scsi_get_resid(SCpnt) % 4 != 0 || + scsi_get_resid(SCpnt) <= PAGE_SIZE ) { data->TransferMode = MODE_IO8; } else if (nsp_burst_mode == BURST_MEM32) { data->TransferMode = MODE_MEM32; diff -puN drivers/scsi/ppa.c~git-scsi-misc drivers/scsi/ppa.c --- a/drivers/scsi/ppa.c~git-scsi-misc +++ a/drivers/scsi/ppa.c @@ -750,18 +750,16 @@ static int ppa_engine(ppa_struct *dev, s cmd->SCp.phase++; case 4: /* Phase 4 - Setup scatter/gather buffers */ - if (cmd->use_sg) { - /* if many buffers are available, start filling the first */ - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); } else { - /* else fill the only available buffer */ cmd->SCp.buffer = NULL; - cmd->SCp.this_residual = cmd->request_bufflen; - cmd->SCp.ptr = cmd->request_buffer; + cmd->SCp.this_residual = 0; + cmd->SCp.ptr = NULL; } - cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.phase++; case 5: /* Phase 5 - Data transfer stage */ diff -puN drivers/scsi/psi240i.c~git-scsi-misc /dev/null --- a/drivers/scsi/psi240i.c +++ /dev/null @@ -1,689 +0,0 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux. - * - * Copyright (c) 1997 Perceptive Solutions, Inc. - * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * File Name: psi240i.c - * - * Description: SCSI driver for the PSI240I EIDE interface card. - * - *-M*************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "scsi.h" -#include - -#include "psi240i.h" -#include "psi_chip.h" - -//#define DEBUG 1 - -#ifdef DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - -#define MAXBOARDS 6 /* Increase this and the sizes of the arrays below, if you need more. */ - -#define PORT_DATA 0 -#define PORT_ERROR 1 -#define PORT_SECTOR_COUNT 2 -#define PORT_LBA_0 3 -#define PORT_LBA_8 4 -#define PORT_LBA_16 5 -#define PORT_LBA_24 6 -#define PORT_STAT_CMD 7 -#define PORT_SEL_FAIL 8 -#define PORT_IRQ_STATUS 9 -#define PORT_ADDRESS 10 -#define PORT_FAIL 11 -#define PORT_ALT_STAT 12 - -typedef struct - { - UCHAR device; // device code - UCHAR byte6; // device select register image - UCHAR spigot; // spigot number - UCHAR expectingIRQ; // flag for expecting and interrupt - USHORT sectors; // number of sectors per track - USHORT heads; // number of heads - USHORT cylinders; // number of cylinders for this device - USHORT spareword; // placeholder - ULONG blocks; // number of blocks on device - } OUR_DEVICE, *POUR_DEVICE; - -typedef struct - { - USHORT ports[13]; - OUR_DEVICE device[8]; - struct scsi_cmnd *pSCmnd; - IDE_STRUCT ide; - ULONG startSector; - USHORT sectorCount; - struct scsi_cmnd *SCpnt; - VOID *buffer; - USHORT expectingIRQ; - } ADAPTER240I, *PADAPTER240I; - -#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata) - -static struct Scsi_Host *PsiHost[6] = {NULL,}; /* One for each IRQ level (10-15) */ -static IDENTIFY_DATA identifyData; -static SETUP ChipSetup; - -static USHORT portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5}; - -/**************************************************************** - * Name: WriteData :LOCAL - * - * Description: Write data to device. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static int WriteData (PADAPTER240I padapter) - { - ULONG timer; - USHORT *pports = padapter->ports; - - timer = jiffies + TIMEOUT_DRQ; // calculate the timeout value - do { - if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ ) - { - outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256); - return 0; - } - } while ( time_after(timer, jiffies) ); // test for timeout - - padapter->ide.ide.ides.cmd = 0; // null out the command byte - return 1; - } -/**************************************************************** - * Name: IdeCmd :LOCAL - * - * Description: Process a queued command from the SCSI manager. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: Zero if no error or status register contents on error. - * - ****************************************************************/ -static UCHAR IdeCmd (PADAPTER240I padapter) - { - ULONG timer; - USHORT *pports = padapter->ports; - UCHAR status; - - outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]); // select the spigot - outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]); // select the drive - timer = jiffies + TIMEOUT_READY; // calculate the timeout value - do { - status = inb_p (padapter->ports[PORT_STAT_CMD]); - if ( status & IDE_STATUS_DRDY ) - { - outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]); - outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]); - outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]); - outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]); - padapter->expectingIRQ = 1; - outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]); - - if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE ) - return (WriteData (padapter)); - - return 0; - } - } while ( time_after(timer, jiffies) ); // test for timeout - - padapter->ide.ide.ides.cmd = 0; // null out the command byte - return status; - } -/**************************************************************** - * Name: SetupTransfer :LOCAL - * - * Description: Setup a data transfer command. - * - * Parameters: padapter - Pointer adapter data structure. - * drive - Drive/head register upper nibble only. - * - * Returns: TRUE if no data to transfer. - * - ****************************************************************/ -static int SetupTransfer (PADAPTER240I padapter, UCHAR drive) - { - if ( padapter->sectorCount ) - { - *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector; - padapter->ide.ide.ide[6] |= drive; - padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount; - padapter->sectorCount -= padapter->ide.ide.ides.sectors; // bump the start and count for next xfer - padapter->startSector += padapter->ide.ide.ides.sectors; - return 0; - } - else - { - padapter->ide.ide.ides.cmd = 0; // null out the command byte - padapter->SCpnt = NULL; - return 1; - } - } -/**************************************************************** - * Name: DecodeError :LOCAL - * - * Description: Decode and process device errors. - * - * Parameters: pshost - Pointer to host data block. - * status - Status register code. - * - * Returns: The driver status code. - * - ****************************************************************/ -static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status) - { - PADAPTER240I padapter = HOSTDATA(pshost); - UCHAR error; - - padapter->expectingIRQ = 0; - padapter->SCpnt = NULL; - if ( status & IDE_STATUS_WRITE_FAULT ) - { - return DID_PARITY << 16; - } - if ( status & IDE_STATUS_BUSY ) - return DID_BUS_BUSY << 16; - - error = inb_p (padapter->ports[PORT_ERROR]); - DEB(printk ("\npsi240i error register: %x", error)); - switch ( error ) - { - case IDE_ERROR_AMNF: - case IDE_ERROR_TKONF: - case IDE_ERROR_ABRT: - case IDE_ERROR_IDFN: - case IDE_ERROR_UNC: - case IDE_ERROR_BBK: - default: - return DID_ERROR << 16; - } - return DID_ERROR << 16; - } -/**************************************************************** - * Name: Irq_Handler :LOCAL - * - * Description: Interrupt handler. - * - * Parameters: irq - Hardware IRQ number. - * dev_id - - * - * Returns: TRUE if drive is not ready in time. - * - ****************************************************************/ -static void Irq_Handler (int irq, void *dev_id) - { - struct Scsi_Host *shost; // Pointer to host data block - PADAPTER240I padapter; // Pointer to adapter control structure - USHORT *pports; // I/O port array - struct scsi_cmnd *SCpnt; - UCHAR status; - int z; - - DEB(printk ("\npsi240i received interrupt\n")); - - shost = PsiHost[irq - 10]; - if ( !shost ) - panic ("Splunge!"); - - padapter = HOSTDATA(shost); - pports = padapter->ports; - SCpnt = padapter->SCpnt; - - if ( !padapter->expectingIRQ ) - { - DEB(printk ("\npsi240i Unsolicited interrupt\n")); - return; - } - padapter->expectingIRQ = 0; - - status = inb_p (padapter->ports[PORT_STAT_CMD]); // read the device status - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - goto irqerror; - - DEB(printk ("\npsi240i processing interrupt")); - switch ( padapter->ide.ide.ides.cmd ) // decide how to handle the interrupt - { - case IDE_CMD_READ_MULTIPLE: - if ( status & IDE_STATUS_DRQ ) - { - insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256); - padapter->buffer += padapter->ide.ide.ides.sectors * 512; - if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) ) - { - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; - } - if ( !(status = IdeCmd (padapter)) ) - return; - } - break; - - case IDE_CMD_WRITE_MULTIPLE: - padapter->buffer += padapter->ide.ide.ides.sectors * 512; - if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) ) - { - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; - } - if ( !(status = IdeCmd (padapter)) ) - return; - break; - - case IDE_COMMAND_IDENTIFY: - { - PINQUIRYDATA pinquiryData = SCpnt->request_buffer; - - if ( status & IDE_STATUS_DRQ ) - { - insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1); - - memset (pinquiryData, 0, SCpnt->request_bufflen); // Zero INQUIRY data structure. - pinquiryData->DeviceType = 0; - pinquiryData->Versions = 2; - pinquiryData->AdditionalLength = 35 - 4; - - // Fill in vendor identification fields. - for ( z = 0; z < 8; z += 2 ) - { - pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1]; - pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z]; - } - - // Initialize unused portion of product id. - for ( z = 0; z < 4; z++ ) - pinquiryData->ProductId[12 + z] = ' '; - - // Move firmware revision from IDENTIFY data to - // product revision in INQUIRY data. - for ( z = 0; z < 4; z += 2 ) - { - pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)identifyData.FirmwareRevision)[z + 1]; - pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z]; - } - - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; - } - break; - } - - default: - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; - } - -irqerror:; - DEB(printk ("\npsi240i error Device Status: %X\n", status)); - SCpnt->result = DecodeError (shost, status); - SCpnt->scsi_done (SCpnt); - } - -static irqreturn_t do_Irq_Handler (int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave(dev->host_lock, flags); - Irq_Handler(irq, dev_id); - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} - -/**************************************************************** - * Name: Psi240i_QueueCommand - * - * Description: Process a queued command from the SCSI manager. - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * done - Pointer to done function to call. - * - * Returns: Status code. - * - ****************************************************************/ -static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) - { - UCHAR *cdb = (UCHAR *)SCpnt->cmnd; - // Pointer to SCSI CDB - PADAPTER240I padapter = HOSTDATA (SCpnt->device->host); - // Pointer to adapter control structure - POUR_DEVICE pdev = &padapter->device [SCpnt->device->id]; - // Pointer to device information - UCHAR rc; - // command return code - - SCpnt->scsi_done = done; - padapter->ide.ide.ides.spigot = pdev->spigot; - padapter->buffer = SCpnt->request_buffer; - if (done) - { - if ( !pdev->device ) - { - SCpnt->result = DID_BAD_TARGET << 16; - done (SCpnt); - return 0; - } - } - else - { - printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb); - return 0; - } - - switch ( *cdb ) - { - case SCSIOP_INQUIRY: // inquiry CDB - { - padapter->ide.ide.ide[6] = pdev->byte6; - padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY; - break; - } - - case SCSIOP_TEST_UNIT_READY: // test unit ready CDB - SCpnt->result = DID_OK << 16; - done (SCpnt); - return 0; - - case SCSIOP_READ_CAPACITY: // read capctiy CDB - { - PREAD_CAPACITY_DATA pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer; - - pdata->blksiz = 0x20000; - XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks); - SCpnt->result = DID_OK << 16; - done (SCpnt); - return 0; - } - - case SCSIOP_VERIFY: // verify CDB - *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]); - padapter->ide.ide.ide[6] |= pdev->byte6; - padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8)); - padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY; - break; - - case SCSIOP_READ: // read10 CDB - padapter->startSector = XSCSI2LONG (&cdb[2]); - padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8); - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE; - break; - - case SCSIOP_READ6: // read6 CDB - padapter->startSector = SCSI2LONG (&cdb[1]); - padapter->sectorCount = cdb[4]; - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE; - break; - - case SCSIOP_WRITE: // write10 CDB - padapter->startSector = XSCSI2LONG (&cdb[2]); - padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8); - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE; - break; - case SCSIOP_WRITE6: // write6 CDB - padapter->startSector = SCSI2LONG (&cdb[1]); - padapter->sectorCount = cdb[4]; - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE; - break; - - default: - DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb)); - SCpnt->result = DID_ERROR << 16; - done (SCpnt); - return 0; - } - - padapter->SCpnt = SCpnt; // Save this command data - - rc = IdeCmd (padapter); - if ( rc ) - { - padapter->expectingIRQ = 0; - DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd)); - SCpnt->result = DID_ERROR << 16; - done (SCpnt); - return 0; - } - DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd)); - return 0; - } - -/*************************************************************************** - * Name: ReadChipMemory - * - * Description: Read information from controller memory. - * - * Parameters: psetup - Pointer to memory image of setup information. - * base - base address of memory. - * length - lenght of data space in bytes. - * port - I/O address of data port. - * - * Returns: Nothing. - * - **************************************************************************/ -static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port) - { - USHORT z, zz; - UCHAR *pd = (UCHAR *)pdata; - outb_p (SEL_NONE, port + REG_SEL_FAIL); // setup data port - zz = 0; - while ( zz < length ) - { - outw_p (base, port + REG_ADDRESS); // setup address - - for ( z = 0; z < 8; z++ ) - { - if ( (zz + z) < length ) - *pd++ = inb_p (port + z); // read data byte - } - zz += 8; - base += 8; - } - } -/**************************************************************** - * Name: Psi240i_Detect - * - * Description: Detect and initialize our boards. - * - * Parameters: tpnt - Pointer to SCSI host template structure. - * - * Returns: Number of adapters found. - * - ****************************************************************/ -static int Psi240i_Detect (struct scsi_host_template *tpnt) - { - int board; - int count = 0; - int unit; - int z; - USHORT port, port_range = 16; - CHIP_CONFIG_N chipConfig; - CHIP_DEVICE_N chipDevice[8]; - struct Scsi_Host *pshost; - - for ( board = 0; board < MAXBOARDS; board++ ) // scan for I/O ports - { - pshost = NULL; - port = portAddr[board]; // get base address to test - if ( !request_region (port, port_range, "psi240i") ) - continue; - if ( inb_p (port + REG_FAIL) != CHIP_ID ) // do the first test for likley hood that it is us - goto host_init_failure; - outb_p (SEL_NONE, port + REG_SEL_FAIL); // setup EEPROM/RAM access - outw (0, port + REG_ADDRESS); // setup EEPROM address zero - if ( inb_p (port) != 0x55 ) // test 1st byte - goto host_init_failure; // nope - if ( inb_p (port + 1) != 0xAA ) // test 2nd byte - goto host_init_failure; // nope - - // at this point our board is found and can be accessed. Now we need to initialize - // our informatation and register with the kernel. - - - ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port); - ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port); - ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port); - - if ( !chipConfig.numDrives ) // if no devices on this board - goto host_init_failure; - - pshost = scsi_register (tpnt, sizeof(ADAPTER240I)); - if(pshost == NULL) - goto host_init_failure; - - PsiHost[chipConfig.irq - 10] = pshost; - pshost->unique_id = port; - pshost->io_port = port; - pshost->n_io_port = 16; /* Number of bytes of I/O space used */ - pshost->irq = chipConfig.irq; - - for ( z = 0; z < 11; z++ ) // build regester address array - HOSTDATA(pshost)->ports[z] = port + z; - HOSTDATA(pshost)->ports[11] = port + REG_FAIL; - HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT; - DEB (printk ("\nPorts =")); - DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]);); - - for ( z = 0; z < chipConfig.numDrives; ++z ) - { - unit = chipDevice[z].channel & 0x0F; - HOSTDATA(pshost)->device[unit].device = ChipSetup.setupDevice[unit].device; - HOSTDATA(pshost)->device[unit].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); - HOSTDATA(pshost)->device[unit].spigot = (UCHAR)(1 << (unit >> 1)); - HOSTDATA(pshost)->device[unit].sectors = ChipSetup.setupDevice[unit].sectors; - HOSTDATA(pshost)->device[unit].heads = ChipSetup.setupDevice[unit].heads; - HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders; - HOSTDATA(pshost)->device[unit].blocks = ChipSetup.setupDevice[unit].blocks; - DEB (printk ("\nHOSTDATA->device = %X", HOSTDATA(pshost)->device[unit].device)); - DEB (printk ("\n byte6 = %X", HOSTDATA(pshost)->device[unit].byte6)); - DEB (printk ("\n spigot = %X", HOSTDATA(pshost)->device[unit].spigot)); - DEB (printk ("\n sectors = %X", HOSTDATA(pshost)->device[unit].sectors)); - DEB (printk ("\n heads = %X", HOSTDATA(pshost)->device[unit].heads)); - DEB (printk ("\n cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders)); - DEB (printk ("\n blocks = %lX", HOSTDATA(pshost)->device[unit].blocks)); - } - - if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) - { - printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x IRQ = %d\n", port, chipConfig.irq); - printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n"); - count++; - continue; - } - - printk ("Unable to allocate IRQ for PSI-240I controller.\n"); - -host_init_failure: - - release_region (port, port_range); - if (pshost) - scsi_unregister (pshost); - - } - return count; - } - -static int Psi240i_Release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -/**************************************************************** - * Name: Psi240i_BiosParam - * - * Description: Process the biosparam request from the SCSI manager to - * return C/H/S data. - * - * Parameters: disk - Pointer to SCSI disk structure. - * dev - Major/minor number from kernel. - * geom - Pointer to integer array to place geometry data. - * - * Returns: zero. - * - ****************************************************************/ -static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev, - sector_t capacity, int geom[]) - { - POUR_DEVICE pdev; - - pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]); - - geom[0] = pdev->heads; - geom[1] = pdev->sectors; - geom[2] = pdev->cylinders; - return 0; - } - -MODULE_LICENSE("GPL"); - -static struct scsi_host_template driver_template = { - .proc_name = "psi240i", - .name = "PSI-240I EIDE Disk Controller", - .detect = Psi240i_Detect, - .release = Psi240i_Release, - .queuecommand = Psi240i_QueueCommand, - .bios_param = Psi240i_BiosParam, - .can_queue = 1, - .this_id = -1, - .sg_tablesize = SG_NONE, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" diff -puN drivers/scsi/psi240i.h~git-scsi-misc /dev/null --- a/drivers/scsi/psi240i.h +++ /dev/null @@ -1,315 +0,0 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux. - * - * Copyright (c) 1997 Perceptive Solutions, Inc. - * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * File Name: psi240i.h - * - * Description: Header file for the SCSI driver for the PSI240I - * EIDE interface card. - * - *-M*************************************************************************/ -#ifndef _PSI240I_H -#define _PSI240I_H - -#include - -#ifndef PSI_EIDE_SCSIOP -#define PSI_EIDE_SCSIOP 1 - -/************************************************/ -/* Some defines that we like */ -/************************************************/ -#define CHAR char -#define UCHAR unsigned char -#define SHORT short -#define USHORT unsigned short -#define BOOL unsigned short -#define LONG long -#define ULONG unsigned long -#define VOID void - -/************************************************/ -/* Timeout konstants */ -/************************************************/ -#define TIMEOUT_READY 10 // 100 mSec -#define TIMEOUT_DRQ 40 // 400 mSec - -/************************************************/ -/* Misc. macros */ -/************************************************/ -#define ANY2SCSI(up, p) \ -((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \ -((UCHAR *)up)[1] = ((ULONG)(p)); - -#define SCSI2LONG(up) \ -( (((long)*(((UCHAR *)up))) << 16) \ -+ (((long)(((UCHAR *)up)[1])) << 8) \ -+ ((long)(((UCHAR *)up)[2])) ) - -#define XANY2SCSI(up, p) \ -((UCHAR *)up)[0] = ((long)(p)) >> 24; \ -((UCHAR *)up)[1] = ((long)(p)) >> 16; \ -((UCHAR *)up)[2] = ((long)(p)) >> 8; \ -((UCHAR *)up)[3] = ((long)(p)); - -#define XSCSI2LONG(up) \ -( (((long)(((UCHAR *)up)[0])) << 24) \ -+ (((long)(((UCHAR *)up)[1])) << 16) \ -+ (((long)(((UCHAR *)up)[2])) << 8) \ -+ ((long)(((UCHAR *)up)[3])) ) - -/************************************************/ -/* SCSI CDB operation codes */ -/************************************************/ -#define SCSIOP_TEST_UNIT_READY 0x00 -#define SCSIOP_REZERO_UNIT 0x01 -#define SCSIOP_REWIND 0x01 -#define SCSIOP_REQUEST_BLOCK_ADDR 0x02 -#define SCSIOP_REQUEST_SENSE 0x03 -#define SCSIOP_FORMAT_UNIT 0x04 -#define SCSIOP_READ_BLOCK_LIMITS 0x05 -#define SCSIOP_REASSIGN_BLOCKS 0x07 -#define SCSIOP_READ6 0x08 -#define SCSIOP_RECEIVE 0x08 -#define SCSIOP_WRITE6 0x0A -#define SCSIOP_PRINT 0x0A -#define SCSIOP_SEND 0x0A -#define SCSIOP_SEEK6 0x0B -#define SCSIOP_TRACK_SELECT 0x0B -#define SCSIOP_SLEW_PRINT 0x0B -#define SCSIOP_SEEK_BLOCK 0x0C -#define SCSIOP_PARTITION 0x0D -#define SCSIOP_READ_REVERSE 0x0F -#define SCSIOP_WRITE_FILEMARKS 0x10 -#define SCSIOP_FLUSH_BUFFER 0x10 -#define SCSIOP_SPACE 0x11 -#define SCSIOP_INQUIRY 0x12 -#define SCSIOP_VERIFY6 0x13 -#define SCSIOP_RECOVER_BUF_DATA 0x14 -#define SCSIOP_MODE_SELECT 0x15 -#define SCSIOP_RESERVE_UNIT 0x16 -#define SCSIOP_RELEASE_UNIT 0x17 -#define SCSIOP_COPY 0x18 -#define SCSIOP_ERASE 0x19 -#define SCSIOP_MODE_SENSE 0x1A -#define SCSIOP_START_STOP_UNIT 0x1B -#define SCSIOP_STOP_PRINT 0x1B -#define SCSIOP_LOAD_UNLOAD 0x1B -#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C -#define SCSIOP_SEND_DIAGNOSTIC 0x1D -#define SCSIOP_MEDIUM_REMOVAL 0x1E -#define SCSIOP_READ_CAPACITY 0x25 -#define SCSIOP_READ 0x28 -#define SCSIOP_WRITE 0x2A -#define SCSIOP_SEEK 0x2B -#define SCSIOP_LOCATE 0x2B -#define SCSIOP_WRITE_VERIFY 0x2E -#define SCSIOP_VERIFY 0x2F -#define SCSIOP_SEARCH_DATA_HIGH 0x30 -#define SCSIOP_SEARCH_DATA_EQUAL 0x31 -#define SCSIOP_SEARCH_DATA_LOW 0x32 -#define SCSIOP_SET_LIMITS 0x33 -#define SCSIOP_READ_POSITION 0x34 -#define SCSIOP_SYNCHRONIZE_CACHE 0x35 -#define SCSIOP_COMPARE 0x39 -#define SCSIOP_COPY_COMPARE 0x3A -#define SCSIOP_WRITE_DATA_BUFF 0x3B -#define SCSIOP_READ_DATA_BUFF 0x3C -#define SCSIOP_CHANGE_DEFINITION 0x40 -#define SCSIOP_READ_SUB_CHANNEL 0x42 -#define SCSIOP_READ_TOC 0x43 -#define SCSIOP_READ_HEADER 0x44 -#define SCSIOP_PLAY_AUDIO 0x45 -#define SCSIOP_PLAY_AUDIO_MSF 0x47 -#define SCSIOP_PLAY_TRACK_INDEX 0x48 -#define SCSIOP_PLAY_TRACK_RELATIVE 0x49 -#define SCSIOP_PAUSE_RESUME 0x4B -#define SCSIOP_LOG_SELECT 0x4C -#define SCSIOP_LOG_SENSE 0x4D -#define SCSIOP_MODE_SELECT10 0x55 -#define SCSIOP_MODE_SENSE10 0x5A -#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6 -#define SCSIOP_MECHANISM_STATUS 0xBD -#define SCSIOP_READ_CD 0xBE - -// IDE command definitions -#define IDE_COMMAND_ATAPI_RESET 0x08 -#define IDE_COMMAND_READ 0x20 -#define IDE_COMMAND_WRITE 0x30 -#define IDE_COMMAND_RECALIBRATE 0x10 -#define IDE_COMMAND_SEEK 0x70 -#define IDE_COMMAND_SET_PARAMETERS 0x91 -#define IDE_COMMAND_VERIFY 0x40 -#define IDE_COMMAND_ATAPI_PACKET 0xA0 -#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1 -#define IDE_CMD_READ_MULTIPLE 0xC4 -#define IDE_CMD_WRITE_MULTIPLE 0xC5 -#define IDE_CMD_SET_MULTIPLE 0xC6 -#define IDE_COMMAND_WRITE_DMA 0xCA -#define IDE_COMMAND_READ_DMA 0xC8 -#define IDE_COMMAND_IDENTIFY 0xEC - -// IDE status definitions -#define IDE_STATUS_ERROR 0x01 -#define IDE_STATUS_INDEX 0x02 -#define IDE_STATUS_CORRECTED_ERROR 0x04 -#define IDE_STATUS_DRQ 0x08 -#define IDE_STATUS_DSC 0x10 -#define IDE_STATUS_WRITE_FAULT 0x20 -#define IDE_STATUS_DRDY 0x40 -#define IDE_STATUS_BUSY 0x80 - -// IDE error definitions -#define IDE_ERROR_AMNF 0x01 -#define IDE_ERROR_TKONF 0x02 -#define IDE_ERROR_ABRT 0x04 -#define IDE_ERROR_MCR 0x08 -#define IDE_ERROR_IDFN 0x10 -#define IDE_ERROR_MC 0x20 -#define IDE_ERROR_UNC 0x40 -#define IDE_ERROR_BBK 0x80 - -// IDE interface structure -typedef struct _IDE_STRUCT - { - union - { - UCHAR ide[9]; - struct - { - USHORT data; - UCHAR sectors; - UCHAR lba[4]; - UCHAR cmd; - UCHAR spigot; - } ides; - } ide; - } IDE_STRUCT; - -// SCSI read capacity structure -typedef struct _READ_CAPACITY_DATA - { - ULONG blks; /* total blocks (converted to little endian) */ - ULONG blksiz; /* size of each (converted to little endian) */ - } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA; - -// SCSI inquiry data -#ifndef HOSTS_C - -typedef struct _INQUIRYDATA - { - UCHAR DeviceType :5; - UCHAR DeviceTypeQualifier :3; - UCHAR DeviceTypeModifier :7; - UCHAR RemovableMedia :1; - UCHAR Versions; - UCHAR ResponseDataFormat; - UCHAR AdditionalLength; - UCHAR Reserved[2]; - UCHAR SoftReset :1; - UCHAR CommandQueue :1; - UCHAR Reserved2 :1; - UCHAR LinkedCommands :1; - UCHAR Synchronous :1; - UCHAR Wide16Bit :1; - UCHAR Wide32Bit :1; - UCHAR RelativeAddressing :1; - UCHAR VendorId[8]; - UCHAR ProductId[16]; - UCHAR ProductRevisionLevel[4]; - UCHAR VendorSpecific[20]; - UCHAR Reserved3[40]; - } INQUIRYDATA, *PINQUIRYDATA; -#endif - -// IDE IDENTIFY data -typedef struct _IDENTIFY_DATA - { - USHORT GeneralConfiguration; // 00 - USHORT NumberOfCylinders; // 02 - USHORT Reserved1; // 04 - USHORT NumberOfHeads; // 06 - USHORT UnformattedBytesPerTrack; // 08 - USHORT UnformattedBytesPerSector; // 0A - USHORT SectorsPerTrack; // 0C - USHORT VendorUnique1[3]; // 0E - USHORT SerialNumber[10]; // 14 - USHORT BufferType; // 28 - USHORT BufferSectorSize; // 2A - USHORT NumberOfEccBytes; // 2C - USHORT FirmwareRevision[4]; // 2E - USHORT ModelNumber[20]; // 36 - UCHAR MaximumBlockTransfer; // 5E - UCHAR VendorUnique2; // 5F - USHORT DoubleWordIo; // 60 - USHORT Capabilities; // 62 - USHORT Reserved2; // 64 - UCHAR VendorUnique3; // 66 - UCHAR PioCycleTimingMode; // 67 - UCHAR VendorUnique4; // 68 - UCHAR DmaCycleTimingMode; // 69 - USHORT TranslationFieldsValid:1; // 6A - USHORT Reserved3:15; - USHORT NumberOfCurrentCylinders; // 6C - USHORT NumberOfCurrentHeads; // 6E - USHORT CurrentSectorsPerTrack; // 70 - ULONG CurrentSectorCapacity; // 72 - USHORT Reserved4[197]; // 76 - } IDENTIFY_DATA, *PIDENTIFY_DATA; - -// Identify data without the Reserved4. -typedef struct _IDENTIFY_DATA2 { - USHORT GeneralConfiguration; // 00 - USHORT NumberOfCylinders; // 02 - USHORT Reserved1; // 04 - USHORT NumberOfHeads; // 06 - USHORT UnformattedBytesPerTrack; // 08 - USHORT UnformattedBytesPerSector; // 0A - USHORT SectorsPerTrack; // 0C - USHORT VendorUnique1[3]; // 0E - USHORT SerialNumber[10]; // 14 - USHORT BufferType; // 28 - USHORT BufferSectorSize; // 2A - USHORT NumberOfEccBytes; // 2C - USHORT FirmwareRevision[4]; // 2E - USHORT ModelNumber[20]; // 36 - UCHAR MaximumBlockTransfer; // 5E - UCHAR VendorUnique2; // 5F - USHORT DoubleWordIo; // 60 - USHORT Capabilities; // 62 - USHORT Reserved2; // 64 - UCHAR VendorUnique3; // 66 - UCHAR PioCycleTimingMode; // 67 - UCHAR VendorUnique4; // 68 - UCHAR DmaCycleTimingMode; // 69 - USHORT TranslationFieldsValid:1; // 6A - USHORT Reserved3:15; - USHORT NumberOfCurrentCylinders; // 6C - USHORT NumberOfCurrentHeads; // 6E - USHORT CurrentSectorsPerTrack; // 70 - ULONG CurrentSectorCapacity; // 72 - } IDENTIFY_DATA2, *PIDENTIFY_DATA2; - -#endif // PSI_EIDE_SCSIOP - -// function prototypes -int Psi240i_Command(struct scsi_cmnd *SCpnt); -int Psi240i_Abort(struct scsi_cmnd *SCpnt); -int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags); -#endif diff -puN drivers/scsi/psi_chip.h~git-scsi-misc /dev/null --- a/drivers/scsi/psi_chip.h +++ /dev/null @@ -1,195 +0,0 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux. - * - * Copyright (c) 1997 Perceptive Solutions, Inc. - * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * File Name: psi_chip.h - * - * Description: This file contains the interface defines and - * error codes. - * - *-M*************************************************************************/ -#ifndef PSI_CHIP -#define PSI_CHIP - -/************************************************/ -/* Misc konstants */ -/************************************************/ -#define CHIP_MAXDRIVES 8 - -/************************************************/ -/* Chip I/O addresses */ -/************************************************/ -#define CHIP_ADRS_0 0x0130 -#define CHIP_ADRS_1 0x0150 -#define CHIP_ADRS_2 0x0190 -#define CHIP_ADRS_3 0x0210 -#define CHIP_ADRS_4 0x0230 -#define CHIP_ADRS_5 0x0250 - -/************************************************/ -/* EEPROM locations */ -/************************************************/ -#define CHIP_EEPROM_BIOS 0x0000 // BIOS base address -#define CHIP_EEPROM_DATA 0x2000 // SETUP data base address -#define CHIP_EEPROM_FACTORY 0x2400 // FACTORY data base address -#define CHIP_EEPROM_SETUP 0x3000 // SETUP PROGRAM base address - -#define CHIP_EEPROM_SIZE 32768U // size of the entire EEPROM -#define CHIP_EEPROM_BIOS_SIZE 8192 // size of the BIOS in bytes -#define CHIP_EEPROM_DATA_SIZE 4096 // size of factory, setup, log data block in bytes -#define CHIP_EEPROM_SETUP_SIZE 20480U // size of the setup program in bytes - -/************************************************/ -/* Chip Interrupts */ -/************************************************/ -#define CHIP_IRQ_10 0x72 -#define CHIP_IRQ_11 0x73 -#define CHIP_IRQ_12 0x74 - -/************************************************/ -/* Chip Setup addresses */ -/************************************************/ -#define CHIP_SETUP_BASE 0x0000C000L - -/************************************************/ -/* Chip Register address offsets */ -/************************************************/ -#define REG_DATA 0x00 -#define REG_ERROR 0x01 -#define REG_SECTOR_COUNT 0x02 -#define REG_LBA_0 0x03 -#define REG_LBA_8 0x04 -#define REG_LBA_16 0x05 -#define REG_LBA_24 0x06 -#define REG_STAT_CMD 0x07 -#define REG_SEL_FAIL 0x08 -#define REG_IRQ_STATUS 0x09 -#define REG_ADDRESS 0x0A -#define REG_FAIL 0x0C -#define REG_ALT_STAT 0x0E -#define REG_DRIVE_ADRS 0x0F - -/************************************************/ -/* Chip RAM locations */ -/************************************************/ -#define CHIP_DEVICE 0x8000 -#define CHIP_DEVICE_0 0x8000 -#define CHIP_DEVICE_1 0x8008 -#define CHIP_DEVICE_2 0x8010 -#define CHIP_DEVICE_3 0x8018 -#define CHIP_DEVICE_4 0x8020 -#define CHIP_DEVICE_5 0x8028 -#define CHIP_DEVICE_6 0x8030 -#define CHIP_DEVICE_7 0x8038 -typedef struct - { - UCHAR channel; // channel of this device (0-8). - UCHAR spt; // Sectors Per Track. - ULONG spc; // Sectors Per Cylinder. - } CHIP_DEVICE_N; - -#define CHIP_CONFIG 0x8100 // address of boards configuration. -typedef struct - { - UCHAR irq; // interrupt request channel number - UCHAR numDrives; // Number of accessible drives - UCHAR fastFormat; // Boolean for fast format enable - } CHIP_CONFIG_N; - -#define CHIP_MAP 0x8108 // eight byte device type map. - - -#define CHIP_RAID 0x8120 // array of RAID signature structures and LBA -#define CHIP_RAID_1 0x8120 -#define CHIP_RAID_2 0x8130 -#define CHIP_RAID_3 0x8140 -#define CHIP_RAID_4 0x8150 - -/************************************************/ -/* Chip Register Masks */ -/************************************************/ -#define CHIP_ID 0x7B -#define SEL_RAM 0x8000 -#define MASK_FAIL 0x80 - -/************************************************/ -/* Chip cable select bits */ -/************************************************/ -#define SECTORSXFER 8 - -/************************************************/ -/* Chip cable select bits */ -/************************************************/ -#define SEL_NONE 0x00 -#define SEL_1 0x01 -#define SEL_2 0x02 -#define SEL_3 0x04 -#define SEL_4 0x08 - -/************************************************/ -/* Programmable Interrupt Controller*/ -/************************************************/ -#define PIC1 0x20 // first 8259 base port address -#define PIC2 0xA0 // second 8259 base port address -#define INT_OCW1 1 // Operation Control Word 1: IRQ mask -#define EOI 0x20 // non-specific end-of-interrupt - -/************************************************/ -/* Device/Geometry controls */ -/************************************************/ -#define GEOMETRY_NONE 0x0 // No device -#define GEOMETRY_AUTO 0x1 // Geometry set automatically -#define GEOMETRY_USER 0x2 // User supplied geometry - -#define DEVICE_NONE 0x0 // No device present -#define DEVICE_INACTIVE 0x1 // device present but not registered active -#define DEVICE_ATAPI 0x2 // ATAPI device (CD_ROM, Tape, Etc...) -#define DEVICE_DASD_NONLBA 0x3 // Non LBA incompatible device -#define DEVICE_DASD_LBA 0x4 // LBA compatible device - -/************************************************/ -/* Setup Structure Definitions */ -/************************************************/ -typedef struct // device setup parameters - { - UCHAR geometryControl; // geometry control flags - UCHAR device; // device code - USHORT sectors; // number of sectors per track - USHORT heads; // number of heads - USHORT cylinders; // number of cylinders for this device - ULONG blocks; // number of blocks on device - USHORT spare1; - USHORT spare2; - } SETUP_DEVICE, *PSETUP_DEVICE; - -typedef struct // master setup structure - { - USHORT startupDelay; - USHORT promptBIOS; - USHORT fastFormat; - USHORT spare2; - USHORT spare3; - USHORT spare4; - USHORT spare5; - USHORT spare6; - SETUP_DEVICE setupDevice[8]; - } SETUP, *PSETUP; - -#endif - diff -puN drivers/scsi/qla2xxx/qla_attr.c~git-scsi-misc drivers/scsi/qla2xxx/qla_attr.c --- a/drivers/scsi/qla2xxx/qla_attr.c~git-scsi-misc +++ a/drivers/scsi/qla2xxx/qla_attr.c @@ -1124,7 +1124,7 @@ qla24xx_vport_delete(struct fc_vport *fc down(&ha->vport_sem); ha->cur_vport_count--; - clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map); + clear_bit(vha->vp_idx, ha->vp_idx_map); up(&ha->vport_sem); kfree(vha->node_name); diff -puN drivers/scsi/qla2xxx/qla_def.h~git-scsi-misc drivers/scsi/qla2xxx/qla_def.h --- a/drivers/scsi/qla2xxx/qla_def.h~git-scsi-misc +++ a/drivers/scsi/qla2xxx/qla_def.h @@ -2116,14 +2116,6 @@ struct qla_msix_entry { #define WATCH_INTERVAL 1 /* number of seconds */ -/* NPIV */ -#define MAX_MULTI_ID_LOOP 126 -#define MAX_MULTI_ID_FABRIC 64 -#define MAX_NUM_VPORT_LOOP (MAX_MULTI_ID_LOOP - 1) -#define MAX_NUM_VPORT_FABRIC (MAX_MULTI_ID_FABRIC - 1) -#define MAX_NUM_VHBA_LOOP (MAX_MULTI_ID_LOOP - 1) -#define MAX_NUM_VHBA_FABRIC (MAX_MULTI_ID_FABRIC - 1) - /* * Linux Host Adapter structure */ @@ -2507,7 +2499,7 @@ typedef struct scsi_qla_host { struct list_head vp_list; /* list of VP */ struct fc_vport *fc_vport; /* holds fc_vport * for each vport */ - uint8_t vp_idx_map[16]; + unsigned long vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / sizeof(unsigned long)]; uint16_t num_vhosts; /* number of vports created */ uint16_t num_vsans; /* number of vsan created */ uint16_t vp_idx; /* vport ID */ diff -puN drivers/scsi/qla2xxx/qla_fw.h~git-scsi-misc drivers/scsi/qla2xxx/qla_fw.h --- a/drivers/scsi/qla2xxx/qla_fw.h~git-scsi-misc +++ a/drivers/scsi/qla2xxx/qla_fw.h @@ -954,7 +954,15 @@ struct device_reg_24xx { /* MID Support ***************************************************************/ -#define MAX_MID_VPS 125 +#define MIN_MULTI_ID_FABRIC 64 /* Must be power-of-2. */ +#define MAX_MULTI_ID_FABRIC 256 /* ... */ + +#define for_each_mapped_vp_idx(_ha, _idx) \ + for (_idx = find_next_bit((_ha)->vp_idx_map, \ + (_ha)->max_npiv_vports + 1, 1); \ + _idx <= (_ha)->max_npiv_vports; \ + _idx = find_next_bit((_ha)->vp_idx_map, \ + (_ha)->max_npiv_vports + 1, _idx + 1)) \ struct mid_conf_entry_24xx { uint16_t reserved_1; @@ -982,7 +990,7 @@ struct mid_init_cb_24xx { uint16_t count; uint16_t options; - struct mid_conf_entry_24xx entries[MAX_MID_VPS]; + struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC]; }; @@ -1002,10 +1010,6 @@ struct mid_db_entry_24xx { uint8_t reserved_1; }; -struct mid_db_24xx { - struct mid_db_entry_24xx entries[MAX_MID_VPS]; -}; - /* * Virtual Fabric ID type definition. */ diff -puN drivers/scsi/qla2xxx/qla_init.c~git-scsi-misc drivers/scsi/qla2xxx/qla_init.c --- a/drivers/scsi/qla2xxx/qla_init.c~git-scsi-misc +++ a/drivers/scsi/qla2xxx/qla_init.c @@ -922,9 +922,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) ha->flags.npiv_supported = 1; if ((!ha->max_npiv_vports) || ((ha->max_npiv_vports + 1) % - MAX_MULTI_ID_FABRIC)) + MIN_MULTI_ID_FABRIC)) ha->max_npiv_vports = - MAX_NUM_VPORT_FABRIC; + MIN_MULTI_ID_FABRIC - 1; } if (ql2xallocfwdump) @@ -1162,7 +1162,8 @@ qla2x00_init_rings(scsi_qla_host_t *ha) DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); - mid_init_cb->count = ha->max_npiv_vports; + mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports); + mid_init_cb->options = __constant_cpu_to_le16(BIT_1); rval = qla2x00_init_firmware(ha, ha->init_cb_size); if (rval) { @@ -2566,14 +2567,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_ho /* Bypass virtual ports of the same host. */ if (pha->num_vhosts) { - vp_index = find_next_bit( - (unsigned long *)pha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, 1); - - for (;vp_index <= MAX_MULTI_ID_FABRIC; - vp_index = find_next_bit( - (unsigned long *)pha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) { + for_each_mapped_vp_idx(pha, vp_index) { empty_vp_index = 1; found_vp = 0; list_for_each_entry(vha, &pha->vp_list, @@ -2592,7 +2586,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_ho new_fcport->d_id.b24 == vha->d_id.b24) break; } - if (vp_index <= MAX_MULTI_ID_FABRIC) + + if (vp_index <= pha->max_npiv_vports) continue; } diff -puN drivers/scsi/qla2xxx/qla_isr.c~git-scsi-misc drivers/scsi/qla2xxx/qla_isr.c --- a/drivers/scsi/qla2xxx/qla_isr.c~git-scsi-misc +++ a/drivers/scsi/qla2xxx/qla_isr.c @@ -347,10 +347,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, break; case MBA_SYSTEM_ERR: /* System Error */ - mb[1] = RD_MAILBOX_REG(ha, reg, 1); - mb[2] = RD_MAILBOX_REG(ha, reg, 2); - mb[3] = RD_MAILBOX_REG(ha, reg, 3); - qla_printk(KERN_INFO, ha, "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n", mb[1], mb[2], mb[3]); @@ -579,12 +575,15 @@ qla2x00_async_event(scsi_qla_host_t *ha, /* Check if the Vport has issued a SCR */ if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags)) break; + /* Only handle SCNs for our Vport index. */ + if (ha->flags.npiv_supported && ha->vp_idx != mb[3]) + break; DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", ha->host_no)); DEBUG(printk(KERN_INFO - "scsi(%ld): RSCN database changed -- %04x %04x.\n", - ha->host_no, mb[1], mb[2])); + "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n", + ha->host_no, mb[1], mb[2], mb[3])); rscn_entry = (mb[1] << 16) | mb[2]; host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) | diff -puN drivers/scsi/qla2xxx/qla_mbx.c~git-scsi-misc drivers/scsi/qla2xxx/qla_mbx.c --- a/drivers/scsi/qla2xxx/qla_mbx.c~git-scsi-misc +++ a/drivers/scsi/qla2xxx/qla_mbx.c @@ -905,7 +905,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t * mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID; mcp->mb[9] = ha->vp_idx; - mcp->out_mb = MBX_0; + mcp->out_mb = MBX_9|MBX_0; mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->tov = 30; mcp->flags = 0; @@ -2873,7 +2873,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__, ha->host_no, vp_index)); - if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP) + if (vp_index == 0 || vp_index >= ha->max_npiv_vports) return QLA_PARAMETER_ERROR; vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma); diff -puN drivers/scsi/qla2xxx/qla_mid.c~git-scsi-misc drivers/scsi/qla2xxx/qla_mid.c --- a/drivers/scsi/qla2xxx/qla_mid.c~git-scsi-misc +++ a/drivers/scsi/qla2xxx/qla_mid.c @@ -47,16 +47,15 @@ qla24xx_allocate_vp_id(scsi_qla_host_t * /* Find an empty slot and assign an vp_id */ down(&ha->vport_sem); - vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC); - if (vp_id > MAX_MULTI_ID_FABRIC) { - DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n", - vp_id)); + vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1); + if (vp_id > ha->max_npiv_vports) { + DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n", + vp_id, ha->max_npiv_vports)); up(&ha->vport_sem); return vp_id; } - set_bit(vp_id, (unsigned long *)ha->vp_idx_map); + set_bit(vp_id, ha->vp_idx_map); ha->num_vhosts++; vha->vp_idx = vp_id; list_add_tail(&vha->vp_list, &ha->vp_list); @@ -73,7 +72,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t down(&ha->vport_sem); vp_id = vha->vp_idx; ha->num_vhosts--; - clear_bit(vp_id, (unsigned long *)ha->vp_idx_map); + clear_bit(vp_id, ha->vp_idx_map); list_del(&vha->vp_list); up(&ha->vport_sem); } @@ -216,11 +215,7 @@ qla2x00_alert_all_vps(scsi_qla_host_t *h if (ha->parent) return; - i = find_next_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, 1); - for (;i <= MAX_MULTI_ID_FABRIC; - i = find_next_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, i + 1)) { + for_each_mapped_vp_idx(ha, i) { vp_idx_matched = 0; list_for_each_entry(vha, &ha->vp_list, vp_list) { @@ -311,11 +306,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t * clear_bit(VP_DPC_NEEDED, &ha->dpc_flags); - i = find_next_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, 1); - for (;i <= MAX_MULTI_ID_FABRIC; - i = find_next_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, i + 1)) { + for_each_mapped_vp_idx(ha, i) { vp_idx_matched = 0; list_for_each_entry(vha, &ha->vp_list, vp_list) { @@ -356,9 +347,9 @@ qla24xx_vport_create_req_sanity_check(st /* Check up max-npiv-supports */ if (ha->num_vhosts > ha->max_npiv_vports) { - DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than " - "max_npv_vports %d.\n", ha->host_no, - (uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports)); + DEBUG15(printk("scsi(%ld): num_vhosts %ud is bigger than " + "max_npv_vports %ud.\n", ha->host_no, + ha->num_vhosts, ha->max_npiv_vports)); return VPCERR_UNSUPPORTED; } return 0; @@ -450,7 +441,7 @@ qla24xx_create_vhost(struct fc_vport *fc num_hosts++; down(&ha->vport_sem); - set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map); + set_bit(vha->vp_idx, ha->vp_idx_map); ha->cur_vport_count++; up(&ha->vport_sem); diff -puN drivers/scsi/qla2xxx/qla_version.h~git-scsi-misc drivers/scsi/qla2xxx/qla_version.h --- a/drivers/scsi/qla2xxx/qla_version.h~git-scsi-misc +++ a/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k5" +#define QLA2XXX_VERSION "8.02.00-k6" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 diff -puN drivers/scsi/qlogicpti.c~git-scsi-misc drivers/scsi/qlogicpti.c --- a/drivers/scsi/qlogicpti.c~git-scsi-misc +++ a/drivers/scsi/qlogicpti.c @@ -871,11 +871,12 @@ static inline int load_cmd(struct scsi_c struct scatterlist *sg, *s; int i, n; - if (Cmnd->use_sg) { + if (scsi_bufflen(Cmnd)) { int sg_count; - sg = (struct scatterlist *) Cmnd->request_buffer; - sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction); + sg = scsi_sglist(Cmnd); + sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd), + Cmnd->sc_data_direction); ds = cmd->dataseg; cmd->segment_cnt = sg_count; @@ -914,16 +915,6 @@ static inline int load_cmd(struct scsi_c } sg_count -= n; } - } else if (Cmnd->request_bufflen) { - Cmnd->SCp.ptr = (char *)(unsigned long) - sbus_map_single(qpti->sdev, - Cmnd->request_buffer, - Cmnd->request_bufflen, - Cmnd->sc_data_direction); - - cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr); - cmd->dataseg[0].d_count = Cmnd->request_bufflen; - cmd->segment_cnt = 1; } else { cmd->dataseg[0].d_base = 0; cmd->dataseg[0].d_count = 0; @@ -1159,17 +1150,11 @@ static struct scsi_cmnd *qlogicpti_intr_ else Cmnd->result = DID_ERROR << 16; - if (Cmnd->use_sg) { + if (scsi_bufflen(Cmnd)) sbus_unmap_sg(qpti->sdev, - (struct scatterlist *)Cmnd->request_buffer, - Cmnd->use_sg, + scsi_sglist(Cmnd), scsi_sg_count(Cmnd), Cmnd->sc_data_direction); - } else if (Cmnd->request_bufflen) { - sbus_unmap_single(qpti->sdev, - (__u32)((unsigned long)Cmnd->SCp.ptr), - Cmnd->request_bufflen, - Cmnd->sc_data_direction); - } + qpti->cmd_count[Cmnd->device->id]--; sbus_writew(out_ptr, qpti->qregs + MBOX5); Cmnd->host_scribble = (unsigned char *) done_queue; diff -puN drivers/scsi/scsi.c~git-scsi-misc drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c~git-scsi-misc +++ a/drivers/scsi/scsi.c @@ -122,6 +122,11 @@ static const char *const scsi_device_typ "Automation/Drive ", }; +/** + * scsi_device_type - Return 17 char string indicating device type. + * @type: type number to look up + */ + const char * scsi_device_type(unsigned type) { if (type == 0x1e) @@ -156,6 +161,14 @@ static struct scsi_host_cmd_pool scsi_cm static DEFINE_MUTEX(host_cmd_pool_mutex); +/** + * __scsi_get_command - Allocate a struct scsi_cmnd + * @shost: host to transmit command + * @gfp_mask: allocation mask + * + * Description: allocate a struct scsi_cmd from host's slab, recycling from the + * host's free_list if necessary. + */ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) { struct scsi_cmnd *cmd; @@ -179,13 +192,10 @@ struct scsi_cmnd *__scsi_get_command(str } EXPORT_SYMBOL_GPL(__scsi_get_command); -/* - * Function: scsi_get_command() - * - * Purpose: Allocate and setup a scsi command block - * - * Arguments: dev - parent scsi device - * gfp_mask- allocator flags +/** + * scsi_get_command - Allocate and setup a scsi command block + * @dev: parent scsi device + * @gfp_mask: allocator flags * * Returns: The allocated scsi command structure. */ @@ -217,6 +227,12 @@ struct scsi_cmnd *scsi_get_command(struc } EXPORT_SYMBOL(scsi_get_command); +/** + * __scsi_put_command - Free a struct scsi_cmnd + * @shost: dev->host + * @cmd: Command to free + * @dev: parent scsi device + */ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, struct device *dev) { @@ -237,12 +253,9 @@ void __scsi_put_command(struct Scsi_Host } EXPORT_SYMBOL(__scsi_put_command); -/* - * Function: scsi_put_command() - * - * Purpose: Free a scsi command block - * - * Arguments: cmd - command block to free +/** + * scsi_put_command - Free a scsi command block + * @cmd: command block to free * * Returns: Nothing. * @@ -263,12 +276,13 @@ void scsi_put_command(struct scsi_cmnd * } EXPORT_SYMBOL(scsi_put_command); -/* - * Function: scsi_setup_command_freelist() - * - * Purpose: Setup the command freelist for a scsi host. +/** + * scsi_setup_command_freelist - Setup the command freelist for a scsi host. + * @shost: host to allocate the freelist for. * - * Arguments: shost - host to allocate the freelist for. + * Description: The command freelist protects against system-wide out of memory + * deadlock by preallocating one SCSI command structure for each host, so the + * system can always write to a swap file on a device associated with that host. * * Returns: Nothing. */ @@ -282,7 +296,7 @@ int scsi_setup_command_freelist(struct S /* * Select a command slab for this host and create it if not - * yet existant. + * yet existent. */ mutex_lock(&host_cmd_pool_mutex); pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool); @@ -318,12 +332,9 @@ int scsi_setup_command_freelist(struct S } -/* - * Function: scsi_destroy_command_freelist() - * - * Purpose: Release the command freelist for a scsi host. - * - * Arguments: shost - host that's freelist is going to be destroyed +/** + * scsi_destroy_command_freelist - Release the command freelist for a scsi host. + * @shost: host whose freelist is going to be destroyed */ void scsi_destroy_command_freelist(struct Scsi_Host *shost) { @@ -441,8 +452,12 @@ void scsi_log_completion(struct scsi_cmn } #endif -/* - * Assign a serial number to the request for error recovery +/** + * scsi_cmd_get_serial - Assign a serial number to a command + * @host: the scsi host + * @cmd: command to assign serial number to + * + * Description: a serial number identifies a request for error recovery * and debugging purposes. Protected by the Host_Lock of host. */ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd) @@ -452,14 +467,12 @@ static inline void scsi_cmd_get_serial(s cmd->serial_number = host->cmd_serial_number++; } -/* - * Function: scsi_dispatch_command - * - * Purpose: Dispatch a command to the low-level driver. - * - * Arguments: cmd - command block we are dispatching. +/** + * scsi_dispatch_command - Dispatch a command to the low-level driver. + * @cmd: command block we are dispatching. * - * Notes: + * Return: nonzero return request was rejected and device's queue needs to be + * plugged. */ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) { @@ -585,7 +598,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd * /** * scsi_req_abort_cmd -- Request command recovery for the specified command - * cmd: pointer to the SCSI command of interest + * @cmd: pointer to the SCSI command of interest * * This function requests that SCSI Core start recovery for the * command by deleting the timer and adding the command to the eh @@ -606,9 +619,9 @@ EXPORT_SYMBOL(scsi_req_abort_cmd); * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives * ownership back to SCSI Core -- i.e. the LLDD has finished with it. * - * This function is the mid-level's (SCSI Core) interrupt routine, which - * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues - * the command to the done queue for further processing. + * Description: This function is the mid-level's (SCSI Core) interrupt routine, + * which regains ownership of the SCSI command (de facto) from a LLDD, and + * enqueues the command to the done queue for further processing. * * This is the producer of the done queue who enqueues at the tail. * @@ -617,7 +630,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd); static void scsi_done(struct scsi_cmnd *cmd) { /* - * We don't have to worry about this one timing out any more. + * We don't have to worry about this one timing out anymore. * If we are unable to remove the timer, then the command * has already timed out. In which case, we have no choice but to * let the timeout function run, as we have no idea where in fact @@ -660,10 +673,11 @@ static struct scsi_driver *scsi_cmd_to_d return *(struct scsi_driver **)cmd->request->rq_disk->private_data; } -/* - * Function: scsi_finish_command +/** + * scsi_finish_command - cleanup and pass command back to upper layer + * @cmd: the command * - * Purpose: Pass command off to upper layer for finishing of I/O + * Description: Pass command off to upper layer for finishing of I/O * request, waking processes that are waiting on results, * etc. */ @@ -708,18 +722,14 @@ void scsi_finish_command(struct scsi_cmn } EXPORT_SYMBOL(scsi_finish_command); -/* - * Function: scsi_adjust_queue_depth() - * - * Purpose: Allow low level drivers to tell us to change the queue depth - * on a specific SCSI device - * - * Arguments: sdev - SCSI Device in question - * tagged - Do we use tagged queueing (non-0) or do we treat - * this device as an untagged device (0) - * tags - Number of tags allowed if tagged queueing enabled, - * or number of commands the low level driver can - * queue up in non-tagged mode (as per cmd_per_lun). +/** + * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth + * @sdev: SCSI Device in question + * @tagged: Do we use tagged queueing (non-0) or do we treat + * this device as an untagged device (0) + * @tags: Number of tags allowed if tagged queueing enabled, + * or number of commands the low level driver can + * queue up in non-tagged mode (as per cmd_per_lun). * * Returns: Nothing * @@ -742,8 +752,8 @@ void scsi_adjust_queue_depth(struct scsi spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - /* Check to see if the queue is managed by the block layer - * if it is, and we fail to adjust the depth, exit */ + /* Check to see if the queue is managed by the block layer. + * If it is, and we fail to adjust the depth, exit. */ if (blk_queue_tagged(sdev->request_queue) && blk_queue_resize_tags(sdev->request_queue, tags) != 0) goto out; @@ -772,20 +782,17 @@ void scsi_adjust_queue_depth(struct scsi } EXPORT_SYMBOL(scsi_adjust_queue_depth); -/* - * Function: scsi_track_queue_full() +/** + * scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth + * @sdev: SCSI Device in question + * @depth: Current number of outstanding SCSI commands on this device, + * not counting the one returned as QUEUE_FULL. * - * Purpose: This function will track successive QUEUE_FULL events on a + * Description: This function will track successive QUEUE_FULL events on a * specific SCSI device to determine if and when there is a * need to adjust the queue depth on the device. * - * Arguments: sdev - SCSI Device in question - * depth - Current number of outstanding SCSI commands on - * this device, not counting the one returned as - * QUEUE_FULL. - * - * Returns: 0 - No change needed - * >0 - Adjust queue depth to this new depth + * Returns: 0 - No change needed, >0 - Adjust queue depth to this new depth, * -1 - Drop back to untagged operation using host->cmd_per_lun * as the untagged command depth * @@ -824,10 +831,10 @@ int scsi_track_queue_full(struct scsi_de EXPORT_SYMBOL(scsi_track_queue_full); /** - * scsi_device_get - get an addition reference to a scsi_device + * scsi_device_get - get an additional reference to a scsi_device * @sdev: device to get a reference to * - * Gets a reference to the scsi_device and increments the use count + * Description: Gets a reference to the scsi_device and increments the use count * of the underlying LLDD module. You must hold host_lock of the * parent Scsi_Host or already have a reference when calling this. */ @@ -849,8 +856,8 @@ EXPORT_SYMBOL(scsi_device_get); * scsi_device_put - release a reference to a scsi_device * @sdev: device to release a reference on. * - * Release a reference to the scsi_device and decrements the use count - * of the underlying LLDD module. The device is freed once the last + * Description: Release a reference to the scsi_device and decrements the use + * count of the underlying LLDD module. The device is freed once the last * user vanishes. */ void scsi_device_put(struct scsi_device *sdev) @@ -867,7 +874,7 @@ void scsi_device_put(struct scsi_device } EXPORT_SYMBOL(scsi_device_put); -/* helper for shost_for_each_device, thus not documented */ +/* helper for shost_for_each_device, see that for documentation */ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, struct scsi_device *prev) { @@ -895,9 +902,11 @@ EXPORT_SYMBOL(__scsi_iterate_devices); /** * starget_for_each_device - helper to walk all devices of a target * @starget: target whose devices we want to iterate over. + * @data: Opaque passed to each function call. + * @fn: Function to call on each device * - * This traverses over each devices of @shost. The devices have - * a reference that must be released by scsi_host_put when breaking + * Description: This traverses over each device of @shost. The devices have + * a reference that must be released by scsi_device_put when breaking * out of the loop. */ void starget_for_each_device(struct scsi_target *starget, void * data, @@ -919,13 +928,13 @@ EXPORT_SYMBOL(starget_for_each_device); * @starget: SCSI target pointer * @lun: SCSI Logical Unit Number * - * Looks up the scsi_device with the specified @lun for a give - * @starget. The returned scsi_device does not have an additional + * Description: Looks up the scsi_device with the specified @lun for a given + * @starget. The returned scsi_device does not have an additional * reference. You must hold the host's host_lock over this call and * any access to the returned scsi_device. * - * Note: The only reason why drivers would want to use this is because - * they're need to access the device list in irq context. Otherwise you + * Note: The only reason why drivers should use this is because + * they need to access the device list in irq context. Otherwise you * really want to use scsi_device_lookup_by_target instead. **/ struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget, @@ -947,9 +956,9 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_ta * @starget: SCSI target pointer * @lun: SCSI Logical Unit Number * - * Looks up the scsi_device with the specified @channel, @id, @lun for a - * give host. The returned scsi_device has an additional reference that - * needs to be release with scsi_host_put once you're done with it. + * Description: Looks up the scsi_device with the specified @channel, @id, @lun + * for a given host. The returned scsi_device has an additional reference that + * needs to be released with scsi_device_put once you're done with it. **/ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget, uint lun) @@ -969,19 +978,19 @@ struct scsi_device *scsi_device_lookup_b EXPORT_SYMBOL(scsi_device_lookup_by_target); /** - * scsi_device_lookup - find a device given the host (UNLOCKED) + * __scsi_device_lookup - find a device given the host (UNLOCKED) * @shost: SCSI host pointer * @channel: SCSI channel (zero if only one channel) - * @pun: SCSI target number (physical unit number) + * @id: SCSI target number (physical unit number) * @lun: SCSI Logical Unit Number * - * Looks up the scsi_device with the specified @channel, @id, @lun for a - * give host. The returned scsi_device does not have an additional reference. - * You must hold the host's host_lock over this call and any access to the - * returned scsi_device. + * Description: Looks up the scsi_device with the specified @channel, @id, @lun + * for a given host. The returned scsi_device does not have an additional + * reference. You must hold the host's host_lock over this call and any access + * to the returned scsi_device. * * Note: The only reason why drivers would want to use this is because - * they're need to access the device list in irq context. Otherwise you + * they need to access the device list in irq context. Otherwise you * really want to use scsi_device_lookup instead. **/ struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost, @@ -1006,9 +1015,9 @@ EXPORT_SYMBOL(__scsi_device_lookup); * @id: SCSI target number (physical unit number) * @lun: SCSI Logical Unit Number * - * Looks up the scsi_device with the specified @channel, @id, @lun for a - * give host. The returned scsi_device has an additional reference that - * needs to be release with scsi_host_put once you're done with it. + * Description: Looks up the scsi_device with the specified @channel, @id, @lun + * for a given host. The returned scsi_device has an additional reference that + * needs to be released with scsi_device_put once you're done with it. **/ struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost, uint channel, uint id, uint lun) diff -puN drivers/scsi/scsi_debug.c~git-scsi-misc drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c~git-scsi-misc +++ a/drivers/scsi/scsi_debug.c @@ -329,7 +329,7 @@ int scsi_debug_queuecommand(struct scsi_ if (done == NULL) return 0; /* assume mid level reprocessing command */ - SCpnt->resid = 0; + scsi_set_resid(SCpnt, 0); if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { printk(KERN_INFO "scsi_debug: cmd "); for (k = 0, len = SCpnt->cmd_len; k < len; ++k) @@ -603,26 +603,16 @@ static int fill_from_dev_buffer(struct s void * kaddr_off; struct scatterlist * sg; - if (0 == scp->request_bufflen) + if (0 == scsi_bufflen(scp)) return 0; - if (NULL == scp->request_buffer) + if (NULL == scsi_sglist(scp)) return (DID_ERROR << 16); if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || (scp->sc_data_direction == DMA_FROM_DEVICE))) return (DID_ERROR << 16); - if (0 == scp->use_sg) { - req_len = scp->request_bufflen; - act_len = (req_len < arr_len) ? req_len : arr_len; - memcpy(scp->request_buffer, arr, act_len); - if (scp->resid) - scp->resid -= act_len; - else - scp->resid = req_len - act_len; - return 0; - } active = 1; req_len = act_len = 0; - scsi_for_each_sg(scp, sg, scp->use_sg, k) { + scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) { if (active) { kaddr = (unsigned char *) kmap_atomic(sg_page(sg), KM_USER0); @@ -640,10 +630,10 @@ static int fill_from_dev_buffer(struct s } req_len += sg->length; } - if (scp->resid) - scp->resid -= act_len; + if (scsi_get_resid(scp)) + scsi_set_resid(scp, scsi_get_resid(scp) - act_len); else - scp->resid = req_len - act_len; + scsi_set_resid(scp, req_len - act_len); return 0; } @@ -656,22 +646,15 @@ static int fetch_to_dev_buffer(struct sc void * kaddr_off; struct scatterlist * sg; - if (0 == scp->request_bufflen) + if (0 == scsi_bufflen(scp)) return 0; - if (NULL == scp->request_buffer) + if (NULL == scsi_sglist(scp)) return -1; if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || (scp->sc_data_direction == DMA_TO_DEVICE))) return -1; - if (0 == scp->use_sg) { - req_len = scp->request_bufflen; - len = (req_len < max_arr_len) ? req_len : max_arr_len; - memcpy(arr, scp->request_buffer, len); - return len; - } - sg = scsi_sglist(scp); req_len = fin = 0; - for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) { + scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) { kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); if (NULL == kaddr) return -1; diff -puN drivers/scsi/scsi_devinfo.c~git-scsi-misc drivers/scsi/scsi_devinfo.c --- a/drivers/scsi/scsi_devinfo.c~git-scsi-misc +++ a/drivers/scsi/scsi_devinfo.c @@ -276,11 +276,12 @@ static void scsi_strcpy_devinfo(char *na } /** - * scsi_dev_info_list_add: add one dev_info list entry. + * scsi_dev_info_list_add - add one dev_info list entry. + * @compatible: if true, null terminate short strings. Otherwise space pad. * @vendor: vendor string * @model: model (product) string * @strflags: integer string - * @flag: if strflags NULL, use this flag value + * @flags: if strflags NULL, use this flag value * * Description: * Create and add one dev_info entry for @vendor, @model, @strflags or @@ -322,8 +323,7 @@ static int scsi_dev_info_list_add(int co } /** - * scsi_dev_info_list_add_str: parse dev_list and add to the - * scsi_dev_info_list. + * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list. * @dev_list: string of device flags to add * * Description: @@ -374,15 +374,15 @@ static int scsi_dev_info_list_add_str(ch } /** - * get_device_flags - get device specific flags from the dynamic device - * list. Called during scan time. + * get_device_flags - get device specific flags from the dynamic device list. + * @sdev: &scsi_device to get flags for * @vendor: vendor name * @model: model name * * Description: * Search the scsi_dev_info_list for an entry matching @vendor and * @model, if found, return the matching flags value, else return - * the host or global default settings. + * the host or global default settings. Called during scan time. **/ int scsi_get_device_flags(struct scsi_device *sdev, const unsigned char *vendor, @@ -483,13 +483,11 @@ stop_output: } /* - * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via - * /proc. + * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc. * - * Use: echo "vendor:model:flag" > /proc/scsi/device_info - * - * To add a black/white list entry for vendor and model with an integer - * value of flag to the scsi device info list. + * Description: Adds a black/white list entry for vendor and model with an + * integer value of flag to the scsi device info list. + * To use, echo "vendor:model:flag" > /proc/scsi/device_info */ static int proc_scsi_devinfo_write(struct file *file, const char __user *buf, unsigned long length, void *data) @@ -532,8 +530,7 @@ MODULE_PARM_DESC(default_dev_flags, "scsi default device flag integer value"); /** - * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove - * the scsi_dev_info_list. + * scsi_dev_info_list_delete - called from scsi.c:exit_scsi to remove the scsi_dev_info_list. **/ void scsi_exit_devinfo(void) { @@ -552,13 +549,12 @@ void scsi_exit_devinfo(void) } /** - * scsi_dev_list_init: set up the dynamic device list. - * @dev_list: string of device flags to add + * scsi_init_devinfo - set up the dynamic device list. * * Description: - * Add command line @dev_list entries, then add + * Add command line entries from scsi_dev_flags, then add * scsi_static_device_list entries to the scsi device info list. - **/ + */ int __init scsi_init_devinfo(void) { #ifdef CONFIG_SCSI_PROC_FS diff -puN drivers/scsi/scsi_error.c~git-scsi-misc drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c~git-scsi-misc +++ a/drivers/scsi/scsi_error.c @@ -62,7 +62,7 @@ void scsi_eh_wakeup(struct Scsi_Host *sh * @shost: SCSI host to invoke error handling on. * * Schedule SCSI EH without scmd. - **/ + */ void scsi_schedule_eh(struct Scsi_Host *shost) { unsigned long flags; @@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh); * * Return value: * 0 on failure. - **/ + */ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) { struct Scsi_Host *shost = scmd->device->host; @@ -121,7 +121,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s * This should be turned into an inline function. Each scsi command * has its own timer, and as it is added to the queue, we set up the * timer. When the command completes, we cancel the timer. - **/ + */ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, void (*complete)(struct scsi_cmnd *)) { @@ -155,7 +155,7 @@ void scsi_add_timer(struct scsi_cmnd *sc * Return value: * 1 if we were able to detach the timer. 0 if we blew it, and the * timer function has already started to run. - **/ + */ int scsi_delete_timer(struct scsi_cmnd *scmd) { int rtn; @@ -181,7 +181,7 @@ int scsi_delete_timer(struct scsi_cmnd * * only in that the normal completion handling might run, but if the * normal completion function determines that the timer has already * fired, then it mustn't do anything. - **/ + */ void scsi_times_out(struct scsi_cmnd *scmd) { enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); @@ -224,7 +224,7 @@ void scsi_times_out(struct scsi_cmnd *sc * * Return value: * 0 when dev was taken offline by error recovery. 1 OK to proceed. - **/ + */ int scsi_block_when_processing_errors(struct scsi_device *sdev) { int online; @@ -245,7 +245,7 @@ EXPORT_SYMBOL(scsi_block_when_processing * scsi_eh_prt_fail_stats - Log info on failures. * @shost: scsi host being recovered. * @work_q: Queue of scsi cmds to process. - **/ + */ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, struct list_head *work_q) { @@ -295,7 +295,7 @@ static inline void scsi_eh_prt_fail_stat * Notes: * When a deferred error is detected the current command has * not been executed and needs retrying. - **/ + */ static int scsi_check_sense(struct scsi_cmnd *scmd) { struct scsi_sense_hdr sshdr; @@ -398,7 +398,7 @@ static int scsi_check_sense(struct scsi_ * queued during error recovery. the main difference here is that we * don't allow for the possibility of retries here, and we are a lot * more restrictive about what we consider acceptable. - **/ + */ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) { /* @@ -452,7 +452,7 @@ static int scsi_eh_completed_normally(st /** * scsi_eh_done - Completion function for error handling. * @scmd: Cmd that is done. - **/ + */ static void scsi_eh_done(struct scsi_cmnd *scmd) { struct completion *eh_action; @@ -469,7 +469,7 @@ static void scsi_eh_done(struct scsi_cmn /** * scsi_try_host_reset - ask host adapter to reset itself * @scmd: SCSI cmd to send hsot reset. - **/ + */ static int scsi_try_host_reset(struct scsi_cmnd *scmd) { unsigned long flags; @@ -498,7 +498,7 @@ static int scsi_try_host_reset(struct sc /** * scsi_try_bus_reset - ask host to perform a bus reset * @scmd: SCSI cmd to send bus reset. - **/ + */ static int scsi_try_bus_reset(struct scsi_cmnd *scmd) { unsigned long flags; @@ -533,7 +533,7 @@ static int scsi_try_bus_reset(struct scs * unreliable for a given host, then the host itself needs to put a * timer on it, and set the host back to a consistent state prior to * returning. - **/ + */ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) { int rtn; @@ -568,7 +568,7 @@ static int __scsi_try_to_abort_cmd(struc * author of the low-level driver wishes this operation to be timed, * they can provide this facility themselves. helper functions in * scsi_error.c can be supplied to make this easier to do. - **/ + */ static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) { /* @@ -601,7 +601,7 @@ static void scsi_abort_eh_cmnd(struct sc * sent must be one that does not transfer any data. If @sense_bytes != 0 * @cmnd is ignored and this functions sets up a REQUEST_SENSE command * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer. - **/ + */ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, unsigned char *cmnd, int cmnd_size, unsigned sense_bytes) { @@ -667,7 +667,7 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd); * @ses: saved information from a coresponding call to scsi_prep_eh_cmnd * * Undo any damage done by above scsi_prep_eh_cmnd(). - **/ + */ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) { /* @@ -697,7 +697,7 @@ EXPORT_SYMBOL(scsi_eh_restore_cmnd); * * Return value: * SUCCESS or FAILED or NEEDS_RETRY - **/ + */ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, int cmnd_size, int timeout, unsigned sense_bytes) { @@ -765,7 +765,7 @@ static int scsi_send_eh_cmnd(struct scsi * Some hosts automatically obtain this information, others require * that we obtain it on our own. This function will *not* return until * the command either times out, or it completes. - **/ + */ static int scsi_request_sense(struct scsi_cmnd *scmd) { return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0); @@ -779,10 +779,10 @@ static int scsi_request_sense(struct scs * Notes: * We don't want to use the normal command completion while we are are * still handling errors - it may cause other commands to be queued, - * and that would disturb what we are doing. thus we really want to + * and that would disturb what we are doing. Thus we really want to * keep a list of pending commands for final completion, and once we * are ready to leave error handling we handle completion for real. - **/ + */ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) { scmd->device->host->host_failed--; @@ -794,7 +794,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd); /** * scsi_eh_get_sense - Get device sense data. * @work_q: Queue of commands to process. - * @done_q: Queue of proccessed commands.. + * @done_q: Queue of processed commands. * * Description: * See if we need to request sense information. if so, then get it @@ -802,7 +802,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd); * * Notes: * This has the unfortunate side effect that if a shost adapter does - * not automatically request sense information, that we end up shutting + * not automatically request sense information, we end up shutting * it down before we request it. * * All drivers should request sense information internally these days, @@ -810,7 +810,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd); * * XXX: Long term this code should go away, but that needs an audit of * all LLDDs first. - **/ + */ int scsi_eh_get_sense(struct list_head *work_q, struct list_head *done_q) { @@ -858,11 +858,11 @@ EXPORT_SYMBOL_GPL(scsi_eh_get_sense); /** * scsi_eh_tur - Send TUR to device. - * @scmd: Scsi cmd to send TUR + * @scmd: &scsi_cmnd to send TUR * * Return value: * 0 - Device is ready. 1 - Device NOT ready. - **/ + */ static int scsi_eh_tur(struct scsi_cmnd *scmd) { static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; @@ -887,17 +887,17 @@ retry_tur: } /** - * scsi_eh_abort_cmds - abort canceled commands. - * @shost: scsi host being recovered. - * @eh_done_q: list_head for processed commands. + * scsi_eh_abort_cmds - abort pending commands. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. * * Decription: * Try and see whether or not it makes sense to try and abort the - * running command. this only works out to be the case if we have one - * command that has timed out. if the command simply failed, it makes + * running command. This only works out to be the case if we have one + * command that has timed out. If the command simply failed, it makes * no sense to try and abort the command, since as far as the shost * adapter is concerned, it isn't running. - **/ + */ static int scsi_eh_abort_cmds(struct list_head *work_q, struct list_head *done_q) { @@ -931,11 +931,11 @@ static int scsi_eh_abort_cmds(struct lis /** * scsi_eh_try_stu - Send START_UNIT to device. - * @scmd: Scsi cmd to send START_UNIT + * @scmd: &scsi_cmnd to send START_UNIT * * Return value: * 0 - Device is ready. 1 - Device NOT ready. - **/ + */ static int scsi_eh_try_stu(struct scsi_cmnd *scmd) { static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; @@ -956,13 +956,14 @@ static int scsi_eh_try_stu(struct scsi_c /** * scsi_eh_stu - send START_UNIT if needed - * @shost: scsi host being recovered. - * @eh_done_q: list_head for processed commands. + * @shost: &scsi host being recovered. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. * * Notes: * If commands are failing due to not ready, initializing command required, * try revalidating the device, which will end up sending a start unit. - **/ + */ static int scsi_eh_stu(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) @@ -1008,14 +1009,15 @@ static int scsi_eh_stu(struct Scsi_Host /** * scsi_eh_bus_device_reset - send bdr if needed * @shost: scsi host being recovered. - * @eh_done_q: list_head for processed commands. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. * * Notes: - * Try a bus device reset. still, look to see whether we have multiple + * Try a bus device reset. Still, look to see whether we have multiple * devices that are jammed or not - if we have multiple devices, it * makes no sense to try bus_device_reset - we really would need to try * a bus_reset instead. - **/ + */ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) @@ -1063,9 +1065,10 @@ static int scsi_eh_bus_device_reset(stru /** * scsi_eh_bus_reset - send a bus reset - * @shost: scsi host being recovered. - * @eh_done_q: list_head for processed commands. - **/ + * @shost: &scsi host being recovered. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. + */ static int scsi_eh_bus_reset(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) @@ -1122,7 +1125,7 @@ static int scsi_eh_bus_reset(struct Scsi * scsi_eh_host_reset - send a host reset * @work_q: list_head for processed commands. * @done_q: list_head for processed commands. - **/ + */ static int scsi_eh_host_reset(struct list_head *work_q, struct list_head *done_q) { @@ -1157,8 +1160,7 @@ static int scsi_eh_host_reset(struct lis * scsi_eh_offline_sdevs - offline scsi devices that fail to recover * @work_q: list_head for processed commands. * @done_q: list_head for processed commands. - * - **/ + */ static void scsi_eh_offline_sdevs(struct list_head *work_q, struct list_head *done_q) { @@ -1191,7 +1193,7 @@ static void scsi_eh_offline_sdevs(struct * is woken. In cases where the error code indicates an error that * doesn't require the error handler read (i.e. we don't need to * abort/reset), this function should return SUCCESS. - **/ + */ int scsi_decide_disposition(struct scsi_cmnd *scmd) { int rtn; @@ -1372,7 +1374,7 @@ int scsi_decide_disposition(struct scsi_ * * If scsi_allocate_request() fails for what ever reason, we * completely forget to lock the door. - **/ + */ static void scsi_eh_lock_door(struct scsi_device *sdev) { unsigned char cmnd[MAX_COMMAND_SIZE]; @@ -1396,7 +1398,7 @@ static void scsi_eh_lock_door(struct scs * Notes: * When we entered the error handler, we blocked all further i/o to * this device. we need to 'reverse' this process. - **/ + */ static void scsi_restart_operations(struct Scsi_Host *shost) { struct scsi_device *sdev; @@ -1440,9 +1442,9 @@ static void scsi_restart_operations(stru /** * scsi_eh_ready_devs - check device ready state and recover if not. * @shost: host to be recovered. - * @eh_done_q: list_head for processed commands. - * - **/ + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. + */ void scsi_eh_ready_devs(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) @@ -1458,8 +1460,7 @@ EXPORT_SYMBOL_GPL(scsi_eh_ready_devs); /** * scsi_eh_flush_done_q - finish processed commands or retry them. * @done_q: list_head of processed commands. - * - **/ + */ void scsi_eh_flush_done_q(struct list_head *done_q) { struct scsi_cmnd *scmd, *next; @@ -1513,7 +1514,7 @@ EXPORT_SYMBOL(scsi_eh_flush_done_q); * scsi_finish_cmd() called for it. we do all of the retry stuff * here, so when we restart the host after we return it should have an * empty queue. - **/ + */ static void scsi_unjam_host(struct Scsi_Host *shost) { unsigned long flags; @@ -1540,7 +1541,7 @@ static void scsi_unjam_host(struct Scsi_ * Notes: * This is the main error handling loop. This is run as a kernel thread * for every SCSI host and handles all error handling activity. - **/ + */ int scsi_error_handler(void *data) { struct Scsi_Host *shost = data; @@ -1769,7 +1770,7 @@ EXPORT_SYMBOL(scsi_reset_provider); * * Return value: * 1 if valid sense data information found, else 0; - **/ + */ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr) { @@ -1824,9 +1825,7 @@ int scsi_command_normalize_sense(struct EXPORT_SYMBOL(scsi_command_normalize_sense); /** - * scsi_sense_desc_find - search for a given descriptor type in - * descriptor sense data format. - * + * 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 @@ -1837,7 +1836,7 @@ EXPORT_SYMBOL(scsi_command_normalize_sen * * 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) { @@ -1865,9 +1864,7 @@ const u8 * scsi_sense_desc_find(const u8 EXPORT_SYMBOL(scsi_sense_desc_find); /** - * scsi_get_sense_info_fld - attempts to get information field from - * sense data (either fixed or descriptor format) - * + * scsi_get_sense_info_fld - 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 @@ -1875,7 +1872,7 @@ EXPORT_SYMBOL(scsi_sense_desc_find); * * 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) { diff -puN drivers/scsi/scsi_ioctl.c~git-scsi-misc drivers/scsi/scsi_ioctl.c --- a/drivers/scsi/scsi_ioctl.c~git-scsi-misc +++ a/drivers/scsi/scsi_ioctl.c @@ -174,10 +174,15 @@ static int scsi_ioctl_get_pci(struct scs } -/* - * the scsi_ioctl() function differs from most ioctls in that it does - * not take a major/minor number as the dev field. Rather, it takes - * a pointer to a scsi_devices[] element, a structure. +/** + * scsi_ioctl - Dispatch ioctl to scsi device + * @sdev: scsi device receiving ioctl + * @cmd: which ioctl is it + * @arg: data associated with ioctl + * + * Description: The scsi_ioctl() function differs from most ioctls in that it + * does not take a major/minor number as the dev field. Rather, it takes + * a pointer to a &struct scsi_device. */ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) { @@ -264,9 +269,12 @@ int scsi_ioctl(struct scsi_device *sdev, } EXPORT_SYMBOL(scsi_ioctl); -/* - * the scsi_nonblock_ioctl() function is designed for ioctls which may - * be executed even if the device is in recovery. +/** + * scsi_nonblock_ioctl() - Handle SG_SCSI_RESET + * @sdev: scsi device receiving ioctl + * @cmd: Must be SC_SCSI_RESET + * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST} + * @filp: either NULL or a &struct file which must have the O_NONBLOCK flag. */ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, void __user *arg, struct file *filp) @@ -276,7 +284,7 @@ int scsi_nonblockable_ioctl(struct scsi_ /* The first set of iocts may be executed even if we're doing * error processing, as long as the device was opened * non-blocking */ - if (filp && filp->f_flags & O_NONBLOCK) { + if (filp && (filp->f_flags & O_NONBLOCK)) { if (scsi_host_in_recovery(sdev->host)) return -ENODEV; } else if (!scsi_block_when_processing_errors(sdev)) diff -puN drivers/scsi/scsi_lib.c~git-scsi-misc drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c~git-scsi-misc +++ a/drivers/scsi/scsi_lib.c @@ -175,7 +175,7 @@ int scsi_queue_insert(struct scsi_cmnd * * * returns the req->errors value which is the scsi_cmnd result * field. - **/ + */ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, unsigned char *sense, int timeout, int retries, int flags) @@ -274,7 +274,7 @@ static void scsi_bi_endio(struct bio *bi /** * scsi_req_map_sg - map a scatterlist into a request * @rq: request to fill - * @sg: scatterlist + * @sgl: scatterlist * @nsegs: number of elements * @bufflen: len of buffer * @gfp: memory allocation flags @@ -365,14 +365,16 @@ free_bios: * @sdev: scsi device * @cmd: scsi command * @cmd_len: length of scsi cdb - * @data_direction: data direction + * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE * @buffer: data buffer (this can be a kernel buffer or scatterlist) * @bufflen: len of buffer * @use_sg: if buffer is a scatterlist this is the number of elements * @timeout: request timeout in seconds * @retries: number of times to retry request - * @flags: or into request flags - **/ + * @privdata: data passed to done() + * @done: callback function when done + * @gfp: memory allocation flags + */ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, int cmd_len, int data_direction, void *buffer, unsigned bufflen, int use_sg, int timeout, int retries, void *privdata, @@ -524,7 +526,7 @@ static void scsi_run_queue(struct reques struct Scsi_Host *shost = sdev->host; unsigned long flags; - if (sdev->single_lun) + if (scsi_target(sdev)->single_lun) scsi_single_lun_run(sdev); spin_lock_irqsave(shost->host_lock, flags); @@ -1277,9 +1279,19 @@ int scsi_prep_state_check(struct scsi_de "rejecting I/O to dead device\n"); ret = BLKPREP_KILL; break; - case SDEV_QUIESCE: case SDEV_BLOCK: /* + * Return failfast requests immediately + */ + if (req->cmd_flags & REQ_FAILFAST) { + ret = BLKPREP_KILL; + break; + } + + /* fall through */ + + case SDEV_QUIESCE: + /* * If the devices is blocked we defer normal commands. */ if (!(req->cmd_flags & REQ_PREEMPT)) @@ -1412,6 +1424,17 @@ static inline int scsi_host_queue_ready( return 1; } +static void __scsi_kill_request(struct request *req) +{ + struct scsi_cmnd *cmd = req->special; + struct scsi_device *sdev = cmd->device; + + cmd->result = DID_NO_CONNECT << 16; + atomic_inc(&cmd->device->iorequest_cnt); + sdev->device_busy--; + __scsi_done(cmd); +} + /* * Kill a request for a dead device */ @@ -1525,9 +1548,18 @@ static void scsi_request_fn(struct reque * accept it. */ req = elv_next_request(q); - if (!req || !scsi_dev_queue_ready(q, sdev)) + if (!req) break; + if (!scsi_dev_queue_ready(q, sdev)) { + if ((req->cmd_flags & REQ_FAILFAST) && + !(req->cmd_flags & REQ_PREEMPT)) { + scsi_kill_request(req, q); + continue; + } + break; + } + if (unlikely(!scsi_device_online(sdev))) { sdev_printk(KERN_ERR, sdev, "rejecting I/O to offline device\n"); @@ -1557,7 +1589,7 @@ static void scsi_request_fn(struct reque if (!scsi_host_queue_ready(q, shost, sdev)) goto not_ready; - if (sdev->single_lun) { + if (scsi_target(sdev)->single_lun) { if (scsi_target(sdev)->starget_sdev_user && scsi_target(sdev)->starget_sdev_user != sdev) goto not_ready; @@ -1607,8 +1639,12 @@ static void scsi_request_fn(struct reque * later time. */ spin_lock_irq(q->queue_lock); - blk_requeue_request(q, req); - sdev->device_busy--; + if (unlikely(req->cmd_flags & REQ_FAILFAST)) + __scsi_kill_request(req); + else { + blk_requeue_request(q, req); + sdev->device_busy--; + } if(sdev->device_busy == 0) blk_plug_device(q); out: @@ -1804,7 +1840,7 @@ void scsi_exit_queue(void) * @timeout: command timeout * @retries: number of retries before failing * @data: returns a structure abstracting the mode header data - * @sense: place to put sense data (or NULL if no sense to be collected). + * @sshdr: place to put sense data (or NULL if no sense to be collected). * must be SCSI_SENSE_BUFFERSIZE big. * * Returns zero if successful; negative error number or scsi @@ -1871,8 +1907,7 @@ scsi_mode_select(struct scsi_device *sde EXPORT_SYMBOL_GPL(scsi_mode_select); /** - * scsi_mode_sense - issue a mode sense, falling back from 10 to - * six bytes if necessary. + * scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary. * @sdev: SCSI device to be queried * @dbd: set if mode sense will allow block descriptors to be returned * @modepage: mode page being requested @@ -1881,13 +1916,13 @@ EXPORT_SYMBOL_GPL(scsi_mode_select); * @timeout: command timeout * @retries: number of retries before failing * @data: returns a structure abstracting the mode header data - * @sense: place to put sense data (or NULL if no sense to be collected). + * @sshdr: place to put sense data (or NULL if no sense to be collected). * must be SCSI_SENSE_BUFFERSIZE big. * * Returns zero if unsuccessful, or the header offset (either 4 * or 8 depending on whether a six or ten byte command was * issued) if successful. - **/ + */ int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, int retries, @@ -2007,14 +2042,13 @@ scsi_test_unit_ready(struct scsi_device EXPORT_SYMBOL(scsi_test_unit_ready); /** - * scsi_device_set_state - Take the given device through the device - * state model. + * scsi_device_set_state - Take the given device through the device state model. * @sdev: scsi device to change the state of. * @state: state to change to. * * Returns zero if unsuccessful or an error if the requested * transition is illegal. - **/ + */ int scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) { @@ -2264,7 +2298,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple); * Must be called with user context, may sleep. * * Returns zero if unsuccessful or an error if not. - **/ + */ int scsi_device_quiesce(struct scsi_device *sdev) { @@ -2289,7 +2323,7 @@ EXPORT_SYMBOL(scsi_device_quiesce); * queues. * * Must be called with user context, may sleep. - **/ + */ void scsi_device_resume(struct scsi_device *sdev) { @@ -2326,8 +2360,7 @@ scsi_target_resume(struct scsi_target *s EXPORT_SYMBOL(scsi_target_resume); /** - * scsi_internal_device_block - internal function to put a device - * temporarily into the SDEV_BLOCK state + * scsi_internal_device_block - internal function to put a device temporarily into the SDEV_BLOCK state * @sdev: device to block * * Block request made by scsi lld's to temporarily stop all @@ -2342,7 +2375,7 @@ EXPORT_SYMBOL(scsi_target_resume); * state, all commands are deferred until the scsi lld reenables * the device with scsi_device_unblock or device_block_tmo fires. * This routine assumes the host_lock is held on entry. - **/ + */ int scsi_internal_device_block(struct scsi_device *sdev) { @@ -2382,7 +2415,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_b * (which must be a legal transition) allowing the midlayer to * goose the queue for this device. This routine assumes the * host_lock is held upon entry. - **/ + */ int scsi_internal_device_unblock(struct scsi_device *sdev) { @@ -2460,7 +2493,7 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock); /** * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt - * @sg: scatter-gather list + * @sgl: scatter-gather list * @sg_count: number of segments in sg * @offset: offset in bytes into sg, on return offset into the mapped area * @len: bytes to map, on return number of bytes mapped @@ -2509,8 +2542,7 @@ void *scsi_kmap_atomic_sg(struct scatter EXPORT_SYMBOL(scsi_kmap_atomic_sg); /** - * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously - * mapped with scsi_kmap_atomic_sg + * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously mapped with scsi_kmap_atomic_sg * @virt: virtual address to be unmapped */ void scsi_kunmap_atomic_sg(void *virt) diff -puN drivers/scsi/scsi_netlink.c~git-scsi-misc drivers/scsi/scsi_netlink.c --- a/drivers/scsi/scsi_netlink.c~git-scsi-misc +++ a/drivers/scsi/scsi_netlink.c @@ -32,11 +32,12 @@ EXPORT_SYMBOL_GPL(scsi_nl_sock); /** - * scsi_nl_rcv_msg - - * Receive message handler. Extracts message from a receive buffer. + * scsi_nl_rcv_msg - Receive message handler. + * @skb: socket receive buffer + * + * Description: Extracts message from a receive buffer. * Validates message header and calls appropriate transport message handler * - * @skb: socket receive buffer * **/ static void @@ -99,9 +100,7 @@ next_msg: /** - * scsi_nl_rcv_event - - * Event handler for a netlink socket. - * + * scsi_nl_rcv_event - Event handler for a netlink socket. * @this: event notifier block * @event: event type * @ptr: event payload @@ -129,9 +128,7 @@ static struct notifier_block scsi_netlin /** - * scsi_netlink_init - - * Called by SCSI subsystem to intialize the SCSI transport netlink - * interface + * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface * **/ void @@ -160,9 +157,7 @@ scsi_netlink_init(void) /** - * scsi_netlink_exit - - * Called by SCSI subsystem to disable the SCSI transport netlink - * interface + * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface * **/ void diff -puN drivers/scsi/scsi_proc.c~git-scsi-misc drivers/scsi/scsi_proc.c --- a/drivers/scsi/scsi_proc.c~git-scsi-misc +++ a/drivers/scsi/scsi_proc.c @@ -45,6 +45,16 @@ static struct proc_dir_entry *proc_scsi; /* Protect sht->present and sht->proc_dir */ static DEFINE_MUTEX(global_host_template_mutex); +/** + * proc_scsi_read - handle read from /proc by calling host's proc_info() command + * @buffer: passed to proc_info + * @start: passed to proc_info + * @offset: passed to proc_info + * @length: passed to proc_info + * @eof: returns whether length read was less than requested + * @data: pointer to a &struct Scsi_Host + */ + static int proc_scsi_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { @@ -57,6 +67,13 @@ static int proc_scsi_read(char *buffer, return n; } +/** + * proc_scsi_write_proc - Handle write to /proc by calling host's proc_info() + * @file: not used + * @buf: source of data to write. + * @count: number of bytes (at most PROC_BLOCK_SIZE) to write. + * @data: pointer to &struct Scsi_Host + */ static int proc_scsi_write_proc(struct file *file, const char __user *buf, unsigned long count, void *data) { @@ -80,6 +97,13 @@ out: return ret; } +/** + * scsi_proc_hostdir_add - Create directory in /proc for a scsi host + * @sht: owner of this directory + * + * Sets sht->proc_dir to the new directory. + */ + void scsi_proc_hostdir_add(struct scsi_host_template *sht) { if (!sht->proc_info) @@ -97,6 +121,10 @@ void scsi_proc_hostdir_add(struct scsi_h mutex_unlock(&global_host_template_mutex); } +/** + * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host + * @sht: owner of directory + */ void scsi_proc_hostdir_rm(struct scsi_host_template *sht) { if (!sht->proc_info) @@ -110,6 +138,11 @@ void scsi_proc_hostdir_rm(struct scsi_ho mutex_unlock(&global_host_template_mutex); } + +/** + * scsi_proc_host_add - Add entry for this host to appropriate /proc dir + * @shost: host to add + */ void scsi_proc_host_add(struct Scsi_Host *shost) { struct scsi_host_template *sht = shost->hostt; @@ -133,6 +166,10 @@ void scsi_proc_host_add(struct Scsi_Host p->owner = sht->module; } +/** + * scsi_proc_host_rm - remove this host's entry from /proc + * @shost: which host + */ void scsi_proc_host_rm(struct Scsi_Host *shost) { char name[10]; @@ -143,7 +180,14 @@ void scsi_proc_host_rm(struct Scsi_Host sprintf(name,"%d", shost->host_no); remove_proc_entry(name, shost->hostt->proc_dir); } - +/** + * proc_print_scsidevice - return data about this host + * @dev: A scsi device + * @data: &struct seq_file to output to. + * + * Description: prints Host, Channel, Id, Lun, Vendor, Model, Rev, Type, + * and revision. + */ static int proc_print_scsidevice(struct device *dev, void *data) { struct scsi_device *sdev = to_scsi_device(dev); @@ -189,6 +233,21 @@ static int proc_print_scsidevice(struct return 0; } +/** + * scsi_add_single_device - Respond to user request to probe for/add device + * @host: user-supplied decimal integer + * @channel: user-supplied decimal integer + * @id: user-supplied decimal integer + * @lun: user-supplied decimal integer + * + * Description: called by writing "scsi add-single-device" to /proc/scsi/scsi. + * + * does scsi_host_lookup() and either user_scan() if that transport + * type supports it, or else scsi_scan_host_selected() + * + * Note: this seems to be aimed exclusively at SCSI parallel busses. + */ + static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) { struct Scsi_Host *shost; @@ -206,6 +265,16 @@ static int scsi_add_single_device(uint h return error; } +/** + * scsi_remove_single_device - Respond to user request to remove a device + * @host: user-supplied decimal integer + * @channel: user-supplied decimal integer + * @id: user-supplied decimal integer + * @lun: user-supplied decimal integer + * + * Description: called by writing "scsi remove-single-device" to + * /proc/scsi/scsi. Does a scsi_device_lookup() and scsi_remove_device() + */ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) { struct scsi_device *sdev; @@ -226,6 +295,25 @@ static int scsi_remove_single_device(uin return error; } +/** + * proc_scsi_write - handle writes to /proc/scsi/scsi + * @file: not used + * @buf: buffer to write + * @length: length of buf, at most PAGE_SIZE + * @ppos: not used + * + * Description: this provides a legacy mechanism to add or remove devices by + * Host, Channel, ID, and Lun. To use, + * "echo 'scsi add-single-device 0 1 2 3' > /proc/scsi/scsi" or + * "echo 'scsi remove-single-device 0 1 2 3' > /proc/scsi/scsi" with + * "0 1 2 3" replaced by the Host, Channel, Id, and Lun. + * + * Note: this seems to be aimed at parallel SCSI. Most modern busses (USB, + * SATA, Firewire, Fibre Channel, etc) dynamically assign these values to + * provide a unique identifier and nothing more. + */ + + static ssize_t proc_scsi_write(struct file *file, const char __user *buf, size_t length, loff_t *ppos) { @@ -291,6 +379,11 @@ static ssize_t proc_scsi_write(struct fi return err; } +/** + * proc_scsi_show - show contents of /proc/scsi/scsi (attached devices) + * @s: output goes here + * @p: not used + */ static int proc_scsi_show(struct seq_file *s, void *p) { seq_printf(s, "Attached devices:\n"); @@ -298,10 +391,17 @@ static int proc_scsi_show(struct seq_fil return 0; } +/** + * proc_scsi_open - glue function + * @inode: not used + * @file: passed to single_open() + * + * Associates proc_scsi_show with this file + */ static int proc_scsi_open(struct inode *inode, struct file *file) { /* - * We don't really needs this for the write case but it doesn't + * We don't really need this for the write case but it doesn't * harm either. */ return single_open(file, proc_scsi_show, NULL); @@ -315,6 +415,9 @@ static const struct file_operations proc .release = single_release, }; +/** + * scsi_init_procfs - create scsi and scsi/scsi in procfs + */ int __init scsi_init_procfs(void) { struct proc_dir_entry *pde; @@ -336,6 +439,9 @@ err1: return -ENOMEM; } +/** + * scsi_exit_procfs - Remove scsi/scsi and scsi from procfs + */ void scsi_exit_procfs(void) { remove_proc_entry("scsi/scsi", NULL); diff -puN drivers/scsi/scsi_scan.c~git-scsi-misc drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c~git-scsi-misc +++ a/drivers/scsi/scsi_scan.c @@ -221,6 +221,9 @@ static void scsi_unlock_floptical(struct /** * scsi_alloc_sdev - allocate and setup a scsi_Device + * @starget: which target to allocate a &scsi_device for + * @lun: which lun + * @hostdata: usually NULL and set by ->slave_alloc instead * * Description: * Allocate, initialize for io, and return a pointer to a scsi_Device. @@ -472,7 +475,6 @@ static void scsi_target_reap_usercontext /** * scsi_target_reap - check to see if target is in use and destroy if not - * * @starget: target to be checked * * This is used after removing a LUN or doing a last put of the target @@ -863,7 +865,7 @@ static int scsi_add_lun(struct scsi_devi sdev->no_start_on_add = 1; if (*bflags & BLIST_SINGLELUN) - sdev->single_lun = 1; + scsi_target(sdev)->single_lun = 1; sdev->use_10_for_rw = 1; @@ -928,8 +930,7 @@ static inline void scsi_destroy_sdev(str #ifdef CONFIG_SCSI_LOGGING /** - * scsi_inq_str - print INQUIRY data from min to max index, - * strip trailing whitespace + * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace * @buf: Output buffer with at least end-first+1 bytes of space * @inq: Inquiry buffer (input) * @first: Offset of string into inq @@ -957,9 +958,10 @@ static unsigned char *scsi_inq_str(unsig * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it * @starget: pointer to target device structure * @lun: LUN of target device - * @sdevscan: probe the LUN corresponding to this scsi_device - * @sdevnew: store the value of any new scsi_device allocated * @bflagsp: store bflags here if not NULL + * @sdevp: probe the LUN corresponding to this scsi_device + * @rescan: if nonzero skip some code only needed on first scan + * @hostdata: passed to scsi_alloc_sdev() * * Description: * Call scsi_probe_lun, if a LUN with an attached device is found, @@ -1110,6 +1112,8 @@ static int scsi_probe_and_add_lun(struct * scsi_sequential_lun_scan - sequentially scan a SCSI target * @starget: pointer to target structure to scan * @bflags: black/white list flag for LUN 0 + * @scsi_level: Which version of the standard does this device adhere to + * @rescan: passed to scsi_probe_add_lun() * * Description: * Generally, scan from LUN 1 (LUN 0 is assumed to already have been @@ -1220,7 +1224,7 @@ EXPORT_SYMBOL(scsilun_to_int); /** * int_to_scsilun: reverts an int into a scsi_lun - * @int: integer to be reverted + * @lun: integer to be reverted * @scsilun: struct scsi_lun to be set. * * Description: @@ -1252,18 +1256,22 @@ EXPORT_SYMBOL(int_to_scsilun); /** * scsi_report_lun_scan - Scan using SCSI REPORT LUN results - * @sdevscan: scan the host, channel, and id of this scsi_device + * @starget: which target + * @bflags: Zero or a mix of BLIST_NOLUN, BLIST_REPORTLUN2, or BLIST_NOREPORTLUN + * @rescan: nonzero if we can skip code only needed on first scan * * Description: - * If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN - * command, and scan the resulting list of LUNs by calling - * scsi_probe_and_add_lun. + * Fast scanning for modern (SCSI-3) devices by sending a REPORT LUN command. + * Scan the resulting list of LUNs by calling scsi_probe_and_add_lun. * - * Modifies sdevscan->lun. + * If BLINK_REPORTLUN2 is set, scan a target that supports more than 8 + * LUNs even if it's older than SCSI-3. + * If BLIST_NOREPORTLUN is set, return 1 always. + * If BLIST_NOLUN is set, return 0 always. * * Return: * 0: scan completed (or no memory, so further scanning is futile) - * 1: no report lun scan, or not configured + * 1: could not scan with REPORT LUN **/ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, int rescan) diff -puN drivers/scsi/scsi_tgt_if.c~git-scsi-misc drivers/scsi/scsi_tgt_if.c --- a/drivers/scsi/scsi_tgt_if.c~git-scsi-misc +++ a/drivers/scsi/scsi_tgt_if.c @@ -112,7 +112,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi memset(&ev, 0, sizeof(ev)); ev.p.cmd_req.host_no = shost->host_no; ev.p.cmd_req.itn_id = itn_id; - ev.p.cmd_req.data_len = cmd->request_bufflen; + ev.p.cmd_req.data_len = scsi_bufflen(cmd); memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb)); memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun)); ev.p.cmd_req.attribute = cmd->tag; diff -puN drivers/scsi/scsi_tgt_lib.c~git-scsi-misc drivers/scsi/scsi_tgt_lib.c --- a/drivers/scsi/scsi_tgt_lib.c~git-scsi-misc +++ a/drivers/scsi/scsi_tgt_lib.c @@ -331,7 +331,7 @@ static void scsi_tgt_cmd_done(struct scs scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag); - if (cmd->request_buffer) + if (scsi_sglist(cmd)) scsi_free_sgtable(cmd); queue_work(scsi_tgtd, &tcmd->work); @@ -365,14 +365,15 @@ static int scsi_tgt_init_cmd(struct scsi cmd->request_bufflen = rq->data_len; - dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq)); - count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer); - if (likely(count <= cmd->use_sg)) { + dprintk("cmd %p cnt %d %lu\n", cmd, scsi_sg_count(cmd), + rq_data_dir(rq)); + count = blk_rq_map_sg(rq->q, rq, scsi_sglist(cmd)); + if (likely(count <= scsi_sg_count(cmd))) { cmd->use_sg = count; return 0; } - eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg); + eprintk("cmd %p cnt %d\n", cmd, scsi_sg_count(cmd)); scsi_free_sgtable(cmd); return -EINVAL; } diff -puN drivers/scsi/scsi_transport_fc.c~git-scsi-misc drivers/scsi/scsi_transport_fc.c --- a/drivers/scsi/scsi_transport_fc.c~git-scsi-misc +++ a/drivers/scsi/scsi_transport_fc.c @@ -481,9 +481,9 @@ MODULE_PARM_DESC(dev_loss_tmo, " exceeded, the scsi target is removed. Value should be" " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); -/** +/* * Netlink Infrastructure - **/ + */ static atomic_t fc_event_seq; @@ -491,10 +491,10 @@ static atomic_t fc_event_seq; * fc_get_event_number - Obtain the next sequential FC event number * * Notes: - * We could have inline'd this, but it would have required fc_event_seq to + * We could have inlined this, but it would have required fc_event_seq to * be exposed. For now, live with the subroutine call. * Atomic used to avoid lock/unlock... - **/ + */ u32 fc_get_event_number(void) { @@ -505,7 +505,6 @@ EXPORT_SYMBOL(fc_get_event_number); /** * fc_host_post_event - called to post an even on an fc_host. - * * @shost: host the event occurred on * @event_number: fc event number obtained from get_fc_event_number() * @event_code: fc_host event being posted @@ -513,7 +512,7 @@ EXPORT_SYMBOL(fc_get_event_number); * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_host_post_event(struct Scsi_Host *shost, u32 event_number, enum fc_host_event_code event_code, u32 event_data) @@ -579,17 +578,16 @@ EXPORT_SYMBOL(fc_host_post_event); /** - * fc_host_post_vendor_event - called to post a vendor unique event on - * a fc_host - * + * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host * @shost: host the event occurred on * @event_number: fc event number obtained from get_fc_event_number() * @data_len: amount, in bytes, of vendor unique data * @data_buf: pointer to vendor unique data + * @vendor_id: Vendor id * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, u32 data_len, char * data_buf, u64 vendor_id) @@ -1900,7 +1898,6 @@ static int fc_vport_match(struct attribu /** * fc_timed_out - FC Transport I/O timeout intercept handler - * * @scmd: The SCSI command which timed out * * This routine protects against error handlers getting invoked while a @@ -1920,7 +1917,7 @@ static int fc_vport_match(struct attribu * * Notes: * This routine assumes no locks are held on entry. - **/ + */ static enum scsi_eh_timer_return fc_timed_out(struct scsi_cmnd *scmd) { @@ -2133,7 +2130,7 @@ EXPORT_SYMBOL(fc_release_transport); * 1 - work queued for execution * 0 - work is already queued * -EINVAL - work queue doesn't exist - **/ + */ static int fc_queue_work(struct Scsi_Host *shost, struct work_struct *work) { @@ -2152,7 +2149,7 @@ fc_queue_work(struct Scsi_Host *shost, s /** * fc_flush_work - Flush a fc_host's workqueue. * @shost: Pointer to Scsi_Host bound to fc_host. - **/ + */ static void fc_flush_work(struct Scsi_Host *shost) { @@ -2175,7 +2172,7 @@ fc_flush_work(struct Scsi_Host *shost) * * Return value: * 1 on success / 0 already queued / < 0 for error - **/ + */ static int fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, unsigned long delay) @@ -2195,7 +2192,7 @@ fc_queue_devloss_work(struct Scsi_Host * /** * fc_flush_devloss - Flush a fc_host's devloss workqueue. * @shost: Pointer to Scsi_Host bound to fc_host. - **/ + */ static void fc_flush_devloss(struct Scsi_Host *shost) { @@ -2212,21 +2209,20 @@ fc_flush_devloss(struct Scsi_Host *shost /** - * fc_remove_host - called to terminate any fc_transport-related elements - * for a scsi host. - * @rport: remote port to be unblocked. + * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host. + * @shost: Which &Scsi_Host * * This routine is expected to be called immediately preceeding the * a driver's call to scsi_remove_host(). * * WARNING: A driver utilizing the fc_transport, which fails to call - * this routine prior to scsi_remote_host(), will leave dangling + * this routine prior to scsi_remove_host(), will leave dangling * objects in /sys/class/fc_remote_ports. Access to any of these * objects can result in a system crash !!! * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_remove_host(struct Scsi_Host *shost) { @@ -2281,10 +2277,10 @@ EXPORT_SYMBOL(fc_remove_host); /** * fc_starget_delete - called to delete the scsi decendents of an rport - * (target and all sdevs) - * * @work: remote port to be operated on. - **/ + * + * Deletes target and all sdevs. + */ static void fc_starget_delete(struct work_struct *work) { @@ -2303,9 +2299,8 @@ fc_starget_delete(struct work_struct *wo /** * fc_rport_final_delete - finish rport termination and delete it. - * * @work: remote port to be deleted. - **/ + */ static void fc_rport_final_delete(struct work_struct *work) { @@ -2375,7 +2370,7 @@ fc_rport_final_delete(struct work_struct * * Notes: * This routine assumes no locks are held on entry. - **/ + */ static struct fc_rport * fc_rport_create(struct Scsi_Host *shost, int channel, struct fc_rport_identifiers *ids) @@ -2462,8 +2457,7 @@ delete_rport: } /** - * fc_remote_port_add - notifies the fc transport of the existence - * of a remote FC port. + * fc_remote_port_add - notify fc transport of the existence of a remote FC port. * @shost: scsi host the remote port is connected to. * @channel: Channel on shost port connected to. * @ids: The world wide names, fc address, and FC4 port @@ -2499,7 +2493,7 @@ delete_rport: * * Notes: * This routine assumes no locks are held on entry. - **/ + */ struct fc_rport * fc_remote_port_add(struct Scsi_Host *shost, int channel, struct fc_rport_identifiers *ids) @@ -2683,19 +2677,18 @@ EXPORT_SYMBOL(fc_remote_port_add); /** - * fc_remote_port_delete - notifies the fc transport that a remote - * port is no longer in existence. + * fc_remote_port_delete - notifies the fc transport that a remote port is no longer in existence. * @rport: The remote port that no longer exists * * The LLDD calls this routine to notify the transport that a remote * port is no longer part of the topology. Note: Although a port * may no longer be part of the topology, it may persist in the remote * ports displayed by the fc_host. We do this under 2 conditions: - * - If the port was a scsi target, we delay its deletion by "blocking" it. + * 1) If the port was a scsi target, we delay its deletion by "blocking" it. * This allows the port to temporarily disappear, then reappear without * disrupting the SCSI device tree attached to it. During the "blocked" * period the port will still exist. - * - If the port was a scsi target and disappears for longer than we + * 2) If the port was a scsi target and disappears for longer than we * expect, we'll delete the port and the tear down the SCSI device tree * attached to it. However, we want to semi-persist the target id assigned * to that port if it eventually does exist. The port structure will @@ -2709,7 +2702,8 @@ EXPORT_SYMBOL(fc_remote_port_add); * temporary blocked state. From the LLDD's perspective, the rport no * longer exists. From the SCSI midlayer's perspective, the SCSI target * exists, but all sdevs on it are blocked from further I/O. The following - * is then expected: + * is then expected. + * * If the remote port does not return (signaled by a LLDD call to * fc_remote_port_add()) within the dev_loss_tmo timeout, then the * scsi target is removed - killing all outstanding i/o and removing the @@ -2731,7 +2725,7 @@ EXPORT_SYMBOL(fc_remote_port_add); * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_remote_port_delete(struct fc_rport *rport) { @@ -2792,12 +2786,12 @@ fc_remote_port_delete(struct fc_rport * EXPORT_SYMBOL(fc_remote_port_delete); /** - * fc_remote_port_rolechg - notifies the fc transport that the roles - * on a remote may have changed. + * fc_remote_port_rolechg - notifies the fc transport that the roles on a remote may have changed. * @rport: The remote port that changed. + * @roles: New roles for this port. * - * The LLDD calls this routine to notify the transport that the roles - * on a remote port may have changed. The largest effect of this is + * Description: The LLDD calls this routine to notify the transport that the + * roles on a remote port may have changed. The largest effect of this is * if a port now becomes a FCP Target, it must be allocated a * scsi target id. If the port is no longer a FCP target, any * scsi target id value assigned to it will persist in case the @@ -2810,7 +2804,7 @@ EXPORT_SYMBOL(fc_remote_port_delete); * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) { @@ -2875,12 +2869,12 @@ fc_remote_port_rolechg(struct fc_rport EXPORT_SYMBOL(fc_remote_port_rolechg); /** - * fc_timeout_deleted_rport - Timeout handler for a deleted remote port, - * which we blocked, and has now failed to return - * in the allotted time. - * + * fc_timeout_deleted_rport - Timeout handler for a deleted remote port. * @work: rport target that failed to reappear in the allotted time. - **/ + * + * Description: An attempt to delete a remote port blocks, and if it fails + * to return in the allotted time this gets called. + */ static void fc_timeout_deleted_rport(struct work_struct *work) { @@ -2984,14 +2978,12 @@ fc_timeout_deleted_rport(struct work_str } /** - * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a - * disconnected SCSI target. - * + * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target. * @work: rport to terminate io on. * * Notes: Only requests the failure of the io, not that all are flushed * prior to returning. - **/ + */ static void fc_timeout_fail_rport_io(struct work_struct *work) { @@ -3008,9 +3000,8 @@ fc_timeout_fail_rport_io(struct work_str /** * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. - * * @work: remote port to be scanned. - **/ + */ static void fc_scsi_scan_rport(struct work_struct *work) { @@ -3047,7 +3038,7 @@ fc_scsi_scan_rport(struct work_struct *w * * Notes: * This routine assumes no locks are held on entry. - **/ + */ static int fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev, struct fc_vport_identifiers *ids, struct fc_vport **ret_vport) @@ -3172,7 +3163,7 @@ delete_vport: * * Notes: * This routine assumes no locks are held on entry. - **/ + */ int fc_vport_terminate(struct fc_vport *vport) { @@ -3232,9 +3223,8 @@ EXPORT_SYMBOL(fc_vport_terminate); /** * fc_vport_sched_delete - workq-based delete request for a vport - * * @work: vport to be deleted. - **/ + */ static void fc_vport_sched_delete(struct work_struct *work) { diff -puN drivers/scsi/scsi_transport_iscsi.c~git-scsi-misc drivers/scsi/scsi_transport_iscsi.c --- a/drivers/scsi/scsi_transport_iscsi.c~git-scsi-misc +++ a/drivers/scsi/scsi_transport_iscsi.c @@ -328,9 +328,10 @@ EXPORT_SYMBOL_GPL(iscsi_add_session); * iscsi_create_session - create iscsi class session * @shost: scsi host * @transport: iscsi transport + * @target_id: which target * * This can be called from a LLD or iscsi_transport. - **/ + */ struct iscsi_cls_session * iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport, @@ -382,7 +383,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session); * * Can be called by a LLD or iscsi_transport. There must not be * any running connections. - **/ + */ int iscsi_destroy_session(struct iscsi_cls_session *session) { iscsi_remove_session(session); @@ -418,7 +419,7 @@ static int iscsi_is_conn_dev(const struc * for software iscsi we could be trying to preallocate a connection struct * in which case there could be two connection structs and cid would be * non-zero. - **/ + */ struct iscsi_cls_conn * iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) { @@ -465,10 +466,10 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn); /** * iscsi_destroy_conn - destroy iscsi class connection - * @session: iscsi cls session + * @conn: iscsi cls session * - * This can be called from a LLD or iscsi_transport. - **/ + * This can be called from an LLD or iscsi_transport. + */ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) { transport_unregister_device(&conn->dev); @@ -690,7 +691,7 @@ iscsi_if_get_stats(struct iscsi_transpor * * This is called by HW iscsi LLDs to notify userpsace that its HW has * removed a session. - **/ + */ int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) { struct iscsi_internal *priv; @@ -751,7 +752,7 @@ EXPORT_SYMBOL_GPL(iscsi_if_destroy_sessi * * This is called by HW iscsi LLDs to notify userpsace that its HW has * created a session or a existing session is back in the logged in state. - **/ + */ int iscsi_if_create_session_done(struct iscsi_cls_conn *conn) { struct iscsi_internal *priv; diff -puN drivers/scsi/scsi_transport_sas.c~git-scsi-misc drivers/scsi/scsi_transport_sas.c --- a/drivers/scsi/scsi_transport_sas.c~git-scsi-misc +++ a/drivers/scsi/scsi_transport_sas.c @@ -323,7 +323,7 @@ static int do_sas_phy_delete(struct devi } /** - * sas_remove_children -- tear down a devices SAS data structures + * sas_remove_children - tear down a devices SAS data structures * @dev: device belonging to the sas object * * Removes all SAS PHYs and remote PHYs for a given object @@ -336,7 +336,7 @@ void sas_remove_children(struct device * EXPORT_SYMBOL(sas_remove_children); /** - * sas_remove_host -- tear down a Scsi_Host's SAS data structures + * sas_remove_host - tear down a Scsi_Host's SAS data structures * @shost: Scsi Host that is torn down * * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. @@ -577,7 +577,7 @@ static void sas_phy_release(struct devic } /** - * sas_phy_alloc -- allocates and initialize a SAS PHY structure + * sas_phy_alloc - allocates and initialize a SAS PHY structure * @parent: Parent device * @number: Phy index * @@ -618,7 +618,7 @@ struct sas_phy *sas_phy_alloc(struct dev EXPORT_SYMBOL(sas_phy_alloc); /** - * sas_phy_add -- add a SAS PHY to the device hierarchy + * sas_phy_add - add a SAS PHY to the device hierarchy * @phy: The PHY to be added * * Publishes a SAS PHY to the rest of the system. @@ -638,7 +638,7 @@ int sas_phy_add(struct sas_phy *phy) EXPORT_SYMBOL(sas_phy_add); /** - * sas_phy_free -- free a SAS PHY + * sas_phy_free - free a SAS PHY * @phy: SAS PHY to free * * Frees the specified SAS PHY. @@ -655,7 +655,7 @@ void sas_phy_free(struct sas_phy *phy) EXPORT_SYMBOL(sas_phy_free); /** - * sas_phy_delete -- remove SAS PHY + * sas_phy_delete - remove SAS PHY * @phy: SAS PHY to remove * * Removes the specified SAS PHY. If the SAS PHY has an @@ -677,7 +677,7 @@ sas_phy_delete(struct sas_phy *phy) EXPORT_SYMBOL(sas_phy_delete); /** - * scsi_is_sas_phy -- check if a struct device represents a SAS PHY + * scsi_is_sas_phy - check if a struct device represents a SAS PHY * @dev: device to check * * Returns: @@ -843,7 +843,6 @@ EXPORT_SYMBOL(sas_port_alloc_num); /** * sas_port_add - add a SAS port to the device hierarchy - * * @port: port to be added * * publishes a port to the rest of the system @@ -868,7 +867,7 @@ int sas_port_add(struct sas_port *port) EXPORT_SYMBOL(sas_port_add); /** - * sas_port_free -- free a SAS PORT + * sas_port_free - free a SAS PORT * @port: SAS PORT to free * * Frees the specified SAS PORT. @@ -885,7 +884,7 @@ void sas_port_free(struct sas_port *port EXPORT_SYMBOL(sas_port_free); /** - * sas_port_delete -- remove SAS PORT + * sas_port_delete - remove SAS PORT * @port: SAS PORT to remove * * Removes the specified SAS PORT. If the SAS PORT has an @@ -924,7 +923,7 @@ void sas_port_delete(struct sas_port *po EXPORT_SYMBOL(sas_port_delete); /** - * scsi_is_sas_port -- check if a struct device represents a SAS port + * scsi_is_sas_port - check if a struct device represents a SAS port * @dev: device to check * * Returns: @@ -1309,6 +1308,7 @@ static void sas_rphy_initialize(struct s /** * sas_end_device_alloc - allocate an rphy for an end device + * @parent: which port * * Allocates an SAS remote PHY structure, connected to @parent. * @@ -1345,6 +1345,8 @@ EXPORT_SYMBOL(sas_end_device_alloc); /** * sas_expander_alloc - allocate an rphy for an end device + * @parent: which port + * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE * * Allocates an SAS remote PHY structure, connected to @parent. * @@ -1383,7 +1385,7 @@ struct sas_rphy *sas_expander_alloc(stru EXPORT_SYMBOL(sas_expander_alloc); /** - * sas_rphy_add -- add a SAS remote PHY to the device hierarchy + * sas_rphy_add - add a SAS remote PHY to the device hierarchy * @rphy: The remote PHY to be added * * Publishes a SAS remote PHY to the rest of the system. @@ -1430,8 +1432,8 @@ int sas_rphy_add(struct sas_rphy *rphy) EXPORT_SYMBOL(sas_rphy_add); /** - * sas_rphy_free -- free a SAS remote PHY - * @rphy SAS remote PHY to free + * sas_rphy_free - free a SAS remote PHY + * @rphy: SAS remote PHY to free * * Frees the specified SAS remote PHY. * @@ -1459,7 +1461,7 @@ void sas_rphy_free(struct sas_rphy *rphy EXPORT_SYMBOL(sas_rphy_free); /** - * sas_rphy_delete -- remove and free SAS remote PHY + * sas_rphy_delete - remove and free SAS remote PHY * @rphy: SAS remote PHY to remove and free * * Removes the specified SAS remote PHY and frees it. @@ -1473,7 +1475,7 @@ sas_rphy_delete(struct sas_rphy *rphy) EXPORT_SYMBOL(sas_rphy_delete); /** - * sas_rphy_remove -- remove SAS remote PHY + * sas_rphy_remove - remove SAS remote PHY * @rphy: SAS remote phy to remove * * Removes the specified SAS remote PHY. @@ -1504,7 +1506,7 @@ sas_rphy_remove(struct sas_rphy *rphy) EXPORT_SYMBOL(sas_rphy_remove); /** - * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY + * scsi_is_sas_rphy - check if a struct device represents a SAS remote PHY * @dev: device to check * * Returns: @@ -1604,7 +1606,7 @@ static int sas_user_scan(struct Scsi_Hos SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1) /** - * sas_attach_transport -- instantiate SAS transport template + * sas_attach_transport - instantiate SAS transport template * @ft: SAS transport class function template */ struct scsi_transport_template * @@ -1715,7 +1717,7 @@ sas_attach_transport(struct sas_function EXPORT_SYMBOL(sas_attach_transport); /** - * sas_release_transport -- release SAS transport template instance + * sas_release_transport - release SAS transport template instance * @t: transport template instance */ void sas_release_transport(struct scsi_transport_template *t) diff -puN drivers/scsi/scsi_transport_srp.c~git-scsi-misc drivers/scsi/scsi_transport_srp.c --- a/drivers/scsi/scsi_transport_srp.c~git-scsi-misc +++ a/drivers/scsi/scsi_transport_srp.c @@ -185,11 +185,10 @@ static int srp_host_match(struct attribu /** * srp_rport_add - add a SRP remote port to the device hierarchy - * * @shost: scsi host the remote port is connected to. * @ids: The port id for the remote port. * - * publishes a port to the rest of the system + * Publishes a port to the rest of the system. */ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, struct srp_rport_identifiers *ids) @@ -242,8 +241,8 @@ struct srp_rport *srp_rport_add(struct S EXPORT_SYMBOL_GPL(srp_rport_add); /** - * srp_rport_del -- remove a SRP remote port - * @port: SRP remote port to remove + * srp_rport_del - remove a SRP remote port + * @rport: SRP remote port to remove * * Removes the specified SRP remote port. */ @@ -270,7 +269,7 @@ static int do_srp_rport_del(struct devic } /** - * srp_remove_host -- tear down a Scsi_Host's SRP data structures + * srp_remove_host - tear down a Scsi_Host's SRP data structures * @shost: Scsi Host that is torn down * * Removes all SRP remote ports for a given Scsi_Host. @@ -296,7 +295,7 @@ static int srp_it_nexus_response(struct } /** - * srp_attach_transport -- instantiate SRP transport template + * srp_attach_transport - instantiate SRP transport template * @ft: SRP transport class function template */ struct scsi_transport_template * @@ -336,7 +335,7 @@ srp_attach_transport(struct srp_function EXPORT_SYMBOL_GPL(srp_attach_transport); /** - * srp_release_transport -- release SRP transport template instance + * srp_release_transport - release SRP transport template instance * @t: transport template instance */ void srp_release_transport(struct scsi_transport_template *t) diff -puN drivers/scsi/scsicam.c~git-scsi-misc drivers/scsi/scsicam.c --- a/drivers/scsi/scsicam.c~git-scsi-misc +++ a/drivers/scsi/scsicam.c @@ -24,6 +24,14 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs); +/** + * scsi_bios_ptable - Read PC partition table out of first sector of device. + * @dev: from this device + * + * Description: Reads the first sector from the device and returns %0x42 bytes + * starting at offset %0x1be. + * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error. + */ unsigned char *scsi_bios_ptable(struct block_device *dev) { unsigned char *res = kmalloc(66, GFP_KERNEL); @@ -43,15 +51,17 @@ unsigned char *scsi_bios_ptable(struct b } EXPORT_SYMBOL(scsi_bios_ptable); -/* - * Function : int scsicam_bios_param (struct block_device *bdev, ector_t capacity, int *ip) +/** + * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors. + * @bdev: which device + * @capacity: size of the disk in sectors + * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders * - * Purpose : to determine the BIOS mapping used for a drive in a + * Description : determine the BIOS mapping/geometry used for a drive in a * SCSI-CAM system, storing the results in ip as required * by the HDIO_GETGEO ioctl(). * * Returns : -1 on failure, 0 on success. - * */ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) @@ -98,15 +108,18 @@ int scsicam_bios_param(struct block_devi } EXPORT_SYMBOL(scsicam_bios_param); -/* - * Function : static int scsi_partsize(unsigned char *buf, unsigned long - * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); +/** + * scsi_partsize - Parse cylinders/heads/sectors from PC partition table + * @buf: partition table, see scsi_bios_ptable() + * @capacity: size of the disk in sectors + * @cyls: put cylinders here + * @hds: put heads here + * @secs: put sectors here * - * Purpose : to determine the BIOS mapping used to create the partition + * Description: determine the BIOS mapping/geometry used to create the partition * table, storing the results in *cyls, *hds, and *secs * - * Returns : -1 on failure, 0 on success. - * + * Returns: -1 on failure, 0 on success. */ int scsi_partsize(unsigned char *buf, unsigned long capacity, @@ -194,7 +207,7 @@ EXPORT_SYMBOL(scsi_partsize); * * WORKING X3T9.2 * DRAFT 792D - * + * see http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf * * Revision 6 * 10-MAR-94 diff -puN drivers/scsi/sd.c~git-scsi-misc drivers/scsi/sd.c --- a/drivers/scsi/sd.c~git-scsi-misc +++ a/drivers/scsi/sd.c @@ -749,8 +749,11 @@ static int sd_media_changed(struct gendi * can deal with it then. It is only because of unrecoverable errors * that we would ever take a device offline in the first place. */ - if (!scsi_device_online(sdp)) - goto not_present; + if (!scsi_device_online(sdp)) { + set_media_not_present(sdkp); + retval = 1; + goto out; + } /* * Using TEST_UNIT_READY enables differentiation between drive with @@ -762,6 +765,7 @@ static int sd_media_changed(struct gendi * sd_revalidate() is called. */ retval = -ENODEV; + if (scsi_block_when_processing_errors(sdp)) retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES); @@ -771,8 +775,11 @@ static int sd_media_changed(struct gendi * and we will figure it out later once the drive is * available again. */ - if (retval) - goto not_present; + if (retval) { + set_media_not_present(sdkp); + retval = 1; + goto out; + } /* * For removable scsi disk we have to recognise the presence @@ -783,12 +790,11 @@ static int sd_media_changed(struct gendi retval = sdp->changed; sdp->changed = 0; - +out: + if (retval != sdkp->previous_state) + sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); + sdkp->previous_state = retval; return retval; - -not_present: - set_media_not_present(sdkp); - return 1; } static int sd_sync_cache(struct scsi_disk *sdkp) diff -puN drivers/scsi/seagate.c~git-scsi-misc /dev/null --- a/drivers/scsi/seagate.c +++ /dev/null @@ -1,1667 +0,0 @@ -/* - * seagate.c Copyright (C) 1992, 1993 Drew Eckhardt - * low level scsi driver for ST01/ST02, Future Domain TMC-885, - * TMC-950 by Drew Eckhardt - * - * Note : TMC-880 boards don't work because they have two bits in - * the status register flipped, I'll fix this "RSN" - * [why do I have strong feeling that above message is from 1993? :-) - * pavel@ucw.cz] - * - * This card does all the I/O via memory mapped I/O, so there is no need - * to check or allocate a region of the I/O address space. - */ - -/* 1996 - to use new read{b,w,l}, write{b,w,l}, and phys_to_virt - * macros, replaced assembler routines with C. There's probably a - * performance hit, but I only have a cdrom and can't tell. Define - * SEAGATE_USE_ASM if you want the old assembler code -- SJT - * - * 1998-jul-29 - created DPRINTK macros and made it work under - * linux 2.1.112, simplified some #defines etc. - * - * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to - * read the physical disk geometry, a bad mistake. Of course it doesn't - * matter much what geometry one invents, but on large disks it - * returned 256 (or more) heads, causing all kind of failures. - * Of course this means that people might see a different geometry now, - * so boot parameters may be necessary in some cases. - */ - -/* - * Configuration : - * To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE - * -DIRQ will override the default of 5. - * Note: You can now set these options from the kernel's "command line". - * The syntax is: - * - * st0x=ADDRESS,IRQ (for a Seagate controller) - * or: - * tmc8xx=ADDRESS,IRQ (for a TMC-8xx or TMC-950 controller) - * eg: - * tmc8xx=0xC8000,15 - * - * will configure the driver for a TMC-8xx style controller using IRQ 15 - * with a base address of 0xC8000. - * - * -DARBITRATE - * Will cause the host adapter to arbitrate for the - * bus for better SCSI-II compatibility, rather than just - * waiting for BUS FREE and then doing its thing. Should - * let us do one command per Lun when I integrate my - * reorganization changes into the distribution sources. - * - * -DDEBUG=65535 - * Will activate debug code. - * - * -DFAST or -DFAST32 - * Will use blind transfers where possible - * - * -DPARITY - * This will enable parity. - * - * -DSEAGATE_USE_ASM - * Will use older seagate assembly code. should be (very small amount) - * Faster. - * - * -DSLOW_RATE=50 - * Will allow compatibility with broken devices that don't - * handshake fast enough (ie, some CD ROM's) for the Seagate - * code. - * - * 50 is some number, It will let you specify a default - * transfer rate if handshaking isn't working correctly. - * - * -DOLDCNTDATASCEME There is a new sceme to set the CONTROL - * and DATA reigsters which complies more closely - * with the SCSI2 standard. This hopefully eliminates - * the need to swap the order these registers are - * 'messed' with. It makes the following two options - * obsolete. To reenable the old sceme define this. - * - * The following to options are patches from the SCSI.HOWTO - * - * -DSWAPSTAT This will swap the definitions for STAT_MSG and STAT_CD. - * - * -DSWAPCNTDATA This will swap the order that seagate.c messes with - * the CONTROL an DATA registers. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - - -#ifdef DEBUG -#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0) -#else -#define DPRINTK( when, msg... ) do { } while (0) -#define DEBUG 0 -#endif -#define DANY( msg... ) DPRINTK( 0xffff, msg ); - -#ifndef IRQ -#define IRQ 5 -#endif - -#ifdef FAST32 -#define FAST -#endif - -#undef LINKED /* Linked commands are currently broken! */ - -#if defined(OVERRIDE) && !defined(CONTROLLER) -#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type -#endif - -#ifndef __i386__ -#undef SEAGATE_USE_ASM -#endif - -/* - Thanks to Brian Antoine for the example code in his Messy-Loss ST-01 - driver, and Mitsugu Suzuki for information on the ST-01 - SCSI host. -*/ - -/* - CONTROL defines -*/ - -#define CMD_RST 0x01 -#define CMD_SEL 0x02 -#define CMD_BSY 0x04 -#define CMD_ATTN 0x08 -#define CMD_START_ARB 0x10 -#define CMD_EN_PARITY 0x20 -#define CMD_INTR 0x40 -#define CMD_DRVR_ENABLE 0x80 - -/* - STATUS -*/ -#ifdef SWAPSTAT -#define STAT_MSG 0x08 -#define STAT_CD 0x02 -#else -#define STAT_MSG 0x02 -#define STAT_CD 0x08 -#endif - -#define STAT_BSY 0x01 -#define STAT_IO 0x04 -#define STAT_REQ 0x10 -#define STAT_SEL 0x20 -#define STAT_PARITY 0x40 -#define STAT_ARB_CMPL 0x80 - -/* - REQUESTS -*/ - -#define REQ_MASK (STAT_CD | STAT_IO | STAT_MSG) -#define REQ_DATAOUT 0 -#define REQ_DATAIN STAT_IO -#define REQ_CMDOUT STAT_CD -#define REQ_STATIN (STAT_CD | STAT_IO) -#define REQ_MSGOUT (STAT_MSG | STAT_CD) -#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO) - -extern volatile int seagate_st0x_timeout; - -#ifdef PARITY -#define BASE_CMD CMD_EN_PARITY -#else -#define BASE_CMD 0 -#endif - -/* - Debugging code -*/ - -#define PHASE_BUS_FREE 1 -#define PHASE_ARBITRATION 2 -#define PHASE_SELECTION 4 -#define PHASE_DATAIN 8 -#define PHASE_DATAOUT 0x10 -#define PHASE_CMDOUT 0x20 -#define PHASE_MSGIN 0x40 -#define PHASE_MSGOUT 0x80 -#define PHASE_STATUSIN 0x100 -#define PHASE_ETC (PHASE_DATAIN | PHASE_DATAOUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN) -#define PRINT_COMMAND 0x200 -#define PHASE_EXIT 0x400 -#define PHASE_RESELECT 0x800 -#define DEBUG_FAST 0x1000 -#define DEBUG_SG 0x2000 -#define DEBUG_LINKED 0x4000 -#define DEBUG_BORKEN 0x8000 - -/* - * Control options - these are timeouts specified in .01 seconds. - */ - -/* 30, 20 work */ -#define ST0X_BUS_FREE_DELAY 25 -#define ST0X_SELECTION_DELAY 25 - -#define SEAGATE 1 /* these determine the type of the controller */ -#define FD 2 - -#define ST0X_ID_STR "Seagate ST-01/ST-02" -#define FD_ID_STR "TMC-8XX/TMC-950" - -static int internal_command (unsigned char target, unsigned char lun, - const void *cmnd, - void *buff, int bufflen, int reselect); - -static int incommand; /* set if arbitration has finished - and we are in some command phase. */ - -static unsigned int base_address = 0; /* Where the card ROM starts, used to - calculate memory mapped register - location. */ - -static void __iomem *st0x_cr_sr; /* control register write, status - register read. 256 bytes in - length. - Read is status of SCSI BUS, as per - STAT masks. */ - -static void __iomem *st0x_dr; /* data register, read write 256 - bytes in length. */ - -static volatile int st0x_aborted = 0; /* set when we are aborted, ie by a - time out, etc. */ - -static unsigned char controller_type = 0; /* set to SEAGATE for ST0x - boards or FD for TMC-8xx - boards */ -static int irq = IRQ; - -module_param(base_address, uint, 0); -module_param(controller_type, byte, 0); -module_param(irq, int, 0); -MODULE_LICENSE("GPL"); - - -#define retcode(result) (((result) << 16) | (message << 8) | status) -#define STATUS ((u8) readb(st0x_cr_sr)) -#define DATA ((u8) readb(st0x_dr)) -#define WRITE_CONTROL(d) { writeb((d), st0x_cr_sr); } -#define WRITE_DATA(d) { writeb((d), st0x_dr); } - -#ifndef OVERRIDE -static unsigned int seagate_bases[] = { - 0xc8000, 0xca000, 0xcc000, - 0xce000, 0xdc000, 0xde000 -}; - -typedef struct { - const unsigned char *signature; - unsigned offset; - unsigned length; - unsigned char type; -} Signature; - -static Signature __initdata signatures[] = { - {"ST01 v1.7 (C) Copyright 1987 Seagate", 15, 37, SEAGATE}, - {"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE}, - -/* - * The following two lines are NOT mistakes. One detects ROM revision - * 3.0.0, the other 3.2. Since seagate has only one type of SCSI adapter, - * and this is not going to change, the "SEAGATE" and "SCSI" together - * are probably "good enough" - */ - - {"SEAGATE SCSI BIOS ", 16, 17, SEAGATE}, - {"SEAGATE SCSI BIOS ", 17, 17, SEAGATE}, - -/* - * However, future domain makes several incompatible SCSI boards, so specific - * signatures must be used. - */ - - {"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD}, - {"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD}, - {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90", 5, 47, FD}, - {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90", 5, 47, FD}, - {"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD}, - {"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD}, - {"IBM F1 BIOS V1.1004/30/92", 5, 25, FD}, - {"FUTURE DOMAIN TMC-950", 5, 21, FD}, - /* Added for 2.2.16 by Matthias_Heidbrink@b.maus.de */ - {"IBM F1 V1.2009/22/93", 5, 25, FD}, -}; - -#define NUM_SIGNATURES ARRAY_SIZE(signatures) -#endif /* n OVERRIDE */ - -/* - * hostno stores the hostnumber, as told to us by the init routine. - */ - -static int hostno = -1; -static void seagate_reconnect_intr (int, void *); -static irqreturn_t do_seagate_reconnect_intr (int, void *); -static int seagate_st0x_bus_reset(struct scsi_cmnd *); - -#ifdef FAST -static int fast = 1; -#else -#define fast 0 -#endif - -#ifdef SLOW_RATE -/* - * Support for broken devices : - * The Seagate board has a handshaking problem. Namely, a lack - * thereof for slow devices. You can blast 600K/second through - * it if you are polling for each byte, more if you do a blind - * transfer. In the first case, with a fast device, REQ will - * transition high-low or high-low-high before your loop restarts - * and you'll have no problems. In the second case, the board - * will insert wait states for up to 13.2 usecs for REQ to - * transition low->high, and everything will work. - * - * However, there's nothing in the state machine that says - * you *HAVE* to see a high-low-high set of transitions before - * sending the next byte, and slow things like the Trantor CD ROMS - * will break because of this. - * - * So, we need to slow things down, which isn't as simple as it - * seems. We can't slow things down period, because then people - * who don't recompile their kernels will shoot me for ruining - * their performance. We need to do it on a case per case basis. - * - * The best for performance will be to, only for borken devices - * (this is stored on a per-target basis in the scsi_devices array) - * - * Wait for a low->high transition before continuing with that - * transfer. If we timeout, continue anyways. We don't need - * a long timeout, because REQ should only be asserted until the - * corresponding ACK is received and processed. - * - * Note that we can't use the system timer for this, because of - * resolution, and we *really* can't use the timer chip since - * gettimeofday() and the beeper routines use that. So, - * the best thing for us to do will be to calibrate a timing - * loop in the initialization code using the timer chip before - * gettimeofday() can screw with it. - * - * FIXME: this is broken (not borken :-). Empty loop costs less than - * loop with ISA access in it! -- pavel@ucw.cz - */ - -static int borken_calibration = 0; - -static void __init borken_init (void) -{ - register int count = 0, start = jiffies + 1, stop = start + 25; - - /* FIXME: There may be a better approach, this is a straight port for - now */ - preempt_disable(); - while (time_before (jiffies, start)) - cpu_relax(); - for (; time_before (jiffies, stop); ++count) - cpu_relax(); - preempt_enable(); - -/* - * Ok, we now have a count for .25 seconds. Convert to a - * count per second and divide by transfer rate in K. */ - - borken_calibration = (count * 4) / (SLOW_RATE * 1024); - - if (borken_calibration < 1) - borken_calibration = 1; -} - -static inline void borken_wait (void) -{ - register int count; - - for (count = borken_calibration; count && (STATUS & STAT_REQ); --count) - cpu_relax(); - -#if (DEBUG & DEBUG_BORKEN) - if (count) - printk ("scsi%d : borken timeout\n", hostno); -#endif -} - -#endif /* def SLOW_RATE */ - -/* These beasts only live on ISA, and ISA means 8MHz. Each ULOOP() - * contains at least one ISA access, which takes more than 0.125 - * usec. So if we loop 8 times time in usec, we are safe. - */ - -#define ULOOP( i ) for (clock = i*8;;) -#define TIMEOUT (!(clock--)) - -static int __init seagate_st0x_detect (struct scsi_host_template * tpnt) -{ - struct Scsi_Host *instance; - int i, j; - unsigned long cr, dr; - - tpnt->proc_name = "seagate"; -/* - * First, we try for the manual override. - */ - DANY ("Autodetecting ST0x / TMC-8xx\n"); - - if (hostno != -1) { - printk (KERN_ERR "seagate_st0x_detect() called twice?!\n"); - return 0; - } - -/* If the user specified the controller type from the command line, - controller_type will be non-zero, so don't try to detect one */ - - if (!controller_type) { -#ifdef OVERRIDE - base_address = OVERRIDE; - controller_type = CONTROLLER; - - DANY ("Base address overridden to %x, controller type is %s\n", - base_address, - controller_type == SEAGATE ? "SEAGATE" : "FD"); -#else /* OVERRIDE */ -/* - * To detect this card, we simply look for the signature - * from the BIOS version notice in all the possible locations - * of the ROM's. This has a nice side effect of not trashing - * any register locations that might be used by something else. - * - * XXX - note that we probably should be probing the address - * space for the on-board RAM instead. - */ - - for (i = 0; i < ARRAY_SIZE(seagate_bases); ++i) { - void __iomem *p = ioremap(seagate_bases[i], 0x2000); - if (!p) - continue; - for (j = 0; j < NUM_SIGNATURES; ++j) - if (check_signature(p + signatures[j].offset, signatures[j].signature, signatures[j].length)) { - base_address = seagate_bases[i]; - controller_type = signatures[j].type; - break; - } - iounmap(p); - } -#endif /* OVERRIDE */ - } - /* (! controller_type) */ - tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6; - tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR; - - if (!base_address) { - printk(KERN_INFO "seagate: ST0x/TMC-8xx not detected.\n"); - return 0; - } - - cr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00); - dr = cr + 0x200; - st0x_cr_sr = ioremap(cr, 0x100); - st0x_dr = ioremap(dr, 0x100); - - DANY("%s detected. Base address = %x, cr = %x, dr = %x\n", - tpnt->name, base_address, cr, dr); - - /* - * At all times, we will use IRQ 5. Should also check for IRQ3 - * if we lose our first interrupt. - */ - instance = scsi_register (tpnt, 0); - if (instance == NULL) - return 0; - - hostno = instance->host_no; - if (request_irq (irq, do_seagate_reconnect_intr, IRQF_DISABLED, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) { - printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq); - return 0; - } - instance->irq = irq; - instance->io_port = base_address; -#ifdef SLOW_RATE - printk(KERN_INFO "Calibrating borken timer... "); - borken_init(); - printk(" %d cycles per transfer\n", borken_calibration); -#endif - printk (KERN_INFO "This is one second... "); - { - int clock; - ULOOP (1 * 1000 * 1000) { - STATUS; - if (TIMEOUT) - break; - } - } - - printk ("done, %s options:" -#ifdef ARBITRATE - " ARBITRATE" -#endif -#if DEBUG - " DEBUG" -#endif -#ifdef FAST - " FAST" -#ifdef FAST32 - "32" -#endif -#endif -#ifdef LINKED - " LINKED" -#endif -#ifdef PARITY - " PARITY" -#endif -#ifdef SEAGATE_USE_ASM - " SEAGATE_USE_ASM" -#endif -#ifdef SLOW_RATE - " SLOW_RATE" -#endif -#ifdef SWAPSTAT - " SWAPSTAT" -#endif -#ifdef SWAPCNTDATA - " SWAPCNTDATA" -#endif - "\n", tpnt->name); - return 1; -} - -static const char *seagate_st0x_info (struct Scsi_Host *shpnt) -{ - static char buffer[64]; - - snprintf(buffer, 64, "%s at irq %d, address 0x%05X", - (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR, - irq, base_address); - return buffer; -} - -/* - * These are our saved pointers for the outstanding command that is - * waiting for a reconnect - */ - -static unsigned char current_target, current_lun; -static unsigned char *current_cmnd, *current_data; -static int current_nobuffs; -static struct scatterlist *current_buffer; -static int current_bufflen; - -#ifdef LINKED -/* - * linked_connected indicates whether or not we are currently connected to - * linked_target, linked_lun and in an INFORMATION TRANSFER phase, - * using linked commands. - */ - -static int linked_connected = 0; -static unsigned char linked_target, linked_lun; -#endif - -static void (*done_fn) (struct scsi_cmnd *) = NULL; -static struct scsi_cmnd *SCint = NULL; - -/* - * These control whether or not disconnect / reconnect will be attempted, - * or are being attempted. - */ - -#define NO_RECONNECT 0 -#define RECONNECT_NOW 1 -#define CAN_RECONNECT 2 - -/* - * LINKED_RIGHT indicates that we are currently connected to the correct target - * for this command, LINKED_WRONG indicates that we are connected to the wrong - * target. Note that these imply CAN_RECONNECT and require defined(LINKED). - */ - -#define LINKED_RIGHT 3 -#define LINKED_WRONG 4 - -/* - * This determines if we are expecting to reconnect or not. - */ - -static int should_reconnect = 0; - -/* - * The seagate_reconnect_intr routine is called when a target reselects the - * host adapter. This occurs on the interrupt triggered by the target - * asserting SEL. - */ - -static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave (dev->host_lock, flags); - seagate_reconnect_intr (irq, dev_id); - spin_unlock_irqrestore (dev->host_lock, flags); - return IRQ_HANDLED; -} - -static void seagate_reconnect_intr (int irq, void *dev_id) -{ - int temp; - struct scsi_cmnd *SCtmp; - - DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno); - - if (!should_reconnect) - printk(KERN_WARNING "scsi%d: unexpected interrupt.\n", hostno); - else { - should_reconnect = 0; - - DPRINTK (PHASE_RESELECT, "scsi%d : internal_command(%d, %08x, %08x, RECONNECT_NOW\n", - hostno, current_target, current_data, current_bufflen); - - temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW); - - if (msg_byte(temp) != DISCONNECT) { - if (done_fn) { - DPRINTK(PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno, hostno, temp); - if (!SCint) - panic ("SCint == NULL in seagate"); - SCtmp = SCint; - SCint = NULL; - SCtmp->result = temp; - done_fn(SCtmp); - } else - printk(KERN_ERR "done_fn() not defined.\n"); - } - } -} - -/* - * The seagate_st0x_queue_command() function provides a queued interface - * to the seagate SCSI driver. Basically, it just passes control onto the - * seagate_command() function, after fixing it so that the done_fn() - * is set to the one passed to the function. We have to be very careful, - * because there are some commands on some devices that do not disconnect, - * and if we simply call the done_fn when the command is done then another - * command is started and queue_command is called again... We end up - * overflowing the kernel stack, and this tends not to be such a good idea. - */ - -static int recursion_depth = 0; - -static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt, - void (*done) (struct scsi_cmnd *)) -{ - int result, reconnect; - struct scsi_cmnd *SCtmp; - - DANY ("seagate: que_command"); - done_fn = done; - current_target = SCpnt->device->id; - current_lun = SCpnt->device->lun; - current_cmnd = SCpnt->cmnd; - current_data = (unsigned char *) SCpnt->request_buffer; - current_bufflen = SCpnt->request_bufflen; - SCint = SCpnt; - if (recursion_depth) - return 1; - recursion_depth++; - do { -#ifdef LINKED - /* - * Set linked command bit in control field of SCSI command. - */ - - current_cmnd[SCpnt->cmd_len] |= 0x01; - if (linked_connected) { - DPRINTK (DEBUG_LINKED, "scsi%d : using linked commands, current I_T_L nexus is ", hostno); - if (linked_target == current_target && linked_lun == current_lun) - { - DPRINTK(DEBUG_LINKED, "correct\n"); - reconnect = LINKED_RIGHT; - } else { - DPRINTK(DEBUG_LINKED, "incorrect\n"); - reconnect = LINKED_WRONG; - } - } else -#endif /* LINKED */ - reconnect = CAN_RECONNECT; - - result = internal_command(SCint->device->id, SCint->device->lun, SCint->cmnd, - SCint->request_buffer, SCint->request_bufflen, reconnect); - if (msg_byte(result) == DISCONNECT) - break; - SCtmp = SCint; - SCint = NULL; - SCtmp->result = result; - done_fn(SCtmp); - } - while (SCint); - recursion_depth--; - return 0; -} - -static int internal_command (unsigned char target, unsigned char lun, - const void *cmnd, void *buff, int bufflen, int reselect) -{ - unsigned char *data = NULL; - struct scatterlist *buffer = NULL; - int clock, temp, nobuffs = 0, done = 0, len = 0; -#if DEBUG - int transfered = 0, phase = 0, newphase; -#endif - register unsigned char status_read; - unsigned char tmp_data, tmp_control, status = 0, message = 0; - unsigned transfersize = 0, underflow = 0; -#ifdef SLOW_RATE - int borken = (int) SCint->device->borken; /* Does the current target require - Very Slow I/O ? */ -#endif - - incommand = 0; - st0x_aborted = 0; - -#if (DEBUG & PRINT_COMMAND) - printk("scsi%d : target = %d, command = ", hostno, target); - __scsi_print_command((unsigned char *) cmnd); -#endif - -#if (DEBUG & PHASE_RESELECT) - switch (reselect) { - case RECONNECT_NOW: - printk("scsi%d : reconnecting\n", hostno); - break; -#ifdef LINKED - case LINKED_RIGHT: - printk("scsi%d : connected, can reconnect\n", hostno); - break; - case LINKED_WRONG: - printk("scsi%d : connected to wrong target, can reconnect\n", - hostno); - break; -#endif - case CAN_RECONNECT: - printk("scsi%d : allowed to reconnect\n", hostno); - break; - default: - printk("scsi%d : not allowed to reconnect\n", hostno); - } -#endif - - if (target == (controller_type == SEAGATE ? 7 : 6)) - return DID_BAD_TARGET; - - /* - * We work it differently depending on if this is is "the first time," - * or a reconnect. If this is a reselect phase, then SEL will - * be asserted, and we must skip selection / arbitration phases. - */ - - switch (reselect) { - case RECONNECT_NOW: - DPRINTK (PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno); - /* - * At this point, we should find the logical or of our ID - * and the original target's ID on the BUS, with BSY, SEL, - * and I/O signals asserted. - * - * After ARBITRATION phase is completed, only SEL, BSY, - * and the target ID are asserted. A valid initiator ID - * is not on the bus until IO is asserted, so we must wait - * for that. - */ - ULOOP (100 * 1000) { - temp = STATUS; - if ((temp & STAT_IO) && !(temp & STAT_BSY)) - break; - if (TIMEOUT) { - DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for IO .\n", hostno); - return (DID_BAD_INTR << 16); - } - } - - /* - * After I/O is asserted by the target, we can read our ID - * and its ID off of the BUS. - */ - - if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) { - DPRINTK (PHASE_RESELECT, "scsi%d : detected reconnect request to different target.\n\tData bus = %d\n", hostno, temp); - return (DID_BAD_INTR << 16); - } - - if (!(temp & (1 << current_target))) { - printk(KERN_WARNING "scsi%d : Unexpected reselect interrupt. Data bus = %d\n", hostno, temp); - return (DID_BAD_INTR << 16); - } - - buffer = current_buffer; - cmnd = current_cmnd; /* WDE add */ - data = current_data; /* WDE add */ - len = current_bufflen; /* WDE add */ - nobuffs = current_nobuffs; - - /* - * We have determined that we have been selected. At this - * point, we must respond to the reselection by asserting - * BSY ourselves - */ - -#if 1 - WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY); -#else - WRITE_CONTROL (BASE_CMD | CMD_BSY); -#endif - - /* - * The target will drop SEL, and raise BSY, at which time - * we must drop BSY. - */ - - ULOOP (100 * 1000) { - if (!(STATUS & STAT_SEL)) - break; - if (TIMEOUT) { - WRITE_CONTROL (BASE_CMD | CMD_INTR); - DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno); - return (DID_BAD_INTR << 16); - } - } - WRITE_CONTROL (BASE_CMD); - /* - * At this point, we have connected with the target - * and can get on with our lives. - */ - break; - case CAN_RECONNECT: -#ifdef LINKED - /* - * This is a bletcherous hack, just as bad as the Unix #! - * interpreter stuff. If it turns out we are using the wrong - * I_T_L nexus, the easiest way to deal with it is to go into - * our INFORMATION TRANSFER PHASE code, send a ABORT - * message on MESSAGE OUT phase, and then loop back to here. - */ -connect_loop: -#endif - DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno); - - /* - * BUS FREE PHASE - * - * On entry, we make sure that the BUS is in a BUS FREE - * phase, by insuring that both BSY and SEL are low for - * at least one bus settle delay. Several reads help - * eliminate wire glitch. - */ - -#ifndef ARBITRATE -#error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock. - clock = jiffies + ST0X_BUS_FREE_DELAY; - - while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && time_before (jiffies, clock)) - cpu_relax(); - - if (time_after (jiffies, clock)) - return retcode (DID_BUS_BUSY); - else if (st0x_aborted) - return retcode (st0x_aborted); -#endif - DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno); - - clock = jiffies + ST0X_SELECTION_DELAY; - - /* - * Arbitration/selection procedure : - * 1. Disable drivers - * 2. Write HOST adapter address bit - * 3. Set start arbitration. - * 4. We get either ARBITRATION COMPLETE or SELECT at this - * point. - * 5. OR our ID and targets on bus. - * 6. Enable SCSI drivers and asserted SEL and ATTN - */ - -#ifdef ARBITRATE - /* FIXME: verify host lock is always held here */ - WRITE_CONTROL(0); - WRITE_DATA((controller_type == SEAGATE) ? 0x80 : 0x40); - WRITE_CONTROL(CMD_START_ARB); - - ULOOP (ST0X_SELECTION_DELAY * 10000) { - status_read = STATUS; - if (status_read & STAT_ARB_CMPL) - break; - if (st0x_aborted) /* FIXME: What? We are going to do something even after abort? */ - break; - if (TIMEOUT || (status_read & STAT_SEL)) { - printk(KERN_WARNING "scsi%d : arbitration lost or timeout.\n", hostno); - WRITE_CONTROL (BASE_CMD); - return retcode (DID_NO_CONNECT); - } - } - DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno); -#endif - - /* - * When the SCSI device decides that we're gawking at it, - * it will respond by asserting BUSY on the bus. - * - * Note : the Seagate ST-01/02 product manual says that we - * should twiddle the DATA register before the control - * register. However, this does not work reliably so we do - * it the other way around. - * - * Probably could be a problem with arbitration too, we - * really should try this with a SCSI protocol or logic - * analyzer to see what is going on. - */ - tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40)); - tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0); - - /* FIXME: verify host lock is always held here */ -#ifdef OLDCNTDATASCEME -#ifdef SWAPCNTDATA - WRITE_CONTROL (tmp_control); - WRITE_DATA (tmp_data); -#else - WRITE_DATA (tmp_data); - WRITE_CONTROL (tmp_control); -#endif -#else - tmp_control ^= CMD_BSY; /* This is guesswork. What used to be in driver */ - WRITE_CONTROL (tmp_control); /* could never work: it sent data into control */ - WRITE_DATA (tmp_data); /* register and control info into data. Hopefully */ - tmp_control ^= CMD_BSY; /* fixed, but order of first two may be wrong. */ - WRITE_CONTROL (tmp_control); /* -- pavel@ucw.cz */ -#endif - - ULOOP (250 * 1000) { - if (st0x_aborted) { - /* - * If we have been aborted, and we have a - * command in progress, IE the target - * still has BSY asserted, then we will - * reset the bus, and notify the midlevel - * driver to expect sense. - */ - - WRITE_CONTROL (BASE_CMD); - if (STATUS & STAT_BSY) { - printk(KERN_WARNING "scsi%d : BST asserted after we've been aborted.\n", hostno); - seagate_st0x_bus_reset(NULL); - return retcode (DID_RESET); - } - return retcode (st0x_aborted); - } - if (STATUS & STAT_BSY) - break; - if (TIMEOUT) { - DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS); - return retcode (DID_NO_CONNECT); - } - } - - /* Establish current pointers. Take into account scatter / gather */ - - if ((nobuffs = SCint->use_sg)) { -#if (DEBUG & DEBUG_SG) - { - int i; - printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs); - for (i = 0; i < nobuffs; ++i) - printk("scsi%d : buffer %d address = %p length = %d\n", - hostno, i, - sg_virt(&buffer[i]), - buffer[i].length); - } -#endif - - buffer = (struct scatterlist *) SCint->request_buffer; - len = buffer->length; - data = sg_virt(buffer); - } else { - DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno); - buffer = NULL; - len = SCint->request_bufflen; - data = (unsigned char *) SCint->request_buffer; - } - - DPRINTK (PHASE_DATAIN | PHASE_DATAOUT, "scsi%d : len = %d\n", - hostno, len); - - break; -#ifdef LINKED - case LINKED_RIGHT: - break; - case LINKED_WRONG: - break; -#endif - } /* end of switch(reselect) */ - - /* - * There are several conditions under which we wish to send a message : - * 1. When we are allowing disconnect / reconnect, and need to - * establish the I_T_L nexus via an IDENTIFY with the DiscPriv bit - * set. - * - * 2. When we are doing linked commands, are have the wrong I_T_L - * nexus established and want to send an ABORT message. - */ - - /* GCC does not like an ifdef inside a macro, so do it the hard way. */ -#ifdef LINKED - WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT)|| (reselect == LINKED_WRONG))? CMD_ATTN : 0)); -#else - WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT))? CMD_ATTN : 0)); -#endif - - /* - * INFORMATION TRANSFER PHASE - * - * The nasty looking read / write inline assembler loops we use for - * DATAIN and DATAOUT phases are approximately 4-5 times as fast as - * the 'C' versions - since we're moving 1024 bytes of data, this - * really adds up. - * - * SJT: The nasty-looking assembler is gone, so it's slower. - * - */ - - DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno); - - incommand = 1; - transfersize = SCint->transfersize; - underflow = SCint->underflow; - - /* - * Now, we poll the device for status information, - * and handle any requests it makes. Note that since we are unsure - * of how much data will be flowing across the system, etc and - * cannot make reasonable timeouts, that we will instead have the - * midlevel driver handle any timeouts that occur in this phase. - */ - - while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) { -#ifdef PARITY - if (status_read & STAT_PARITY) { - printk(KERN_ERR "scsi%d : got parity error\n", hostno); - st0x_aborted = DID_PARITY; - } -#endif - if (status_read & STAT_REQ) { -#if ((DEBUG & PHASE_ETC) == PHASE_ETC) - if ((newphase = (status_read & REQ_MASK)) != phase) { - phase = newphase; - switch (phase) { - case REQ_DATAOUT: - printk ("scsi%d : phase = DATA OUT\n", hostno); - break; - case REQ_DATAIN: - printk ("scsi%d : phase = DATA IN\n", hostno); - break; - case REQ_CMDOUT: - printk - ("scsi%d : phase = COMMAND OUT\n", hostno); - break; - case REQ_STATIN: - printk ("scsi%d : phase = STATUS IN\n", hostno); - break; - case REQ_MSGOUT: - printk - ("scsi%d : phase = MESSAGE OUT\n", hostno); - break; - case REQ_MSGIN: - printk ("scsi%d : phase = MESSAGE IN\n", hostno); - break; - default: - printk ("scsi%d : phase = UNKNOWN\n", hostno); - st0x_aborted = DID_ERROR; - } - } -#endif - switch (status_read & REQ_MASK) { - case REQ_DATAOUT: - /* - * If we are in fast mode, then we simply splat - * the data out in word-sized chunks as fast as - * we can. - */ - - if (!len) { -#if 0 - printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun); - st0x_aborted = DID_ERROR; - fast = 0; -#endif - break; - } - - if (fast && transfersize - && !(len % transfersize) - && (len >= transfersize) -#ifdef FAST32 - && !(transfersize % 4) -#endif - ) { - DPRINTK (DEBUG_FAST, - "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" - " len = %d, data = %08x\n", - hostno, SCint->underflow, - SCint->transfersize, len, - data); - - /* SJT: Start. Fast Write */ -#ifdef SEAGATE_USE_ASM - __asm__ ("cld\n\t" -#ifdef FAST32 - "shr $2, %%ecx\n\t" - "1:\t" - "lodsl\n\t" - "movl %%eax, (%%edi)\n\t" -#else - "1:\t" - "lodsb\n\t" - "movb %%al, (%%edi)\n\t" -#endif - "loop 1b;" - /* output */ : - /* input */ :"D" (st0x_dr), - "S" - (data), - "c" (SCint->transfersize) -/* clobbered */ - : "eax", "ecx", - "esi"); -#else /* SEAGATE_USE_ASM */ - memcpy_toio(st0x_dr, data, transfersize); -#endif /* SEAGATE_USE_ASM */ -/* SJT: End */ - len -= transfersize; - data += transfersize; - DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data); - } else { - /* - * We loop as long as we are in a - * data out phase, there is data to - * send, and BSY is still active. - */ - -/* SJT: Start. Slow Write. */ -#ifdef SEAGATE_USE_ASM - - int __dummy_1, __dummy_2; - -/* - * We loop as long as we are in a data out phase, there is data to send, - * and BSY is still active. - */ -/* Local variables : len = ecx , data = esi, - st0x_cr_sr = ebx, st0x_dr = edi -*/ - __asm__ ( - /* Test for any data here at all. */ - "orl %%ecx, %%ecx\n\t" - "jz 2f\n\t" "cld\n\t" -/* "movl st0x_cr_sr, %%ebx\n\t" */ -/* "movl st0x_dr, %%edi\n\t" */ - "1:\t" - "movb (%%ebx), %%al\n\t" - /* Test for BSY */ - "test $1, %%al\n\t" - "jz 2f\n\t" - /* Test for data out phase - STATUS & REQ_MASK should be - REQ_DATAOUT, which is 0. */ - "test $0xe, %%al\n\t" - "jnz 2f\n\t" - /* Test for REQ */ - "test $0x10, %%al\n\t" - "jz 1b\n\t" - "lodsb\n\t" - "movb %%al, (%%edi)\n\t" - "loop 1b\n\t" "2:\n" - /* output */ :"=S" (data), "=c" (len), - "=b" - (__dummy_1), - "=D" (__dummy_2) -/* input */ - : "0" (data), "1" (len), - "2" (st0x_cr_sr), - "3" (st0x_dr) -/* clobbered */ - : "eax"); -#else /* SEAGATE_USE_ASM */ - while (len) { - unsigned char stat; - - stat = STATUS; - if (!(stat & STAT_BSY) - || ((stat & REQ_MASK) != - REQ_DATAOUT)) - break; - if (stat & STAT_REQ) { - WRITE_DATA (*data++); - --len; - } - } -#endif /* SEAGATE_USE_ASM */ -/* SJT: End. */ - } - - if (!len && nobuffs) { - --nobuffs; - ++buffer; - len = buffer->length; - data = sg_virt(buffer); - DPRINTK (DEBUG_SG, - "scsi%d : next scatter-gather buffer len = %d address = %08x\n", - hostno, len, data); - } - break; - - case REQ_DATAIN: -#ifdef SLOW_RATE - if (borken) { -#if (DEBUG & (PHASE_DATAIN)) - transfered += len; -#endif - for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) { - *data++ = DATA; - borken_wait(); - } -#if (DEBUG & (PHASE_DATAIN)) - transfered -= len; -#endif - } else -#endif - - if (fast && transfersize - && !(len % transfersize) - && (len >= transfersize) -#ifdef FAST32 - && !(transfersize % 4) -#endif - ) { - DPRINTK (DEBUG_FAST, - "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" - " len = %d, data = %08x\n", - hostno, SCint->underflow, - SCint->transfersize, len, - data); - -/* SJT: Start. Fast Read */ -#ifdef SEAGATE_USE_ASM - __asm__ ("cld\n\t" -#ifdef FAST32 - "shr $2, %%ecx\n\t" - "1:\t" - "movl (%%esi), %%eax\n\t" - "stosl\n\t" -#else - "1:\t" - "movb (%%esi), %%al\n\t" - "stosb\n\t" -#endif - "loop 1b\n\t" - /* output */ : - /* input */ :"S" (st0x_dr), - "D" - (data), - "c" (SCint->transfersize) -/* clobbered */ - : "eax", "ecx", - "edi"); -#else /* SEAGATE_USE_ASM */ - memcpy_fromio(data, st0x_dr, len); -#endif /* SEAGATE_USE_ASM */ -/* SJT: End */ - len -= transfersize; - data += transfersize; -#if (DEBUG & PHASE_DATAIN) - printk ("scsi%d: transfered += %d\n", hostno, transfersize); - transfered += transfersize; -#endif - - DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data); - } else { - -#if (DEBUG & PHASE_DATAIN) - printk ("scsi%d: transfered += %d\n", hostno, len); - transfered += len; /* Assume we'll transfer it all, then - subtract what we *didn't* transfer */ -#endif - -/* - * We loop as long as we are in a data in phase, there is room to read, - * and BSY is still active - */ - -/* SJT: Start. */ -#ifdef SEAGATE_USE_ASM - - int __dummy_3, __dummy_4; - -/* Dummy clobbering variables for the new gcc-2.95 */ - -/* - * We loop as long as we are in a data in phase, there is room to read, - * and BSY is still active - */ - /* Local variables : ecx = len, edi = data - esi = st0x_cr_sr, ebx = st0x_dr */ - __asm__ ( - /* Test for room to read */ - "orl %%ecx, %%ecx\n\t" - "jz 2f\n\t" "cld\n\t" -/* "movl st0x_cr_sr, %%esi\n\t" */ -/* "movl st0x_dr, %%ebx\n\t" */ - "1:\t" - "movb (%%esi), %%al\n\t" - /* Test for BSY */ - "test $1, %%al\n\t" - "jz 2f\n\t" - /* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, - = STAT_IO, which is 4. */ - "movb $0xe, %%ah\n\t" - "andb %%al, %%ah\n\t" - "cmpb $0x04, %%ah\n\t" - "jne 2f\n\t" - /* Test for REQ */ - "test $0x10, %%al\n\t" - "jz 1b\n\t" - "movb (%%ebx), %%al\n\t" - "stosb\n\t" - "loop 1b\n\t" "2:\n" - /* output */ :"=D" (data), "=c" (len), - "=S" - (__dummy_3), - "=b" (__dummy_4) -/* input */ - : "0" (data), "1" (len), - "2" (st0x_cr_sr), - "3" (st0x_dr) -/* clobbered */ - : "eax"); -#else /* SEAGATE_USE_ASM */ - while (len) { - unsigned char stat; - - stat = STATUS; - if (!(stat & STAT_BSY) - || ((stat & REQ_MASK) != - REQ_DATAIN)) - break; - if (stat & STAT_REQ) { - *data++ = DATA; - --len; - } - } -#endif /* SEAGATE_USE_ASM */ -/* SJT: End. */ -#if (DEBUG & PHASE_DATAIN) - printk ("scsi%d: transfered -= %d\n", hostno, len); - transfered -= len; /* Since we assumed all of Len got * - transfered, correct our mistake */ -#endif - } - - if (!len && nobuffs) { - --nobuffs; - ++buffer; - len = buffer->length; - data = sg_virt(buffer); - DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data); - } - break; - - case REQ_CMDOUT: - while (((status_read = STATUS) & STAT_BSY) && - ((status_read & REQ_MASK) == REQ_CMDOUT)) - if (status_read & STAT_REQ) { - WRITE_DATA (*(const unsigned char *) cmnd); - cmnd = 1 + (const unsigned char *)cmnd; -#ifdef SLOW_RATE - if (borken) - borken_wait (); -#endif - } - break; - - case REQ_STATIN: - status = DATA; - break; - - case REQ_MSGOUT: - /* - * We can only have sent a MSG OUT if we - * requested to do this by raising ATTN. - * So, we must drop ATTN. - */ - WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE); - /* - * If we are reconnecting, then we must - * send an IDENTIFY message in response - * to MSGOUT. - */ - switch (reselect) { - case CAN_RECONNECT: - WRITE_DATA (IDENTIFY (1, lun)); - DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno); - break; -#ifdef LINKED - case LINKED_WRONG: - WRITE_DATA (ABORT); - linked_connected = 0; - reselect = CAN_RECONNECT; - goto connect_loop; - DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno); -#endif /* LINKED */ - DPRINTK (DEBUG_LINKED, "correct\n"); - default: - WRITE_DATA (NOP); - printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target); - } - break; - - case REQ_MSGIN: - switch (message = DATA) { - case DISCONNECT: - DANY("seagate: deciding to disconnect\n"); - should_reconnect = 1; - current_data = data; /* WDE add */ - current_buffer = buffer; - current_bufflen = len; /* WDE add */ - current_nobuffs = nobuffs; -#ifdef LINKED - linked_connected = 0; -#endif - done = 1; - DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno); - break; - -#ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: -#endif - case COMMAND_COMPLETE: - /* - * Note : we should check for underflow here. - */ - DPRINTK(PHASE_MSGIN, "scsi%d : command complete.\n", hostno); - done = 1; - break; - case ABORT: - DPRINTK(PHASE_MSGIN, "scsi%d : abort message.\n", hostno); - done = 1; - break; - case SAVE_POINTERS: - current_buffer = buffer; - current_bufflen = len; /* WDE add */ - current_data = data; /* WDE mod */ - current_nobuffs = nobuffs; - DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno); - break; - case RESTORE_POINTERS: - buffer = current_buffer; - cmnd = current_cmnd; - data = current_data; /* WDE mod */ - len = current_bufflen; - nobuffs = current_nobuffs; - DPRINTK(PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno); - break; - default: - - /* - * IDENTIFY distinguishes itself - * from the other messages by - * setting the high bit. - * - * Note : we need to handle at - * least one outstanding command - * per LUN, and need to hash the - * SCSI command for that I_T_L - * nexus based on the known ID - * (at this point) and LUN. - */ - - if (message & 0x80) { - DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7); - } else { - /* - * We should go into a - * MESSAGE OUT phase, and - * send a MESSAGE_REJECT - * if we run into a message - * that we don't like. The - * seagate driver needs - * some serious - * restructuring first - * though. - */ - DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target); - } - } - break; - default: - printk(KERN_ERR "scsi%d : unknown phase.\n", hostno); - st0x_aborted = DID_ERROR; - } /* end of switch (status_read & REQ_MASK) */ -#ifdef SLOW_RATE - /* - * I really don't care to deal with borken devices in - * each single byte transfer case (ie, message in, - * message out, status), so I'll do the wait here if - * necessary. - */ - if(borken) - borken_wait(); -#endif - - } /* if(status_read & STAT_REQ) ends */ - } /* while(((status_read = STATUS)...) ends */ - - DPRINTK(PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered); - -#if (DEBUG & PHASE_EXIT) -#if 0 /* Doesn't work for scatter/gather */ - printk("Buffer : \n"); - for(i = 0; i < 20; ++i) - printk("%02x ", ((unsigned char *) data)[i]); /* WDE mod */ - printk("\n"); -#endif - printk("scsi%d : status = ", hostno); - scsi_print_status(status); - printk(" message = %02x\n", message); -#endif - - /* We shouldn't reach this until *after* BSY has been deasserted */ - -#ifdef LINKED - else - { - /* - * Fix the message byte so that unsuspecting high level drivers - * don't puke when they see a LINKED COMMAND message in place of - * the COMMAND COMPLETE they may be expecting. Shouldn't be - * necessary, but it's better to be on the safe side. - * - * A non LINKED* message byte will indicate that the command - * completed, and we are now disconnected. - */ - - switch (message) { - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - message = COMMAND_COMPLETE; - linked_target = current_target; - linked_lun = current_lun; - linked_connected = 1; - DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established for linked command.\n", hostno); - /* We also will need to adjust status to accommodate intermediate - conditions. */ - if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD)) - status = GOOD; - break; - /* - * We should also handle what are "normal" termination - * messages here (ABORT, BUS_DEVICE_RESET?, and - * COMMAND_COMPLETE individually, and flake if things - * aren't right. - */ - default: - DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno); - linked_connected = 0; - } - } -#endif /* LINKED */ - - if (should_reconnect) { - DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno); - WRITE_CONTROL (BASE_CMD | CMD_INTR); - } else - WRITE_CONTROL (BASE_CMD); - - return retcode (st0x_aborted); -} /* end of internal_command */ - -static int seagate_st0x_abort(struct scsi_cmnd * SCpnt) -{ - st0x_aborted = DID_ABORT; - return SUCCESS; -} - -#undef ULOOP -#undef TIMEOUT - -/* - * the seagate_st0x_reset function resets the SCSI bus - * - * May be called with SCpnt = NULL - */ - -static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt) -{ - /* No timeouts - this command is going to fail because it was reset. */ - DANY ("scsi%d: Reseting bus... ", hostno); - - /* assert RESET signal on SCSI bus. */ - WRITE_CONTROL (BASE_CMD | CMD_RST); - - mdelay (20); - - WRITE_CONTROL (BASE_CMD); - st0x_aborted = DID_RESET; - - DANY ("done.\n"); - return SUCCESS; -} - -static int seagate_st0x_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, shost); - release_region(shost->io_port, shost->n_io_port); - return 0; -} - -static struct scsi_host_template driver_template = { - .detect = seagate_st0x_detect, - .release = seagate_st0x_release, - .info = seagate_st0x_info, - .queuecommand = seagate_st0x_queue_command, - .eh_abort_handler = seagate_st0x_abort, - .eh_bus_reset_handler = seagate_st0x_bus_reset, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" diff -puN drivers/scsi/sr.c~git-scsi-misc drivers/scsi/sr.c --- a/drivers/scsi/sr.c~git-scsi-misc +++ a/drivers/scsi/sr.c @@ -192,8 +192,9 @@ static int sr_media_change(struct cdrom_ * and we will figure it out later once the drive is * available again. */ cd->device->changed = 1; - return 1; /* This will force a flush, if called from - * check_disk_change */ + /* This will force a flush, if called from check_disk_change */ + retval = 1; + goto out; }; retval = cd->device->changed; @@ -203,9 +204,16 @@ static int sr_media_change(struct cdrom_ if (retval) { /* check multisession offset etc */ sr_cd_check(cdi); - get_sectorsize(cd); } + +out: + /* Notify userspace, that media has changed. */ + if (retval != cd->previous_state) + sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, + GFP_KERNEL); + cd->previous_state = retval; + return retval; } diff -puN drivers/scsi/sr.h~git-scsi-misc drivers/scsi/sr.h --- a/drivers/scsi/sr.h~git-scsi-misc +++ a/drivers/scsi/sr.h @@ -37,6 +37,7 @@ typedef struct scsi_cd { unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ unsigned readcd_cdda:1; /* reading audio data using READ_CD */ + unsigned previous_state:1; /* media has changed */ struct cdrom_device_info cdi; /* We hold gendisk and scsi_device references on probe and use * the refs on this kref to decide when to release them */ diff -puN drivers/scsi/sun3_NCR5380.c~git-scsi-misc drivers/scsi/sun3_NCR5380.c --- a/drivers/scsi/sun3_NCR5380.c~git-scsi-misc +++ a/drivers/scsi/sun3_NCR5380.c @@ -515,9 +515,9 @@ static __inline__ void initialize_SCp(st * various queues are valid. */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; @@ -528,8 +528,8 @@ static __inline__ void initialize_SCp(st } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } } @@ -935,7 +935,7 @@ static int NCR5380_queue_command(struct } # endif # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) # endif switch (cmd->cmnd[0]) { @@ -943,14 +943,14 @@ static int NCR5380_queue_command(struct case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingw++; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingr++; break; } @@ -1345,7 +1345,7 @@ static void collect_stats(struct NCR5380 struct scsi_cmnd *cmd) { # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) # endif switch (cmd->cmnd[0]) { @@ -1353,14 +1353,14 @@ static void collect_stats(struct NCR5380 case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ + /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/ hostdata->pendingw--; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ + /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/ hostdata->pendingr--; break; } diff -puN drivers/scsi/wd33c93.c~git-scsi-misc drivers/scsi/wd33c93.c --- a/drivers/scsi/wd33c93.c~git-scsi-misc +++ a/drivers/scsi/wd33c93.c @@ -407,16 +407,16 @@ wd33c93_queuecommand(struct scsi_cmnd *c * - SCp.phase records this command's SRCID_ER bit setting */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } /* WD docs state that at the conclusion of a "LEVEL2" command, the diff -puN drivers/scsi/wd7000.c~git-scsi-misc drivers/scsi/wd7000.c --- a/drivers/scsi/wd7000.c~git-scsi-misc +++ a/drivers/scsi/wd7000.c @@ -1108,13 +1108,10 @@ static int wd7000_queuecommand(struct sc scb->host = host; nseg = scsi_sg_count(SCpnt); - if (nseg) { + if (nseg > 1) { struct scatterlist *sg; unsigned i; - if (SCpnt->device->host->sg_tablesize == SG_NONE) { - panic("wd7000_queuecommand: scatter/gather not supported.\n"); - } dprintk("Using scatter/gather with %d elements.\n", nseg); sgb = scb->sgb; @@ -1128,7 +1125,10 @@ static int wd7000_queuecommand(struct sc } } else { scb->op = 0; - any2scsi(scb->dataptr, isa_virt_to_bus(scsi_sglist(SCpnt))); + if (nseg) { + struct scatterlist *sg = scsi_sglist(SCpnt); + any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset); + } any2scsi(scb->maxlen, scsi_bufflen(SCpnt)); } @@ -1524,7 +1524,7 @@ static __init int wd7000_detect(struct s * For boards before rev 6.0, scatter/gather isn't supported. */ if (host->rev1 < 6) - sh->sg_tablesize = SG_NONE; + sh->sg_tablesize = 1; present++; /* count it */ diff -puN drivers/usb/storage/freecom.c~git-scsi-misc drivers/usb/storage/freecom.c --- a/drivers/usb/storage/freecom.c~git-scsi-misc +++ a/drivers/usb/storage/freecom.c @@ -132,8 +132,7 @@ freecom_readdata (struct scsi_cmnd *srb, /* Now transfer all of our blocks. */ US_DEBUGP("Start of read\n"); - result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer, - count, srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, ipipe, srb); US_DEBUGP("freecom_readdata done!\n"); if (result > USB_STOR_XFER_SHORT) @@ -166,8 +165,7 @@ freecom_writedata (struct scsi_cmnd *srb /* Now transfer all of our blocks. */ US_DEBUGP("Start of write\n"); - result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer, - count, srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, opipe, srb); US_DEBUGP("freecom_writedata done!\n"); if (result > USB_STOR_XFER_SHORT) @@ -281,7 +279,7 @@ int freecom_transport(struct scsi_cmnd * * and such will hang. */ US_DEBUGP("Device indicates that it has %d bytes available\n", le16_to_cpu (fst->Count)); - US_DEBUGP("SCSI requested %d\n", srb->request_bufflen); + US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb)); /* Find the length we desire to read. */ switch (srb->cmnd[0]) { @@ -292,12 +290,12 @@ int freecom_transport(struct scsi_cmnd * length = le16_to_cpu(fst->Count); break; default: - length = srb->request_bufflen; + length = scsi_bufflen(srb); } /* verify that this amount is legal */ - if (length > srb->request_bufflen) { - length = srb->request_bufflen; + if (length > scsi_bufflen(srb)) { + length = scsi_bufflen(srb); US_DEBUGP("Truncating request to match buffer length: %d\n", length); } diff -puN drivers/usb/storage/isd200.c~git-scsi-misc drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c~git-scsi-misc +++ a/drivers/usb/storage/isd200.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -287,6 +288,7 @@ struct isd200_info { /* maximum number of LUNs supported */ unsigned char MaxLUNs; struct scsi_cmnd srb; + struct scatterlist sg; }; @@ -398,6 +400,31 @@ static void isd200_build_sense(struct us * Transport routines ***********************************************************************/ +/************************************************************************** + * isd200_set_srb(), isd200_srb_set_bufflen() + * + * Two helpers to facilitate in initialization of scsi_cmnd structure + * Will need to change when struct scsi_cmnd changes + */ +static void isd200_set_srb(struct isd200_info *info, + enum dma_data_direction dir, void* buff, unsigned bufflen) +{ + struct scsi_cmnd *srb = &info->srb; + + if (buff) + sg_init_one(&info->sg, buff, bufflen); + + srb->sc_data_direction = dir; + srb->request_buffer = buff ? &info->sg : NULL; + srb->request_bufflen = bufflen; + srb->use_sg = buff ? 1 : 0; +} + +static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen) +{ + srb->request_bufflen = bufflen; +} + /************************************************************************** * isd200_action @@ -432,9 +459,7 @@ static int isd200_action( struct us_data ata.generic.RegisterSelect = REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_STATUS | REG_ERROR; - srb->sc_data_direction = DMA_FROM_DEVICE; - srb->request_buffer = pointer; - srb->request_bufflen = value; + isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value); break; case ACTION_ENUM: @@ -444,7 +469,7 @@ static int isd200_action( struct us_data ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; - srb->sc_data_direction = DMA_NONE; + isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_RESET: @@ -453,7 +478,7 @@ static int isd200_action( struct us_data ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; - srb->sc_data_direction = DMA_NONE; + isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_REENABLE: @@ -462,7 +487,7 @@ static int isd200_action( struct us_data ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; - srb->sc_data_direction = DMA_NONE; + isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_SOFT_RESET: @@ -471,21 +496,20 @@ static int isd200_action( struct us_data ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; ata.write.CommandByte = WIN_SRST; - srb->sc_data_direction = DMA_NONE; + isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; - srb->sc_data_direction = DMA_FROM_DEVICE; - srb->request_buffer = (void *) info->id; - srb->request_bufflen = sizeof(struct hd_driveid); + isd200_set_srb(info, DMA_FROM_DEVICE, info->id, + sizeof(struct hd_driveid)); break; default: US_DEBUGP("Error: Undefined action %d\n",action); - break; + return ISD200_ERROR; } memcpy(srb->cmnd, &ata, sizeof(ata.generic)); @@ -590,7 +614,7 @@ static void isd200_invoke_transport( str return; } - if ((srb->resid > 0) && + if ((scsi_get_resid(srb) > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || @@ -1217,7 +1241,6 @@ static int isd200_get_inquiry_data( stru return(retStatus); } - /************************************************************************** * isd200_scsi_to_ata * @@ -1266,7 +1289,7 @@ static int isd200_scsi_to_ata(struct scs ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; + isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; @@ -1284,7 +1307,7 @@ static int isd200_scsi_to_ata(struct scs ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; + isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; @@ -1390,7 +1413,7 @@ static int isd200_scsi_to_ata(struct scs ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? WIN_DOORLOCK : WIN_DOORUNLOCK; - srb->request_bufflen = 0; + isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Not removeable media, just report okay\n"); srb->result = SAM_STAT_GOOD; @@ -1416,7 +1439,7 @@ static int isd200_scsi_to_ata(struct scs ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; + isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Nothing to do, just report okay\n"); srb->result = SAM_STAT_GOOD; @@ -1525,7 +1548,7 @@ int isd200_Initialization(struct us_data void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) { - int sendToTransport = 1; + int sendToTransport = 1, orig_bufflen; union ata_cdb ataCdb; /* Make sure driver was initialized */ @@ -1533,11 +1556,14 @@ void isd200_ata_command(struct scsi_cmnd if (us->extra == NULL) US_DEBUGP("ERROR Driver not initialized\n"); - /* Convert command */ - srb->resid = 0; + scsi_set_resid(srb, 0); + /* scsi_bufflen might change in protocol translation to ata */ + orig_bufflen = scsi_bufflen(srb); sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb); /* send the command to the transport layer */ if (sendToTransport) isd200_invoke_transport(us, srb, &ataCdb); + + isd200_srb_set_bufflen(srb, orig_bufflen); } diff -puN drivers/usb/storage/protocol.c~git-scsi-misc drivers/usb/storage/protocol.c --- a/drivers/usb/storage/protocol.c~git-scsi-misc +++ a/drivers/usb/storage/protocol.c @@ -149,11 +149,7 @@ void usb_stor_transparent_scsi_command(s ***********************************************************************/ /* Copy a buffer of length buflen to/from the srb's transfer buffer. - * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer - * points to a list of s-g entries and we ignore srb->request_bufflen. - * For non-scatter-gather transfers, srb->request_buffer points to the - * transfer buffer itself and srb->request_bufflen is the buffer's length.) - * Update the *index and *offset variables so that the next copy will + * Update the **sgptr and *offset variables so that the next copy will * pick up from where this one left off. */ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, @@ -162,80 +158,64 @@ unsigned int usb_stor_access_xfer_buf(un { unsigned int cnt; - /* If not using scatter-gather, just transfer the data directly. - * Make certain it will fit in the available buffer space. */ - if (srb->use_sg == 0) { - if (*offset >= srb->request_bufflen) - return 0; - cnt = min(buflen, srb->request_bufflen - *offset); - if (dir == TO_XFER_BUF) - memcpy((unsigned char *) srb->request_buffer + *offset, - buffer, cnt); - else - memcpy(buffer, (unsigned char *) srb->request_buffer + - *offset, cnt); - *offset += cnt; - - /* Using scatter-gather. We have to go through the list one entry + /* We have to go through the list one entry * at a time. Each s-g entry contains some number of pages, and * each page has to be kmap()'ed separately. If the page is already * in kernel-addressable memory then kmap() will return its address. * If the page is not directly accessible -- such as a user buffer * located in high memory -- then kmap() will map it to a temporary * position in the kernel's virtual address space. */ - } else { - struct scatterlist *sg = *sgptr; + struct scatterlist *sg = *sgptr; + + if (!sg) + sg = scsi_sglist(srb); - if (!sg) - sg = (struct scatterlist *) srb->request_buffer; + /* This loop handles a single s-g list entry, which may + * include multiple pages. Find the initial page structure + * and the starting offset within the page, and update + * the *offset and **sgptr values for the next loop. */ + cnt = 0; + while (cnt < buflen) { + struct page *page = sg_page(sg) + + ((sg->offset + *offset) >> PAGE_SHIFT); + unsigned int poff = + (sg->offset + *offset) & (PAGE_SIZE-1); + unsigned int sglen = sg->length - *offset; + + if (sglen > buflen - cnt) { + + /* Transfer ends within this s-g entry */ + sglen = buflen - cnt; + *offset += sglen; + } else { + + /* Transfer continues to next s-g entry */ + *offset = 0; + sg = sg_next(sg); + } - /* This loop handles a single s-g list entry, which may - * include multiple pages. Find the initial page structure - * and the starting offset within the page, and update - * the *offset and *index values for the next loop. */ - cnt = 0; - while (cnt < buflen) { - struct page *page = sg_page(sg) + - ((sg->offset + *offset) >> PAGE_SHIFT); - unsigned int poff = - (sg->offset + *offset) & (PAGE_SIZE-1); - unsigned int sglen = sg->length - *offset; - - if (sglen > buflen - cnt) { - - /* Transfer ends within this s-g entry */ - sglen = buflen - cnt; - *offset += sglen; - } else { - - /* Transfer continues to next s-g entry */ - *offset = 0; - sg = sg_next(sg); - } - - /* Transfer the data for all the pages in this - * s-g entry. For each page: call kmap(), do the - * transfer, and call kunmap() immediately after. */ - while (sglen > 0) { - unsigned int plen = min(sglen, (unsigned int) - PAGE_SIZE - poff); - unsigned char *ptr = kmap(page); - - if (dir == TO_XFER_BUF) - memcpy(ptr + poff, buffer + cnt, plen); - else - memcpy(buffer + cnt, ptr + poff, plen); - kunmap(page); - - /* Start at the beginning of the next page */ - poff = 0; - ++page; - cnt += plen; - sglen -= plen; - } + /* Transfer the data for all the pages in this + * s-g entry. For each page: call kmap(), do the + * transfer, and call kunmap() immediately after. */ + while (sglen > 0) { + unsigned int plen = min(sglen, (unsigned int) + PAGE_SIZE - poff); + unsigned char *ptr = kmap(page); + + if (dir == TO_XFER_BUF) + memcpy(ptr + poff, buffer + cnt, plen); + else + memcpy(buffer + cnt, ptr + poff, plen); + kunmap(page); + + /* Start at the beginning of the next page */ + poff = 0; + ++page; + cnt += plen; + sglen -= plen; } - *sgptr = sg; } + *sgptr = sg; /* Return the amount actually transferred */ return cnt; @@ -251,6 +231,6 @@ void usb_stor_set_xfer_buf(unsigned char usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset, TO_XFER_BUF); - if (buflen < srb->request_bufflen) - srb->resid = srb->request_bufflen - buflen; + if (buflen < scsi_bufflen(srb)) + scsi_set_resid(srb, scsi_bufflen(srb) - buflen); } diff -puN drivers/usb/storage/sddr09.c~git-scsi-misc drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c~git-scsi-misc +++ a/drivers/usb/storage/sddr09.c @@ -1623,7 +1623,7 @@ int sddr09_transport(struct scsi_cmnd *s return USB_STOR_TRANSPORT_ERROR; } - if (srb->request_bufflen == 0) + if (scsi_bufflen(srb) == 0) return USB_STOR_TRANSPORT_GOOD; if (srb->sc_data_direction == DMA_TO_DEVICE || @@ -1634,12 +1634,9 @@ int sddr09_transport(struct scsi_cmnd *s US_DEBUGP("SDDR09: %s %d bytes\n", (srb->sc_data_direction == DMA_TO_DEVICE) ? "sending" : "receiving", - srb->request_bufflen); + scsi_bufflen(srb)); - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, - srb->request_bufflen, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); diff -puN drivers/usb/storage/shuttle_usbat.c~git-scsi-misc drivers/usb/storage/shuttle_usbat.c --- a/drivers/usb/storage/shuttle_usbat.c~git-scsi-misc +++ a/drivers/usb/storage/shuttle_usbat.c @@ -130,7 +130,7 @@ static int usbat_write(struct us_data *u * Convenience function to perform a bulk read */ static int usbat_bulk_read(struct us_data *us, - unsigned char *data, + void* buf, unsigned int len, int use_sg) { @@ -138,14 +138,14 @@ static int usbat_bulk_read(struct us_dat return USB_STOR_XFER_GOOD; US_DEBUGP("usbat_bulk_read: len = %d\n", len); - return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, data, len, use_sg, NULL); + return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL); } /* * Convenience function to perform a bulk write */ static int usbat_bulk_write(struct us_data *us, - unsigned char *data, + void* buf, unsigned int len, int use_sg) { @@ -153,7 +153,7 @@ static int usbat_bulk_write(struct us_da return USB_STOR_XFER_GOOD; US_DEBUGP("usbat_bulk_write: len = %d\n", len); - return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, data, len, use_sg, NULL); + return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL); } /* @@ -314,7 +314,7 @@ static int usbat_wait_not_busy(struct us * Read block data from the data register */ static int usbat_read_block(struct us_data *us, - unsigned char *content, + void* buf, unsigned short len, int use_sg) { @@ -337,7 +337,7 @@ static int usbat_read_block(struct us_da if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - result = usbat_bulk_read(us, content, len, use_sg); + result = usbat_bulk_read(us, buf, len, use_sg); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); } @@ -347,7 +347,7 @@ static int usbat_read_block(struct us_da */ static int usbat_write_block(struct us_data *us, unsigned char access, - unsigned char *content, + void* buf, unsigned short len, int minutes, int use_sg) @@ -372,7 +372,7 @@ static int usbat_write_block(struct us_d if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - result = usbat_bulk_write(us, content, len, use_sg); + result = usbat_bulk_write(us, buf, len, use_sg); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -392,7 +392,7 @@ static int usbat_hp8200e_rw_block_test(s unsigned char timeout, unsigned char qualifier, int direction, - unsigned char *content, + void *buf, unsigned short len, int use_sg, int minutes) @@ -472,7 +472,7 @@ static int usbat_hp8200e_rw_block_test(s } result = usb_stor_bulk_transfer_sg(us, - pipe, content, len, use_sg, NULL); + pipe, buf, len, use_sg, NULL); /* * If we get a stall on the bulk download, we'll retry @@ -606,7 +606,7 @@ static int usbat_multiple_write(struct u * other related details) are defined beforehand with _set_shuttle_features(). */ static int usbat_read_blocks(struct us_data *us, - unsigned char *buffer, + void* buffer, int len, int use_sg) { @@ -648,7 +648,7 @@ static int usbat_read_blocks(struct us_d * other related details) are defined beforehand with _set_shuttle_features(). */ static int usbat_write_blocks(struct us_data *us, - unsigned char *buffer, + void* buffer, int len, int use_sg) { @@ -1170,15 +1170,15 @@ static int usbat_hp8200e_handle_read10(s US_DEBUGP("handle_read10: transfersize %d\n", srb->transfersize); - if (srb->request_bufflen < 0x10000) { + if (scsi_bufflen(srb) < 0x10000) { result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, registers, data, 19, USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), DMA_FROM_DEVICE, - srb->request_buffer, - srb->request_bufflen, srb->use_sg, 1); + scsi_sglist(srb), + scsi_bufflen(srb), scsi_sg_count(srb), 1); return result; } @@ -1196,7 +1196,7 @@ static int usbat_hp8200e_handle_read10(s len <<= 16; len |= data[7+7]; US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); - srb->transfersize = srb->request_bufflen/len; + srb->transfersize = scsi_bufflen(srb)/len; } if (!srb->transfersize) { @@ -1213,7 +1213,7 @@ static int usbat_hp8200e_handle_read10(s len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); - len = min(len, srb->request_bufflen); + len = min(len, scsi_bufflen(srb)); buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) /* bloody hell! */ return USB_STOR_TRANSPORT_FAILED; @@ -1222,10 +1222,10 @@ static int usbat_hp8200e_handle_read10(s sector |= short_pack(data[7+5], data[7+4]); transferred = 0; - while (transferred != srb->request_bufflen) { + while (transferred != scsi_bufflen(srb)) { - if (len > srb->request_bufflen - transferred) - len = srb->request_bufflen - transferred; + if (len > scsi_bufflen(srb) - transferred) + len = scsi_bufflen(srb) - transferred; data[3] = len&0xFF; /* (cylL) = expected length (L) */ data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ @@ -1261,7 +1261,7 @@ static int usbat_hp8200e_handle_read10(s transferred += len; sector += len / srb->transfersize; - } /* while transferred != srb->request_bufflen */ + } /* while transferred != scsi_bufflen(srb) */ kfree(buffer); return result; @@ -1429,9 +1429,8 @@ static int usbat_hp8200e_transport(struc unsigned char data[32]; unsigned int len; int i; - char string[64]; - len = srb->request_bufflen; + len = scsi_bufflen(srb); /* Send A0 (ATA PACKET COMMAND). Note: I guess we're never going to get any of the ATA @@ -1472,8 +1471,8 @@ static int usbat_hp8200e_transport(struc USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), DMA_TO_DEVICE, - srb->request_buffer, - len, srb->use_sg, 10); + scsi_sglist(srb), + len, scsi_sg_count(srb), 10); if (result == USB_STOR_TRANSPORT_GOOD) { transferred += len; @@ -1540,23 +1539,8 @@ static int usbat_hp8200e_transport(struc len = *status; - result = usbat_read_block(us, srb->request_buffer, len, srb->use_sg); - - /* Debug-print the first 32 bytes of the transfer */ - - if (!srb->use_sg) { - string[0] = 0; - for (i=0; irequest_buffer)[i]); - if ((i%16)==15) { - US_DEBUGP("%s\n", string); - string[0] = 0; - } - } - if (string[0]!=0) - US_DEBUGP("%s\n", string); - } + result = usbat_read_block(us, scsi_sglist(srb), len, + scsi_sg_count(srb)); } return result; diff -puN drivers/usb/storage/transport.c~git-scsi-misc drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c~git-scsi-misc +++ a/drivers/usb/storage/transport.c @@ -459,6 +459,22 @@ static int usb_stor_bulk_transfer_sglist } /* + * Common used function. Transfer a complete command + * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid + */ +int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe, + struct scsi_cmnd* srb) +{ + unsigned int partial; + int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb), + scsi_sg_count(srb), scsi_bufflen(srb), + &partial); + + scsi_set_resid(srb, scsi_bufflen(srb) - partial); + return result; +} + +/* * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * @@ -508,7 +524,7 @@ void usb_stor_invoke_transport(struct sc int result; /* send the command to the transport layer */ - srb->resid = 0; + scsi_set_resid(srb, 0); result = us->transport(srb, us); /* if the command gets aborted by the higher layers, we need to @@ -568,7 +584,7 @@ void usb_stor_invoke_transport(struct sc * A short transfer on a command where we don't expect it * is unusual, but it doesn't mean we need to auto-sense. */ - if ((srb->resid > 0) && + if ((scsi_get_resid(srb) > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || @@ -593,7 +609,7 @@ void usb_stor_invoke_transport(struct sc srb->cmd_len = 12; /* issue the auto-sense command */ - srb->resid = 0; + scsi_set_resid(srb, 0); temp_result = us->transport(us->srb, us); /* let's clean up right away */ @@ -649,7 +665,7 @@ void usb_stor_invoke_transport(struct sc /* Did we transfer less than the minimum amount required? */ if (srb->result == SAM_STAT_GOOD && - srb->request_bufflen - srb->resid < srb->underflow) + scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); return; @@ -708,7 +724,7 @@ void usb_stor_stop_transport(struct us_d int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) { - unsigned int transfer_length = srb->request_bufflen; + unsigned int transfer_length = scsi_bufflen(srb); unsigned int pipe = 0; int result; @@ -737,9 +753,7 @@ int usb_stor_CBI_transport(struct scsi_c if (transfer_length) { pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, transfer_length, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); US_DEBUGP("CBI data stage result is 0x%x\n", result); /* if we stalled the data transfer it means command failed */ @@ -808,7 +822,7 @@ int usb_stor_CBI_transport(struct scsi_c */ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) { - unsigned int transfer_length = srb->request_bufflen; + unsigned int transfer_length = scsi_bufflen(srb); int result; /* COMMAND STAGE */ @@ -836,9 +850,7 @@ int usb_stor_CB_transport(struct scsi_cm if (transfer_length) { unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, transfer_length, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); US_DEBUGP("CB data stage result is 0x%x\n", result); /* if we stalled the data transfer it means command failed */ @@ -904,7 +916,7 @@ int usb_stor_Bulk_transport(struct scsi_ { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; - unsigned int transfer_length = srb->request_bufflen; + unsigned int transfer_length = scsi_bufflen(srb); unsigned int residue; int result; int fake_sense = 0; @@ -955,9 +967,7 @@ int usb_stor_Bulk_transport(struct scsi_ if (transfer_length) { unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, transfer_length, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); US_DEBUGP("Bulk data transfer result 0x%x\n", result); if (result == USB_STOR_XFER_ERROR) return USB_STOR_TRANSPORT_ERROR; @@ -1036,7 +1046,8 @@ int usb_stor_Bulk_transport(struct scsi_ if (residue) { if (!(us->flags & US_FL_IGNORE_RESIDUE)) { residue = min(residue, transfer_length); - srb->resid = max(srb->resid, (int) residue); + scsi_set_resid(srb, max(scsi_get_resid(srb), + (int) residue)); } } diff -puN drivers/usb/storage/transport.h~git-scsi-misc drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h~git-scsi-misc +++ a/drivers/usb/storage/transport.h @@ -139,6 +139,8 @@ extern int usb_stor_bulk_transfer_buf(st void *buf, unsigned int length, unsigned int *act_len); extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, int use_sg, int *residual); +extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe, + struct scsi_cmnd* srb); extern int usb_stor_port_reset(struct us_data *us); #endif diff -puN include/scsi/libsas.h~git-scsi-misc include/scsi/libsas.h --- a/include/scsi/libsas.h~git-scsi-misc +++ a/include/scsi/libsas.h @@ -122,8 +122,8 @@ struct ex_phy { u8 attached_sata_dev:1; u8 attached_sata_ps:1; - enum sas_proto attached_tproto; - enum sas_proto attached_iproto; + enum sas_protocol attached_tproto; + enum sas_protocol attached_iproto; u8 attached_sas_addr[SAS_ADDR_SIZE]; u8 attached_phy_id; @@ -191,8 +191,8 @@ struct domain_device { struct list_head dev_list_node; - enum sas_proto iproto; - enum sas_proto tproto; + enum sas_protocol iproto; + enum sas_protocol tproto; struct sas_rphy *rphy; @@ -245,8 +245,8 @@ struct asd_sas_port { enum sas_class class; u8 sas_addr[SAS_ADDR_SIZE]; u8 attached_sas_addr[SAS_ADDR_SIZE]; - enum sas_proto iproto; - enum sas_proto tproto; + enum sas_protocol iproto; + enum sas_protocol tproto; enum sas_oob_mode oob_mode; @@ -289,8 +289,8 @@ struct asd_sas_phy { int id; /* must be set */ enum sas_class class; - enum sas_proto iproto; - enum sas_proto tproto; + enum sas_protocol iproto; + enum sas_protocol tproto; enum sas_phy_type type; enum sas_phy_role role; @@ -537,7 +537,7 @@ struct sas_task { spinlock_t task_state_lock; unsigned task_state_flags; - enum sas_proto task_proto; + enum sas_protocol task_proto; /* Used by the discovery code. */ struct timer_list timer; @@ -563,7 +563,7 @@ struct sas_task { struct work_struct abort_work; }; - +extern struct kmem_cache *sas_task_cache; #define SAS_TASK_STATE_PENDING 1 #define SAS_TASK_STATE_DONE 2 @@ -573,7 +573,6 @@ struct sas_task { static inline struct sas_task *sas_alloc_task(gfp_t flags) { - extern struct kmem_cache *sas_task_cache; struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags); if (task) { @@ -590,7 +589,6 @@ static inline struct sas_task *sas_alloc static inline void sas_free_task(struct sas_task *task) { if (task) { - extern struct kmem_cache *sas_task_cache; BUG_ON(!list_empty(&task->list)); kmem_cache_free(sas_task_cache, task); } diff -puN include/scsi/sas.h~git-scsi-misc include/scsi/sas.h --- a/include/scsi/sas.h~git-scsi-misc +++ a/include/scsi/sas.h @@ -102,13 +102,12 @@ enum sas_dev_type { SATA_PM_PORT= 8, }; -/* Partly from IDENTIFY address frame. */ -enum sas_proto { - SATA_PROTO = 1, - SAS_PROTO_SMP = 2, /* protocol */ - SAS_PROTO_STP = 4, /* protocol */ - SAS_PROTO_SSP = 8, /* protocol */ - SAS_PROTO_ALL = 0xE, +enum sas_protocol { + SAS_PROTOCOL_SATA = 0x01, + SAS_PROTOCOL_SMP = 0x02, + SAS_PROTOCOL_STP = 0x04, + SAS_PROTOCOL_SSP = 0x08, + SAS_PROTOCOL_ALL = 0x0E, }; /* From the spec; local phys only */ diff -puN include/scsi/scsi_device.h~git-scsi-misc include/scsi/scsi_device.h --- a/include/scsi/scsi_device.h~git-scsi-misc +++ a/include/scsi/scsi_device.h @@ -122,9 +122,6 @@ struct scsi_device { unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ unsigned simple_tags:1; /* simple queue tag messages are enabled */ unsigned ordered_tags:1;/* ordered queue tag messages are enabled */ - unsigned single_lun:1; /* Indicates we should only allow I/O to - * one of the luns for the device at a - * time. */ unsigned was_reset:1; /* There was a bus reset on the bus for * this device */ unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN @@ -202,6 +199,9 @@ struct scsi_target { unsigned int id; /* target id ... replace * scsi_device.id eventually */ unsigned int create:1; /* signal that it needs to be added */ + unsigned int single_lun:1; /* Indicates we should only + * allow I/O to one of the luns + * for the device at a time. */ unsigned int pdt_1f_for_no_lun; /* PDT = 0x1f */ /* means no lun present */ diff -puN include/scsi/scsi_transport_sas.h~git-scsi-misc include/scsi/scsi_transport_sas.h --- a/include/scsi/scsi_transport_sas.h~git-scsi-misc +++ a/include/scsi/scsi_transport_sas.h @@ -4,6 +4,7 @@ #include #include #include +#include struct scsi_transport_template; struct sas_rphy; @@ -16,13 +17,6 @@ enum sas_device_type { SAS_FANOUT_EXPANDER_DEVICE, }; -enum sas_protocol { - SAS_PROTOCOL_SATA = 0x01, - SAS_PROTOCOL_SMP = 0x02, - SAS_PROTOCOL_STP = 0x04, - SAS_PROTOCOL_SSP = 0x08, -}; - static inline int sas_protocol_ata(enum sas_protocol proto) { return ((proto & SAS_PROTOCOL_SATA) || diff -puN include/scsi/sd.h~git-scsi-misc include/scsi/sd.h --- a/include/scsi/sd.h~git-scsi-misc +++ a/include/scsi/sd.h @@ -41,6 +41,7 @@ struct scsi_disk { u32 index; u8 media_present; u8 write_prot; + unsigned previous_state : 1; unsigned WCE : 1; /* state of disk WCE bit */ unsigned RCD : 1; /* state of disk RCD bit, unused */ unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ _