diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_scsi_host.c')
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 146 |
1 files changed, 65 insertions, 81 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index eeba76cdf774..b6e233d9a0a1 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/kthread.h> | 26 | #include <linux/kthread.h> |
27 | #include <linux/firmware.h> | 27 | #include <linux/firmware.h> |
28 | #include <linux/export.h> | ||
28 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
29 | 30 | ||
30 | #include "sas_internal.h" | 31 | #include "sas_internal.h" |
@@ -182,79 +183,56 @@ int sas_queue_up(struct sas_task *task) | |||
182 | return 0; | 183 | return 0; |
183 | } | 184 | } |
184 | 185 | ||
185 | /** | 186 | int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) |
186 | * sas_queuecommand -- Enqueue a command for processing | ||
187 | * @parameters: See SCSI Core documentation | ||
188 | * | ||
189 | * Note: XXX: Remove the host unlock/lock pair when SCSI Core can | ||
190 | * call us without holding an IRQ spinlock... | ||
191 | */ | ||
192 | static int sas_queuecommand_lck(struct scsi_cmnd *cmd, | ||
193 | void (*scsi_done)(struct scsi_cmnd *)) | ||
194 | __releases(host->host_lock) | ||
195 | __acquires(dev->sata_dev.ap->lock) | ||
196 | __releases(dev->sata_dev.ap->lock) | ||
197 | __acquires(host->host_lock) | ||
198 | { | 187 | { |
199 | int res = 0; | ||
200 | struct domain_device *dev = cmd_to_domain_dev(cmd); | ||
201 | struct Scsi_Host *host = cmd->device->host; | ||
202 | struct sas_internal *i = to_sas_internal(host->transportt); | 188 | struct sas_internal *i = to_sas_internal(host->transportt); |
189 | struct domain_device *dev = cmd_to_domain_dev(cmd); | ||
190 | struct sas_ha_struct *sas_ha = dev->port->ha; | ||
191 | struct sas_task *task; | ||
192 | int res = 0; | ||
203 | 193 | ||
204 | spin_unlock_irq(host->host_lock); | 194 | /* If the device fell off, no sense in issuing commands */ |
195 | if (dev->gone) { | ||
196 | cmd->result = DID_BAD_TARGET << 16; | ||
197 | goto out_done; | ||
198 | } | ||
205 | 199 | ||
206 | { | 200 | if (dev_is_sata(dev)) { |
207 | struct sas_ha_struct *sas_ha = dev->port->ha; | 201 | unsigned long flags; |
208 | struct sas_task *task; | ||
209 | |||
210 | /* If the device fell off, no sense in issuing commands */ | ||
211 | if (dev->gone) { | ||
212 | cmd->result = DID_BAD_TARGET << 16; | ||
213 | scsi_done(cmd); | ||
214 | goto out; | ||
215 | } | ||
216 | 202 | ||
217 | if (dev_is_sata(dev)) { | 203 | spin_lock_irqsave(dev->sata_dev.ap->lock, flags); |
218 | unsigned long flags; | 204 | res = ata_sas_queuecmd(cmd, dev->sata_dev.ap); |
205 | spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); | ||
206 | return res; | ||
207 | } | ||
219 | 208 | ||
220 | spin_lock_irqsave(dev->sata_dev.ap->lock, flags); | 209 | task = sas_create_task(cmd, dev, GFP_ATOMIC); |
221 | res = ata_sas_queuecmd(cmd, dev->sata_dev.ap); | 210 | if (!task) |
222 | spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); | 211 | return SCSI_MLQUEUE_HOST_BUSY; |
223 | goto out; | ||
224 | } | ||
225 | 212 | ||
226 | res = -ENOMEM; | 213 | /* Queue up, Direct Mode or Task Collector Mode. */ |
227 | task = sas_create_task(cmd, dev, GFP_ATOMIC); | 214 | if (sas_ha->lldd_max_execute_num < 2) |
228 | if (!task) | 215 | res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); |
229 | goto out; | 216 | else |
217 | res = sas_queue_up(task); | ||
230 | 218 | ||
231 | cmd->scsi_done = scsi_done; | 219 | if (res) |
232 | /* Queue up, Direct Mode or Task Collector Mode. */ | 220 | goto out_free_task; |
233 | if (sas_ha->lldd_max_execute_num < 2) | 221 | return 0; |
234 | res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); | ||
235 | else | ||
236 | res = sas_queue_up(task); | ||
237 | 222 | ||
238 | /* Examine */ | 223 | out_free_task: |
239 | if (res) { | 224 | SAS_DPRINTK("lldd_execute_task returned: %d\n", res); |
240 | SAS_DPRINTK("lldd_execute_task returned: %d\n", res); | 225 | ASSIGN_SAS_TASK(cmd, NULL); |
241 | ASSIGN_SAS_TASK(cmd, NULL); | 226 | sas_free_task(task); |
242 | sas_free_task(task); | 227 | if (res == -SAS_QUEUE_FULL) |
243 | if (res == -SAS_QUEUE_FULL) { | 228 | cmd->result = DID_SOFT_ERROR << 16; /* retry */ |
244 | cmd->result = DID_SOFT_ERROR << 16; /* retry */ | 229 | else |
245 | res = 0; | 230 | cmd->result = DID_ERROR << 16; |
246 | scsi_done(cmd); | 231 | out_done: |
247 | } | 232 | cmd->scsi_done(cmd); |
248 | goto out; | 233 | return 0; |
249 | } | ||
250 | } | ||
251 | out: | ||
252 | spin_lock_irq(host->host_lock); | ||
253 | return res; | ||
254 | } | 234 | } |
255 | 235 | ||
256 | DEF_SCSI_QCMD(sas_queuecommand) | ||
257 | |||
258 | static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) | 236 | static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) |
259 | { | 237 | { |
260 | struct sas_task *task = TO_SAS_TASK(cmd); | 238 | struct sas_task *task = TO_SAS_TASK(cmd); |
@@ -784,8 +762,7 @@ int sas_target_alloc(struct scsi_target *starget) | |||
784 | return 0; | 762 | return 0; |
785 | } | 763 | } |
786 | 764 | ||
787 | #define SAS_DEF_QD 32 | 765 | #define SAS_DEF_QD 256 |
788 | #define SAS_MAX_QD 64 | ||
789 | 766 | ||
790 | int sas_slave_configure(struct scsi_device *scsi_dev) | 767 | int sas_slave_configure(struct scsi_device *scsi_dev) |
791 | { | 768 | { |
@@ -825,34 +802,41 @@ void sas_slave_destroy(struct scsi_device *scsi_dev) | |||
825 | struct domain_device *dev = sdev_to_domain_dev(scsi_dev); | 802 | struct domain_device *dev = sdev_to_domain_dev(scsi_dev); |
826 | 803 | ||
827 | if (dev_is_sata(dev)) | 804 | if (dev_is_sata(dev)) |
828 | dev->sata_dev.ap->link.device[0].class = ATA_DEV_NONE; | 805 | sas_to_ata_dev(dev)->class = ATA_DEV_NONE; |
829 | } | 806 | } |
830 | 807 | ||
831 | int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth, | 808 | int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason) |
832 | int reason) | ||
833 | { | 809 | { |
834 | int res = min(new_depth, SAS_MAX_QD); | 810 | struct domain_device *dev = sdev_to_domain_dev(sdev); |
835 | 811 | ||
836 | if (reason != SCSI_QDEPTH_DEFAULT) | 812 | if (dev_is_sata(dev)) |
813 | return __ata_change_queue_depth(dev->sata_dev.ap, sdev, depth, | ||
814 | reason); | ||
815 | |||
816 | switch (reason) { | ||
817 | case SCSI_QDEPTH_DEFAULT: | ||
818 | case SCSI_QDEPTH_RAMP_UP: | ||
819 | if (!sdev->tagged_supported) | ||
820 | depth = 1; | ||
821 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
822 | break; | ||
823 | case SCSI_QDEPTH_QFULL: | ||
824 | scsi_track_queue_full(sdev, depth); | ||
825 | break; | ||
826 | default: | ||
837 | return -EOPNOTSUPP; | 827 | return -EOPNOTSUPP; |
838 | |||
839 | if (scsi_dev->tagged_supported) | ||
840 | scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev), | ||
841 | res); | ||
842 | else { | ||
843 | struct domain_device *dev = sdev_to_domain_dev(scsi_dev); | ||
844 | sas_printk("device %llx LUN %x queue depth changed to 1\n", | ||
845 | SAS_ADDR(dev->sas_addr), | ||
846 | scsi_dev->lun); | ||
847 | scsi_adjust_queue_depth(scsi_dev, 0, 1); | ||
848 | res = 1; | ||
849 | } | 828 | } |
850 | 829 | ||
851 | return res; | 830 | return depth; |
852 | } | 831 | } |
853 | 832 | ||
854 | int sas_change_queue_type(struct scsi_device *scsi_dev, int qt) | 833 | int sas_change_queue_type(struct scsi_device *scsi_dev, int qt) |
855 | { | 834 | { |
835 | struct domain_device *dev = sdev_to_domain_dev(scsi_dev); | ||
836 | |||
837 | if (dev_is_sata(dev)) | ||
838 | return -EINVAL; | ||
839 | |||
856 | if (!scsi_dev->tagged_supported) | 840 | if (!scsi_dev->tagged_supported) |
857 | return 0; | 841 | return 0; |
858 | 842 | ||