STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
+static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
+static int NCR_700_change_queue_type(struct scsi_device *SDpnt, int depth);
STATIC struct device_attribute *NCR_700_dev_attrs[];
struct Scsi_Host *
NCR_700_detect(struct scsi_host_template *tpnt,
- struct NCR_700_Host_Parameters *hostdata, struct device *dev,
- unsigned long irq, u8 scsi_id)
+ struct NCR_700_Host_Parameters *hostdata, struct device *dev)
{
dma_addr_t pScript, pSlots;
__u8 *memory;
tpnt->use_clustering = ENABLE_CLUSTERING;
tpnt->slave_configure = NCR_700_slave_configure;
tpnt->slave_destroy = NCR_700_slave_destroy;
+ tpnt->change_queue_depth = NCR_700_change_queue_depth;
+ tpnt->change_queue_type = NCR_700_change_queue_type;
if(tpnt->name == NULL)
tpnt->name = "53c700";
host->max_lun = NCR_700_MAX_LUNS;
BUG_ON(NCR_700_transport_template == NULL);
host->transportt = NCR_700_transport_template;
- host->unique_id = hostdata->base;
- host->base = hostdata->base;
+ host->unique_id = (unsigned long)hostdata->base;
hostdata->eh_complete = NULL;
- host->irq = irq;
- host->this_id = scsi_id;
host->hostdata[0] = (unsigned long)hostdata;
/* kick the chip */
NCR_700_writeb(0xff, host, CTEST9_REG);
/* reset the chip */
NCR_700_chip_reset(host);
- if (request_irq(irq, NCR_700_intr, SA_SHIRQ, dev->bus_id, host)) {
- dev_printk(KERN_ERR, dev, "53c700: irq %lu request failed\n ",
- irq);
- goto out_put_host;
- }
-
if (scsi_add_host(host, dev)) {
dev_printk(KERN_ERR, dev, "53c700: scsi_add_host failed\n");
- goto out_release_irq;
+ scsi_host_put(host);
+ return NULL;
}
spi_signalling(host) = hostdata->differential ? SPI_SIGNAL_HVD :
SPI_SIGNAL_SE;
return host;
-
- out_release_irq:
- free_irq(irq, host);
- out_put_host:
- scsi_host_put(host);
-
- return NULL;
}
int
switch(hostdata->msgin[2]) {
case A_SDTR_MSG:
if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
+ struct scsi_target *starget = SCp->device->sdev_target;
__u8 period = hostdata->msgin[3];
__u8 offset = hostdata->msgin[4];
offset = 0;
period = 0;
}
+
+ spi_offset(starget) = offset;
+ spi_period(starget) = period;
if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) {
- if(spi_offset(SCp->device->sdev_target) != 0)
- printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
- host->host_no, pun, lun,
- offset, period*4);
- else
- printk(KERN_INFO "scsi%d: (%d:%d) Asynchronous\n",
- host->host_no, pun, lun);
+ spi_display_xfer_agreement(starget);
NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
}
-
- spi_offset(SCp->device->sdev_target) = offset;
- spi_period(SCp->device->sdev_target) = period;
-
NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
spi_offset(SCp->device->sdev_target) = 0;
NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
- } else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
+ } else if(SCp != NULL && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION) {
/* rejected our first simple tag message */
printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun);
- NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ /* we're done negotiating */
+ NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION);
hostdata->tag_negotiated &= ~(1<<SCp->device->id);
SCp->device->tagged_supported = 0;
scsi_deactivate_tcq(SCp->device, host->cmd_per_lun);
if(dsps == A_GOOD_STATUS_AFTER_STATUS) {
DEBUG((" COMMAND COMPLETE, status=%02x\n",
hostdata->status[0]));
- /* OK, if TCQ still on, we know it works */
- NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ /* OK, if TCQ still under negotiation, we now know it works */
+ if (NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION)
+ NCR_700_set_tag_neg_state(SCp->device,
+ NCR_700_FINISHED_TAG_NEGOTIATION);
+
/* check for contingent allegiance contitions */
if(status_byte(hostdata->status[0]) == CHECK_CONDITION ||
status_byte(hostdata->status[0]) == COMMAND_TERMINATED) {
printk("53c700: scsi%d, command ", SCp->device->host->host_no);
scsi_print_command(SCp);
#endif
- if(SCp->device->tagged_supported && !SCp->device->simple_tags
- && (hostdata->tag_negotiated &(1<<SCp->device->id)) == 0
- && NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
- /* upper layer has indicated tags are supported. We don't
- * necessarily believe it yet.
- *
- * NOTE: There is a danger here: the mid layer supports
- * tag queuing per LUN. We only support it per PUN because
- * of potential reselection issues */
- scsi_activate_tcq(SCp->device, NCR_700_DEFAULT_TAGS);
- }
-
if(blk_rq_tagged(SCp->request)
- && (hostdata->tag_negotiated &(1<<SCp->device->id)) == 0) {
- printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
+ && (hostdata->tag_negotiated &(1<<SCp->device->id)) == 0
+ && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_START_TAG_NEGOTIATION) {
+ printk(KERN_ERR "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
hostdata->tag_negotiated |= (1<<SCp->device->id);
- NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ NCR_700_set_tag_neg_state(SCp->device, NCR_700_DURING_TAG_NEGOTIATION);
}
/* here we may have to process an untagged command. The gate
hostdata->tag_negotiated &= ~(1<<SCp->device->id);
}
- if((hostdata->tag_negotiated &(1<<SCp->device->id))) {
+ if((hostdata->tag_negotiated &(1<<SCp->device->id))
+ && scsi_get_tag_type(SCp->device)) {
slot->tag = SCp->request->tag;
DEBUG(("53c700 %d:%d:%d, sending out tag %d, slot %p\n",
SCp->device->host->host_no, SCp->device->id, SCp->device->lun, slot->tag,
/* to do here: allocate memory; build a queue_full list */
if(SDp->tagged_supported) {
- /* do TCQ stuff here */
+ scsi_set_tag_type(SDp, MSG_ORDERED_TAG);
+ scsi_activate_tcq(SDp, NCR_700_DEFAULT_TAGS);
+ NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
} else {
/* initialise to default depth */
scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun);
/* to do here: deallocate memory */
}
-static ssize_t
-NCR_700_store_queue_depth(struct device *dev, const char *buf, size_t count)
+static int
+NCR_700_change_queue_depth(struct scsi_device *SDp, int depth)
{
- int depth;
+ if (depth > NCR_700_MAX_TAGS)
+ depth = NCR_700_MAX_TAGS;
- struct scsi_device *SDp = to_scsi_device(dev);
- depth = simple_strtoul(buf, NULL, 0);
- if(depth > NCR_700_MAX_TAGS)
- return -EINVAL;
- scsi_adjust_queue_depth(SDp, MSG_ORDERED_TAG, depth);
+ scsi_adjust_queue_depth(SDp, scsi_get_tag_type(SDp), depth);
+ return depth;
+}
- return count;
+static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
+{
+ int change_tag = ((tag_type ==0 && scsi_get_tag_type(SDp) != 0)
+ || (tag_type != 0 && scsi_get_tag_type(SDp) == 0));
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+
+ scsi_set_tag_type(SDp, tag_type);
+
+ /* We have a global (per target) flag to track whether TCQ is
+ * enabled, so we'll be turning it off for the entire target here.
+ * our tag algorithm will fail if we mix tagged and untagged commands,
+ * so quiesce the device before doing this */
+ if (change_tag)
+ scsi_target_quiesce(SDp->sdev_target);
+
+ if (!tag_type) {
+ /* shift back to the default unqueued number of commands
+ * (the user can still raise this) */
+ scsi_deactivate_tcq(SDp, SDp->host->cmd_per_lun);
+ hostdata->tag_negotiated &= ~(1 << SDp->id);
+ } else {
+ /* Here, we cleared the negotiation flag above, so this
+ * will force the driver to renegotiate */
+ scsi_activate_tcq(SDp, SDp->queue_depth);
+ if (change_tag)
+ NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
+ }
+ if (change_tag)
+ scsi_target_resume(SDp->sdev_target);
+
+ return tag_type;
}
static ssize_t
return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp));
}
-static struct device_attribute NCR_700_queue_depth_attr = {
- .attr = {
- .name = "queue_depth",
- .mode = S_IWUSR,
- },
- .store = NCR_700_store_queue_depth,
-};
-
static struct device_attribute NCR_700_active_tags_attr = {
.attr = {
.name = "active_tags",
};
STATIC struct device_attribute *NCR_700_dev_attrs[] = {
- &NCR_700_queue_depth_attr,
&NCR_700_active_tags_attr,
NULL,
};