diff options
Diffstat (limited to 'drivers/scsi/aacraid')
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 341 | ||||
-rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 3 | ||||
-rw-r--r-- | drivers/scsi/aacraid/comminit.c | 6 | ||||
-rw-r--r-- | drivers/scsi/aacraid/commsup.c | 3 | ||||
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 320 |
5 files changed, 407 insertions, 266 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 707ee2f5954d..a64285ab0728 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -549,7 +549,9 @@ static void get_container_name_callback(void *context, struct fib * fibptr) if ((le32_to_cpu(get_name_reply->status) == CT_OK) && (get_name_reply->data[0] != '\0')) { char *sp = get_name_reply->data; - sp[sizeof(((struct aac_get_name_resp *)NULL)->data)] = '\0'; + int data_size = FIELD_SIZEOF(struct aac_get_name_resp, data); + + sp[data_size - 1] = '\0'; while (*sp == ' ') ++sp; if (*sp) { @@ -579,21 +581,25 @@ static void get_container_name_callback(void *context, struct fib * fibptr) static int aac_get_container_name(struct scsi_cmnd * scsicmd) { int status; + int data_size; struct aac_get_name *dinfo; struct fib * cmd_fibcontext; struct aac_dev * dev; dev = (struct aac_dev *)scsicmd->device->host->hostdata; + data_size = FIELD_SIZEOF(struct aac_get_name_resp, data); + cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); aac_fib_init(cmd_fibcontext); dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext); + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; dinfo->command = cpu_to_le32(VM_ContainerConfig); dinfo->type = cpu_to_le32(CT_READ_NAME); dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); - dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data)); + dinfo->count = cpu_to_le32(data_size - 1); status = aac_fib_send(ContainerCommand, cmd_fibcontext, @@ -606,10 +612,8 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status); aac_fib_complete(cmd_fibcontext); @@ -720,6 +724,7 @@ static void _aac_probe_container1(void * context, struct fib * fibptr) dinfo->count = cpu_to_le32(scmd_id(scsicmd)); dinfo->type = cpu_to_le32(FT_FILESYS); + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; status = aac_fib_send(ContainerCommand, fibptr, @@ -731,9 +736,7 @@ static void _aac_probe_container1(void * context, struct fib * fibptr) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - else if (status < 0) { + if (status < 0 && status != -EINPROGRESS) { /* Inherit results from VM_NameServe, if any */ dresp->status = cpu_to_le32(ST_OK); _aac_probe_container2(context, fibptr); @@ -761,6 +764,7 @@ static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(stru dinfo->count = cpu_to_le32(scmd_id(scsicmd)); dinfo->type = cpu_to_le32(FT_FILESYS); scsicmd->SCp.ptr = (char *)callback; + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; status = aac_fib_send(ContainerCommand, fibptr, @@ -772,10 +776,9 @@ static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(stru /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } + if (status < 0) { scsicmd->SCp.ptr = NULL; aac_fib_complete(fibptr); @@ -1121,6 +1124,7 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd) dinfo->command = cpu_to_le32(VM_ContainerConfig); dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID); dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; status = aac_fib_send(ContainerCommand, cmd_fibcontext, @@ -1133,10 +1137,8 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status); aac_fib_complete(cmd_fibcontext); @@ -2330,16 +2332,14 @@ static int aac_read(struct scsi_cmnd * scsicmd) * Alocate and initialize a Fib */ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); - + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count); /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status); /* @@ -2424,16 +2424,14 @@ static int aac_write(struct scsi_cmnd * scsicmd) * Allocate and initialize a Fib then setup a BlockWrite command */ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); - + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua); /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status); /* @@ -2583,6 +2581,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd) synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd)); synchronizecmd->count = cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data)); + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; /* * Now send the Fib to the adapter @@ -2598,10 +2597,8 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } printk(KERN_WARNING "aac_synchronize: aac_fib_send failed with status: %d.\n", status); @@ -2661,6 +2658,7 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd) pmcmd->cid = cpu_to_le32(sdev_id(sdev)); pmcmd->parm = (scsicmd->cmnd[1] & 1) ? cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0; + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; /* * Now send the Fib to the adapter @@ -2676,10 +2674,8 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } aac_fib_complete(cmd_fibcontext); aac_fib_free(cmd_fibcontext); @@ -3198,10 +3194,11 @@ static int query_disk(struct aac_dev *dev, void __user *arg) return -EBUSY; if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) return -EFAULT; - if (qd.cnum == -1) + if (qd.cnum == -1) { + if (qd.id < 0 || qd.id >= dev->maximum_num_containers) + return -EINVAL; qd.cnum = qd.id; - else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) - { + } else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) { if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers) return -EINVAL; qd.instance = dev->scsi_host_ptr->host_no; @@ -3686,16 +3683,14 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) * Allocate and initialize a Fib then setup a BlockWrite command */ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); - + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; status = aac_adapter_scsi(cmd_fibcontext, scsicmd); /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status); aac_fib_complete(cmd_fibcontext); @@ -3733,15 +3728,14 @@ static int aac_send_hba_fib(struct scsi_cmnd *scsicmd) if (!cmd_fibcontext) return -1; + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; status = aac_adapter_hba(cmd_fibcontext, scsicmd); /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + if (status == -EINPROGRESS) return 0; - } pr_warn("aac_hba_cmd_req: aac_fib_send failed with status: %d\n", status); @@ -3757,6 +3751,8 @@ static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg) struct aac_dev *dev; unsigned long byte_count = 0; int nseg; + struct scatterlist *sg; + int i; dev = (struct aac_dev *)scsicmd->device->host->hostdata; // Get rid of old data @@ -3765,32 +3761,29 @@ static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg) psg->sg[0].count = 0; nseg = scsi_dma_map(scsicmd); - if (nseg < 0) + if (nseg <= 0) return nseg; - if (nseg) { - struct scatterlist *sg; - int i; - psg->count = cpu_to_le32(nseg); + psg->count = cpu_to_le32(nseg); - scsi_for_each_sg(scsicmd, sg, nseg, i) { - psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg)); - psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); - byte_count += sg_dma_len(sg); - } - /* hba wants the size to be exact */ - if (byte_count > scsi_bufflen(scsicmd)) { - u32 temp = le32_to_cpu(psg->sg[i-1].count) - - (byte_count - scsi_bufflen(scsicmd)); - psg->sg[i-1].count = cpu_to_le32(temp); - byte_count = scsi_bufflen(scsicmd); - } - /* Check for command underflow */ - if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ - printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", - byte_count, scsicmd->underflow); - } + scsi_for_each_sg(scsicmd, sg, nseg, i) { + psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg)); + psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); + byte_count += sg_dma_len(sg); } + /* hba wants the size to be exact */ + if (byte_count > scsi_bufflen(scsicmd)) { + u32 temp = le32_to_cpu(psg->sg[i-1].count) - + (byte_count - scsi_bufflen(scsicmd)); + psg->sg[i-1].count = cpu_to_le32(temp); + byte_count = scsi_bufflen(scsicmd); + } + /* Check for command underflow */ + if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { + printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", + byte_count, scsicmd->underflow); + } + return byte_count; } @@ -3801,6 +3794,8 @@ static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg) unsigned long byte_count = 0; u64 addr; int nseg; + struct scatterlist *sg; + int i; dev = (struct aac_dev *)scsicmd->device->host->hostdata; // Get rid of old data @@ -3810,34 +3805,31 @@ static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg) psg->sg[0].count = 0; nseg = scsi_dma_map(scsicmd); - if (nseg < 0) + if (nseg <= 0) return nseg; - if (nseg) { - struct scatterlist *sg; - int i; - - scsi_for_each_sg(scsicmd, sg, nseg, i) { - int count = sg_dma_len(sg); - addr = sg_dma_address(sg); - psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); - psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - psg->sg[i].count = cpu_to_le32(count); - byte_count += count; - } - psg->count = cpu_to_le32(nseg); - /* hba wants the size to be exact */ - if (byte_count > scsi_bufflen(scsicmd)) { - u32 temp = le32_to_cpu(psg->sg[i-1].count) - - (byte_count - scsi_bufflen(scsicmd)); - psg->sg[i-1].count = cpu_to_le32(temp); - byte_count = scsi_bufflen(scsicmd); - } - /* Check for command underflow */ - if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ - printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", - byte_count, scsicmd->underflow); - } + + scsi_for_each_sg(scsicmd, sg, nseg, i) { + int count = sg_dma_len(sg); + addr = sg_dma_address(sg); + psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); + psg->sg[i].addr[1] = cpu_to_le32(addr>>32); + psg->sg[i].count = cpu_to_le32(count); + byte_count += count; + } + psg->count = cpu_to_le32(nseg); + /* hba wants the size to be exact */ + if (byte_count > scsi_bufflen(scsicmd)) { + u32 temp = le32_to_cpu(psg->sg[i-1].count) - + (byte_count - scsi_bufflen(scsicmd)); + psg->sg[i-1].count = cpu_to_le32(temp); + byte_count = scsi_bufflen(scsicmd); } + /* Check for command underflow */ + if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { + printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", + byte_count, scsicmd->underflow); + } + return byte_count; } @@ -3845,6 +3837,8 @@ static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg) { unsigned long byte_count = 0; int nseg; + struct scatterlist *sg; + int i; // Get rid of old data psg->count = 0; @@ -3856,37 +3850,34 @@ static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg) psg->sg[0].flags = 0; nseg = scsi_dma_map(scsicmd); - if (nseg < 0) + if (nseg <= 0) return nseg; - if (nseg) { - struct scatterlist *sg; - int i; - - scsi_for_each_sg(scsicmd, sg, nseg, i) { - int count = sg_dma_len(sg); - u64 addr = sg_dma_address(sg); - psg->sg[i].next = 0; - psg->sg[i].prev = 0; - psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32)); - psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); - psg->sg[i].count = cpu_to_le32(count); - psg->sg[i].flags = 0; - byte_count += count; - } - psg->count = cpu_to_le32(nseg); - /* hba wants the size to be exact */ - if (byte_count > scsi_bufflen(scsicmd)) { - u32 temp = le32_to_cpu(psg->sg[i-1].count) - - (byte_count - scsi_bufflen(scsicmd)); - psg->sg[i-1].count = cpu_to_le32(temp); - byte_count = scsi_bufflen(scsicmd); - } - /* Check for command underflow */ - if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ - printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", - byte_count, scsicmd->underflow); - } + + scsi_for_each_sg(scsicmd, sg, nseg, i) { + int count = sg_dma_len(sg); + u64 addr = sg_dma_address(sg); + psg->sg[i].next = 0; + psg->sg[i].prev = 0; + psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32)); + psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); + psg->sg[i].count = cpu_to_le32(count); + psg->sg[i].flags = 0; + byte_count += count; + } + psg->count = cpu_to_le32(nseg); + /* hba wants the size to be exact */ + if (byte_count > scsi_bufflen(scsicmd)) { + u32 temp = le32_to_cpu(psg->sg[i-1].count) - + (byte_count - scsi_bufflen(scsicmd)); + psg->sg[i-1].count = cpu_to_le32(temp); + byte_count = scsi_bufflen(scsicmd); + } + /* Check for command underflow */ + if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { + printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", + byte_count, scsicmd->underflow); } + return byte_count; } @@ -3895,75 +3886,77 @@ static long aac_build_sgraw2(struct scsi_cmnd *scsicmd, { unsigned long byte_count = 0; int nseg; + struct scatterlist *sg; + int i, conformable = 0; + u32 min_size = PAGE_SIZE, cur_size; nseg = scsi_dma_map(scsicmd); - if (nseg < 0) + if (nseg <= 0) return nseg; - if (nseg) { - struct scatterlist *sg; - int i, conformable = 0; - u32 min_size = PAGE_SIZE, cur_size; - - scsi_for_each_sg(scsicmd, sg, nseg, i) { - int count = sg_dma_len(sg); - u64 addr = sg_dma_address(sg); - - BUG_ON(i >= sg_max); - rio2->sge[i].addrHigh = cpu_to_le32((u32)(addr>>32)); - rio2->sge[i].addrLow = cpu_to_le32((u32)(addr & 0xffffffff)); - cur_size = cpu_to_le32(count); - rio2->sge[i].length = cur_size; - rio2->sge[i].flags = 0; - if (i == 0) { - conformable = 1; - rio2->sgeFirstSize = cur_size; - } else if (i == 1) { - rio2->sgeNominalSize = cur_size; + + scsi_for_each_sg(scsicmd, sg, nseg, i) { + int count = sg_dma_len(sg); + u64 addr = sg_dma_address(sg); + + BUG_ON(i >= sg_max); + rio2->sge[i].addrHigh = cpu_to_le32((u32)(addr>>32)); + rio2->sge[i].addrLow = cpu_to_le32((u32)(addr & 0xffffffff)); + cur_size = cpu_to_le32(count); + rio2->sge[i].length = cur_size; + rio2->sge[i].flags = 0; + if (i == 0) { + conformable = 1; + rio2->sgeFirstSize = cur_size; + } else if (i == 1) { + rio2->sgeNominalSize = cur_size; + min_size = cur_size; + } else if ((i+1) < nseg && cur_size != rio2->sgeNominalSize) { + conformable = 0; + if (cur_size < min_size) min_size = cur_size; - } else if ((i+1) < nseg && cur_size != rio2->sgeNominalSize) { - conformable = 0; - if (cur_size < min_size) - min_size = cur_size; - } - byte_count += count; } + byte_count += count; + } - /* hba wants the size to be exact */ - if (byte_count > scsi_bufflen(scsicmd)) { - u32 temp = le32_to_cpu(rio2->sge[i-1].length) - - (byte_count - scsi_bufflen(scsicmd)); - rio2->sge[i-1].length = cpu_to_le32(temp); - byte_count = scsi_bufflen(scsicmd); - } + /* hba wants the size to be exact */ + if (byte_count > scsi_bufflen(scsicmd)) { + u32 temp = le32_to_cpu(rio2->sge[i-1].length) - + (byte_count - scsi_bufflen(scsicmd)); + rio2->sge[i-1].length = cpu_to_le32(temp); + byte_count = scsi_bufflen(scsicmd); + } - rio2->sgeCnt = cpu_to_le32(nseg); - rio2->flags |= cpu_to_le16(RIO2_SG_FORMAT_IEEE1212); - /* not conformable: evaluate required sg elements */ - if (!conformable) { - int j, nseg_new = nseg, err_found; - for (i = min_size / PAGE_SIZE; i >= 1; --i) { - err_found = 0; - nseg_new = 2; - for (j = 1; j < nseg - 1; ++j) { - if (rio2->sge[j].length % (i*PAGE_SIZE)) { - err_found = 1; - break; - } - nseg_new += (rio2->sge[j].length / (i*PAGE_SIZE)); - } - if (!err_found) + rio2->sgeCnt = cpu_to_le32(nseg); + rio2->flags |= cpu_to_le16(RIO2_SG_FORMAT_IEEE1212); + /* not conformable: evaluate required sg elements */ + if (!conformable) { + int j, nseg_new = nseg, err_found; + for (i = min_size / PAGE_SIZE; i >= 1; --i) { + err_found = 0; + nseg_new = 2; + for (j = 1; j < nseg - 1; ++j) { + if (rio2->sge[j].length % (i*PAGE_SIZE)) { + err_found = 1; break; + } + nseg_new += (rio2->sge[j].length / (i*PAGE_SIZE)); } - if (i > 0 && nseg_new <= sg_max) - aac_convert_sgraw2(rio2, i, nseg, nseg_new); - } else - rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT); + if (!err_found) + break; + } + if (i > 0 && nseg_new <= sg_max) { + int ret = aac_convert_sgraw2(rio2, i, nseg, nseg_new); - /* Check for command underflow */ - if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { - printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", - byte_count, scsicmd->underflow); + if (ret < 0) + return ret; } + } else + rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT); + + /* Check for command underflow */ + if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { + printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", + byte_count, scsicmd->underflow); } return byte_count; @@ -3980,7 +3973,7 @@ static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int sge = kmalloc(nseg_new * sizeof(struct sge_ieee1212), GFP_ATOMIC); if (sge == NULL) - return -1; + return -ENOMEM; for (i = 1, pos = 1; i < nseg-1; ++i) { for (j = 0; j < rio2->sge[i].length / (pages * PAGE_SIZE); ++j) { diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index d31a9bc2ba69..92fabf2b0c24 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1723,6 +1723,7 @@ struct aac_dev #define FIB_CONTEXT_FLAG_FASTRESP (0x00000008) #define FIB_CONTEXT_FLAG_NATIVE_HBA (0x00000010) #define FIB_CONTEXT_FLAG_NATIVE_HBA_TMF (0x00000020) +#define FIB_CONTEXT_FLAG_SCSI_CMD (0x00000040) /* * Define the command values @@ -2274,7 +2275,7 @@ struct aac_get_name_resp { __le32 parm3; __le32 parm4; __le32 parm5; - u8 data[16]; + u8 data[17]; }; #define CT_CID_TO_32BITS_UID 165 diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 9ee025b1d0e0..97d269f16888 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -520,9 +520,9 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) dev->raw_io_64 = 1; dev->sync_mode = aac_sync_mode; if (dev->a_ops.adapter_comm && - (status[1] & AAC_OPT_NEW_COMM)) { - dev->comm_interface = AAC_COMM_MESSAGE; - dev->raw_io_interface = 1; + (status[1] & AAC_OPT_NEW_COMM)) { + dev->comm_interface = AAC_COMM_MESSAGE; + dev->raw_io_interface = 1; if ((status[1] & AAC_OPT_NEW_COMM_TYPE1)) { /* driver supports TYPE1 (Tupelo) */ dev->comm_interface = AAC_COMM_MESSAGE_TYPE1; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 1c617ccfaf12..dfe8e70f8d99 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -770,7 +770,8 @@ int aac_hba_send(u8 command, struct fib *fibptr, fib_callback callback, /* bit1 of request_id must be 0 */ hbacmd->request_id = cpu_to_le32((((u32)(fibptr - dev->fibs)) << 2) + 1); - } else + fibptr->flags |= FIB_CONTEXT_FLAG_SCSI_CMD; + } else if (command != HBA_IU_TYPE_SCSI_TM_REQ) return -EINVAL; diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 0f277df73af0..87cc4a93e637 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -814,111 +814,225 @@ static int aac_eh_abort(struct scsi_cmnd* cmd) return ret; } +static u8 aac_eh_tmf_lun_reset_fib(struct aac_hba_map_info *info, + struct fib *fib, u64 tmf_lun) +{ + struct aac_hba_tm_req *tmf; + u64 address; + + /* start a HBA_TMF_LUN_RESET TMF request */ + tmf = (struct aac_hba_tm_req *)fib->hw_fib_va; + memset(tmf, 0, sizeof(*tmf)); + tmf->tmf = HBA_TMF_LUN_RESET; + tmf->it_nexus = info->rmw_nexus; + int_to_scsilun(tmf_lun, (struct scsi_lun *)tmf->lun); + + address = (u64)fib->hw_error_pa; + tmf->error_ptr_hi = cpu_to_le32 + ((u32)(address >> 32)); + tmf->error_ptr_lo = cpu_to_le32 + ((u32)(address & 0xffffffff)); + tmf->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); + fib->hbacmd_size = sizeof(*tmf); + + return HBA_IU_TYPE_SCSI_TM_REQ; +} + +static u8 aac_eh_tmf_hard_reset_fib(struct aac_hba_map_info *info, + struct fib *fib) +{ + struct aac_hba_reset_req *rst; + u64 address; + + /* already tried, start a hard reset now */ + rst = (struct aac_hba_reset_req *)fib->hw_fib_va; + memset(rst, 0, sizeof(*rst)); + rst->it_nexus = info->rmw_nexus; + + address = (u64)fib->hw_error_pa; + rst->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); + rst->error_ptr_lo = cpu_to_le32 + ((u32)(address & 0xffffffff)); + rst->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); + fib->hbacmd_size = sizeof(*rst); + + return HBA_IU_TYPE_SATA_REQ; +} + +void aac_tmf_callback(void *context, struct fib *fibptr) +{ + struct aac_hba_resp *err = + &((struct aac_native_hba *)fibptr->hw_fib_va)->resp.err; + struct aac_hba_map_info *info = context; + int res; + + switch (err->service_response) { + case HBA_RESP_SVCRES_TMF_REJECTED: + res = -1; + break; + case HBA_RESP_SVCRES_TMF_LUN_INVALID: + res = 0; + break; + case HBA_RESP_SVCRES_TMF_COMPLETE: + case HBA_RESP_SVCRES_TMF_SUCCEEDED: + res = 0; + break; + default: + res = -2; + break; + } + aac_fib_complete(fibptr); + + info->reset_state = res; +} + /* - * aac_eh_reset - Reset command handling + * aac_eh_dev_reset - Device reset command handling * @scsi_cmd: SCSI command block causing the reset * */ -static int aac_eh_reset(struct scsi_cmnd* cmd) +static int aac_eh_dev_reset(struct scsi_cmnd *cmd) { struct scsi_device * dev = cmd->device; struct Scsi_Host * host = dev->host; struct aac_dev * aac = (struct aac_dev *)host->hostdata; + struct aac_hba_map_info *info; int count; u32 bus, cid; + struct fib *fib; int ret = FAILED; - int status = 0; - __le32 supported_options2 = 0; - bool is_mu_reset; - bool is_ignore_reset; - bool is_doorbell_reset; - + int status; + u8 command; bus = aac_logical_to_phys(scmd_channel(cmd)); cid = scmd_id(cmd); - if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS && - aac->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) { - struct fib *fib; - int status; - u64 address; - u8 command; + info = &aac->hba_map[bus][cid]; + if (bus >= AAC_MAX_BUSES || cid >= AAC_MAX_TARGETS || + info->devtype != AAC_DEVTYPE_NATIVE_RAW) + return FAILED; - pr_err("%s: Host adapter reset request. SCSI hang ?\n", - AAC_DRIVERNAME); + if (info->reset_state > 0) + return FAILED; - fib = aac_fib_alloc(aac); - if (!fib) - return ret; + pr_err("%s: Host adapter reset request. SCSI hang ?\n", + AAC_DRIVERNAME); + + fib = aac_fib_alloc(aac); + if (!fib) + return ret; + + /* start a HBA_TMF_LUN_RESET TMF request */ + command = aac_eh_tmf_lun_reset_fib(info, fib, dev->lun); + info->reset_state = 1; - if (aac->hba_map[bus][cid].reset_state == 0) { - struct aac_hba_tm_req *tmf; - - /* start a HBA_TMF_LUN_RESET TMF request */ - tmf = (struct aac_hba_tm_req *)fib->hw_fib_va; - memset(tmf, 0, sizeof(*tmf)); - tmf->tmf = HBA_TMF_LUN_RESET; - tmf->it_nexus = aac->hba_map[bus][cid].rmw_nexus; - tmf->lun[1] = cmd->device->lun; - - address = (u64)fib->hw_error_pa; - tmf->error_ptr_hi = cpu_to_le32 - ((u32)(address >> 32)); - tmf->error_ptr_lo = cpu_to_le32 - ((u32)(address & 0xffffffff)); - tmf->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); - fib->hbacmd_size = sizeof(*tmf); - - command = HBA_IU_TYPE_SCSI_TM_REQ; - aac->hba_map[bus][cid].reset_state++; - } else if (aac->hba_map[bus][cid].reset_state >= 1) { - struct aac_hba_reset_req *rst; - - /* already tried, start a hard reset now */ - rst = (struct aac_hba_reset_req *)fib->hw_fib_va; - memset(rst, 0, sizeof(*rst)); - /* reset_type is already zero... */ - rst->it_nexus = aac->hba_map[bus][cid].rmw_nexus; - - address = (u64)fib->hw_error_pa; - rst->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); - rst->error_ptr_lo = cpu_to_le32 - ((u32)(address & 0xffffffff)); - rst->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); - fib->hbacmd_size = sizeof(*rst); - - command = HBA_IU_TYPE_SATA_REQ; - aac->hba_map[bus][cid].reset_state = 0; + status = aac_hba_send(command, fib, + (fib_callback) aac_tmf_callback, + (void *) info); + + /* Wait up to 15 seconds for completion */ + for (count = 0; count < 15; ++count) { + if (info->reset_state == 0) { + ret = info->reset_state == 0 ? SUCCESS : FAILED; + break; } - cmd->SCp.sent_command = 0; + msleep(1000); + } - status = aac_hba_send(command, fib, - (fib_callback) aac_hba_callback, - (void *) cmd); + return ret; +} - /* Wait up to 15 seconds for completion */ - for (count = 0; count < 15; ++count) { - if (cmd->SCp.sent_command) { - ret = SUCCESS; - break; - } - msleep(1000); +/* + * aac_eh_target_reset - Target reset command handling + * @scsi_cmd: SCSI command block causing the reset + * + */ +static int aac_eh_target_reset(struct scsi_cmnd *cmd) +{ + struct scsi_device * dev = cmd->device; + struct Scsi_Host * host = dev->host; + struct aac_dev * aac = (struct aac_dev *)host->hostdata; + struct aac_hba_map_info *info; + int count; + u32 bus, cid; + int ret = FAILED; + struct fib *fib; + int status; + u8 command; + + bus = aac_logical_to_phys(scmd_channel(cmd)); + cid = scmd_id(cmd); + info = &aac->hba_map[bus][cid]; + if (bus >= AAC_MAX_BUSES || cid >= AAC_MAX_TARGETS || + info->devtype != AAC_DEVTYPE_NATIVE_RAW) + return FAILED; + + if (info->reset_state > 0) + return FAILED; + + pr_err("%s: Host adapter reset request. SCSI hang ?\n", + AAC_DRIVERNAME); + + fib = aac_fib_alloc(aac); + if (!fib) + return ret; + + + /* already tried, start a hard reset now */ + command = aac_eh_tmf_hard_reset_fib(info, fib); + + info->reset_state = 2; + + status = aac_hba_send(command, fib, + (fib_callback) aac_tmf_callback, + (void *) info); + + /* Wait up to 15 seconds for completion */ + for (count = 0; count < 15; ++count) { + if (info->reset_state <= 0) { + ret = info->reset_state == 0 ? SUCCESS : FAILED; + break; } + msleep(1000); + } - if (ret == SUCCESS) - goto out; + return ret; +} - } else { +/* + * aac_eh_bus_reset - Bus reset command handling + * @scsi_cmd: SCSI command block causing the reset + * + */ +static int aac_eh_bus_reset(struct scsi_cmnd* cmd) +{ + struct scsi_device * dev = cmd->device; + struct Scsi_Host * host = dev->host; + struct aac_dev * aac = (struct aac_dev *)host->hostdata; + int count; + u32 cmd_bus; + int status = 0; - /* Mark the assoc. FIB to not complete, eh handler does this */ - for (count = 0; - count < (host->can_queue + AAC_NUM_MGT_FIB); - ++count) { - struct fib *fib = &aac->fibs[count]; - if (fib->hw_fib_va->header.XferState && - (fib->flags & FIB_CONTEXT_FLAG) && - (fib->callback_data == cmd)) { + cmd_bus = aac_logical_to_phys(scmd_channel(cmd)); + /* Mark the assoc. FIB to not complete, eh handler does this */ + for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { + struct fib *fib = &aac->fibs[count]; + + if (fib->hw_fib_va->header.XferState && + (fib->flags & FIB_CONTEXT_FLAG) && + (fib->flags & FIB_CONTEXT_FLAG_SCSI_CMD)) { + struct aac_hba_map_info *info; + u32 bus, cid; + + cmd = (struct scsi_cmnd *)fib->callback_data; + bus = aac_logical_to_phys(scmd_channel(cmd)); + if (bus != cmd_bus) + continue; + cid = scmd_id(cmd); + info = &aac->hba_map[bus][cid]; + if (bus >= AAC_MAX_BUSES || cid >= AAC_MAX_TARGETS || + info->devtype != AAC_DEVTYPE_NATIVE_RAW) { fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; } @@ -935,8 +1049,24 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) dev_err(&aac->pdev->dev, "Adapter health - %d\n", status); count = get_num_of_incomplete_fibs(aac); - if (count == 0) - return SUCCESS; + return (count == 0) ? SUCCESS : FAILED; +} + +/* + * aac_eh_host_reset - Host reset command handling + * @scsi_cmd: SCSI command block causing the reset + * + */ +int aac_eh_host_reset(struct scsi_cmnd *cmd) +{ + struct scsi_device * dev = cmd->device; + struct Scsi_Host * host = dev->host; + struct aac_dev * aac = (struct aac_dev *)host->hostdata; + int ret = FAILED; + __le32 supported_options2 = 0; + bool is_mu_reset; + bool is_ignore_reset; + bool is_doorbell_reset; /* * Check if reset is supported by the firmware @@ -954,11 +1084,24 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) && aac_check_reset && (aac_check_reset != -1 || !is_ignore_reset)) { /* Bypass wait for command quiesce */ - aac_reset_adapter(aac, 2, IOP_HWSOFT_RESET); + if (aac_reset_adapter(aac, 2, IOP_HWSOFT_RESET) == 0) + ret = SUCCESS; + } + /* + * Reset EH state + */ + if (ret == SUCCESS) { + int bus, cid; + struct aac_hba_map_info *info; + + for (bus = 0; bus < AAC_MAX_BUSES; bus++) { + for (cid = 0; cid < AAC_MAX_TARGETS; cid++) { + info = &aac->hba_map[bus][cid]; + if (info->devtype == AAC_DEVTYPE_NATIVE_RAW) + info->reset_state = 0; + } + } } - ret = SUCCESS; - -out: return ret; } @@ -1382,7 +1525,10 @@ static struct scsi_host_template aac_driver_template = { .change_queue_depth = aac_change_queue_depth, .sdev_attrs = aac_dev_attrs, .eh_abort_handler = aac_eh_abort, - .eh_host_reset_handler = aac_eh_reset, + .eh_device_reset_handler = aac_eh_dev_reset, + .eh_target_reset_handler = aac_eh_target_reset, + .eh_bus_reset_handler = aac_eh_bus_reset, + .eh_host_reset_handler = aac_eh_host_reset, .can_queue = AAC_NUM_IO_FIB, .this_id = MAXIMUM_NUM_CONTAINERS, .sg_tablesize = 16, @@ -1457,7 +1603,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* * Only series 7 needs freset. */ - if (pdev->device == PMC_DEVICE_S7) + if (pdev->device == PMC_DEVICE_S7) pdev->needs_freset = 1; list_for_each_entry(aac, &aac_devices, entry) { |