+static void synchronize_callback(void *context, struct fib *fibptr)
+{
+ struct aac_synchronize_reply *synchronizereply;
+ struct scsi_cmnd *cmd;
+
+ cmd = context;
+ cmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
+ smp_processor_id(), jiffies));
+ BUG_ON(fibptr == NULL);
+
+
+ synchronizereply = fib_data(fibptr);
+ if (le32_to_cpu(synchronizereply->status) == CT_OK)
+ cmd->result = DID_OK << 16 |
+ COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+ else {
+ struct scsi_device *sdev = cmd->device;
+ struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+ u32 cid = sdev_id(sdev);
+ printk(KERN_WARNING
+ "synchronize_callback: synchronize failed, status = %d\n",
+ le32_to_cpu(synchronizereply->status));
+ cmd->result = DID_OK << 16 |
+ COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+ set_sense((u8 *)&dev->fsa_dev[cid].sense_data,
+ HARDWARE_ERROR,
+ SENCODE_INTERNAL_TARGET_FAILURE,
+ ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+ 0, 0);
+ memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+ min(sizeof(dev->fsa_dev[cid].sense_data),
+ sizeof(cmd->sense_buffer)));
+ }
+
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ cmd->scsi_done(cmd);
+}
+
+static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
+{
+ int status;
+ struct fib *cmd_fibcontext;
+ struct aac_synchronize *synchronizecmd;
+ struct scsi_cmnd *cmd;
+ struct scsi_device *sdev = scsicmd->device;
+ int active = 0;
+ unsigned long flags;
+
+ /*
+ * Wait for all outstanding queued commands to complete to this
+ * specific target (block).
+ */
+ spin_lock_irqsave(&sdev->list_lock, flags);
+ list_for_each_entry(cmd, &sdev->cmd_list, list)
+ if (cmd != scsicmd && cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
+ ++active;
+ break;
+ }
+
+ spin_unlock_irqrestore(&sdev->list_lock, flags);
+
+ /*
+ * Yield the processor (requeue for later)
+ */
+ if (active)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+
+ /*
+ * Allocate and initialize a Fib
+ */
+ if (!(cmd_fibcontext =
+ aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata)))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ aac_fib_init(cmd_fibcontext);
+
+ synchronizecmd = fib_data(cmd_fibcontext);
+ synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
+ synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
+ synchronizecmd->cid = cpu_to_le32(cid);
+ synchronizecmd->count =
+ cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
+
+ /*
+ * Now send the Fib to the adapter
+ */
+ status = aac_fib_send(ContainerCommand,
+ cmd_fibcontext,
+ sizeof(struct aac_synchronize),
+ FsaNormal,
+ 0, 1,
+ (fib_callback)synchronize_callback,
+ (void *)scsicmd);
+
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
+
+ printk(KERN_WARNING
+ "aac_synchronize: aac_fib_send failed with status: %d.\n", status);
+ aac_fib_complete(cmd_fibcontext);
+ aac_fib_free(cmd_fibcontext);
+ return SCSI_MLQUEUE_HOST_BUSY;
+}