From 5236467ae72ecd71baa162b7734c57bfe8fa0ff9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 10 Mar 2006 23:24:55 +0100 Subject: [SCSI] megaraid/megaraid_mm.c: fix a NULL pointer dereference This patch fixes a NULL pointer dereference spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_mm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 8f3ce0432295..e8f534fb336b 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -898,10 +898,8 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); - if (!adapter) { - rval = -ENOMEM; - goto memalloc_error; - } + if (!adapter) + return -ENOMEM; memset(adapter, 0, sizeof(mraid_mmadp_t)); -- cgit v1.2.2 From a0f9b48dc0954c48a6b0342d9697886be6b0e4d3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:52:56 -0400 Subject: [SCSI] lpfc 8.1.5 : Fix Discovery processing for NPorts that hit nodev_tmo during discovery Fix Discovery processing for NPorts that hit nodev_tmo during discovery Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_disc.h | 1 + drivers/scsi/lpfc/lpfc_hbadisc.c | 2 + drivers/scsi/lpfc/lpfc_nportdisc.c | 98 +++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 8932b1be2b60..41cf5d3ea6ce 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -113,6 +113,7 @@ struct lpfc_nodelist { #define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from NPR list */ #define NLP_DELAY_REMOVE 0x4000000 /* Defer removal till end of DSM */ +#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ /* Defines for list searchs */ #define NLP_SEARCH_MAPPED 0x1 /* search mapped */ diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 6721e679df62..2a2e2eb406ac 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1238,6 +1238,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) evt_listp); } + nlp->nlp_flag &= ~NLP_NODEV_REMOVE; nlp->nlp_type |= NLP_FC_NODE; break; case NLP_MAPPED_LIST: @@ -1258,6 +1259,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) evt_listp); } + nlp->nlp_flag &= ~NLP_NODEV_REMOVE; break; case NLP_NPR_LIST: nlp->nlp_flag |= list; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 3d77bd999b70..c48ec631a33b 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -832,11 +832,17 @@ static uint32_t lpfc_device_rm_plogi_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp, 1); + if(ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } + else { + /* software abort outstanding PLOGI */ + lpfc_els_abort(phba, ndlp, 1); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - return NLP_STE_FREED_NODE; + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } } static uint32_t @@ -851,7 +857,7 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); return ndlp->nlp_state; @@ -987,11 +993,17 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp, 1); + if(ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } + else { + /* software abort outstanding ADISC */ + lpfc_els_abort(phba, ndlp, 1); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - return NLP_STE_FREED_NODE; + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } } static uint32_t @@ -1006,7 +1018,7 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_flag |= NLP_NPR_ADISC; spin_unlock_irq(phba->host->host_lock); @@ -1133,8 +1145,14 @@ lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - return NLP_STE_FREED_NODE; + if(ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } + else { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } } static uint32_t @@ -1146,7 +1164,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); return ndlp->nlp_state; } @@ -1278,11 +1296,17 @@ static uint32_t lpfc_device_rm_prli_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - /* software abort outstanding PRLI */ - lpfc_els_abort(phba, ndlp, 1); + if(ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } + else { + /* software abort outstanding PLOGI */ + lpfc_els_abort(phba, ndlp, 1); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - return NLP_STE_FREED_NODE; + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } } @@ -1313,7 +1337,7 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); return ndlp->nlp_state; } @@ -1386,7 +1410,7 @@ lpfc_device_recov_unmap_node(struct lpfc_hba * phba, ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE; ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); lpfc_disc_set_adisc(phba, ndlp); return ndlp->nlp_state; @@ -1469,7 +1493,7 @@ lpfc_device_recov_mapped_node(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); lpfc_disc_set_adisc(phba, ndlp); return ndlp->nlp_state; @@ -1617,9 +1641,16 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { struct lpfc_iocbq *cmdiocb, *rspiocb; + IOCB_t *irsp; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; + + irsp = &rspiocb->iocb; + if (irsp->ulpStatus) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } return ndlp->nlp_state; } @@ -1628,9 +1659,16 @@ lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { struct lpfc_iocbq *cmdiocb, *rspiocb; + IOCB_t *irsp; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; + + irsp = &rspiocb->iocb; + if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } return ndlp->nlp_state; } @@ -1649,9 +1687,16 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba, uint32_t evt) { struct lpfc_iocbq *cmdiocb, *rspiocb; + IOCB_t *irsp; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; + + irsp = &rspiocb->iocb; + if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } return ndlp->nlp_state; } @@ -1668,7 +1713,12 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba, if (!mb->mbxStatus) ndlp->nlp_rpi = mb->un.varWords[0]; - + else { + if (ndlp->nlp_flag & NLP_NODEV_REMOVE) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } + } return ndlp->nlp_state; } @@ -1677,6 +1727,10 @@ lpfc_device_rm_npr_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { + if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); return NLP_STE_FREED_NODE; } @@ -1687,7 +1741,7 @@ lpfc_device_recov_npr_node(struct lpfc_hba * phba, uint32_t evt) { spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); if (ndlp->nlp_flag & NLP_DELAY_TMO) { lpfc_cancel_retry_delay_tmo(phba, ndlp); -- cgit v1.2.2 From 4b0b91d4611aba058c16440f9841906853741330 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:00 -0400 Subject: [SCSI] lpfc 8.1.5 : Use asynchronous ABTS completion to speed up abort completions Use asynchronous ABTS completion to speed up abort completions Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_crtn.h | 1 - drivers/scsi/lpfc/lpfc_els.c | 7 ------- drivers/scsi/lpfc/lpfc_hw.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 9 --------- drivers/scsi/lpfc/lpfc_mbox.c | 33 +++------------------------------ drivers/scsi/lpfc/lpfc_nportdisc.c | 4 ---- 6 files changed, 4 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index fad607b2e6f4..ee22173fce43 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -27,7 +27,6 @@ void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_set_slim(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *, uint32_t); void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4813beaaca8f..45abc76ff898 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -302,10 +302,6 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0)) goto fail_free_mbox; - /* - * set_slim mailbox command needs to execute first, - * queue this command to be processed later. - */ mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; mbox->context2 = ndlp; @@ -1872,9 +1868,6 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, if (mbox) { if ((rspiocb->iocb.ulpStatus == 0) && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { - /* set_slim mailbox command needs to execute first, - * queue this command to be processed later. - */ lpfc_unreg_rpi(phba, ndlp); mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; mbox->context2 = ndlp; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 54d04188f7cc..b12569eefd1c 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1539,6 +1539,7 @@ typedef struct { #define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */ #define FLAGS_LINK_SPEED 0x0800 /* Bit 11 */ +#define FLAGS_IMED_ABORT 0x04000 /* Bit 14 */ uint32_t link_speed; #define LINK_SPEED_AUTO 0 /* Auto selection */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 66d5d003555d..033778ced16c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -294,15 +294,6 @@ lpfc_config_port_post(struct lpfc_hba * phba) } } - /* This should turn on DELAYED ABTS for ELS timeouts */ - lpfc_set_slim(phba, pmb, 0x052198, 0x1); - if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - phba->hba_state = LPFC_HBA_ERROR; - mempool_free( pmb, phba->mbox_mem_pool); - return -EIO; - } - - lpfc_read_config(phba, pmb); if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { lpfc_printf_log(phba, diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index c585e2b2e589..e42f22aaf71b 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -200,6 +200,9 @@ lpfc_init_link(struct lpfc_hba * phba, break; } + /* Enable asynchronous ABTS responses from firmware */ + mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT; + /* NEW_FEATURE * Setting up the link speed */ @@ -292,36 +295,6 @@ lpfc_unreg_did(struct lpfc_hba * phba, uint32_t did, LPFC_MBOXQ_t * pmb) return; } -/***********************************************/ - -/* command to write slim */ -/***********************************************/ -void -lpfc_set_slim(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t addr, - uint32_t value) -{ - MAILBOX_t *mb; - - mb = &pmb->mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - /* addr = 0x090597 is AUTO ABTS disable for ELS commands */ - /* addr = 0x052198 is DELAYED ABTS enable for ELS commands */ - - /* - * Always turn on DELAYED ABTS for ELS timeouts - */ - if ((addr == 0x052198) && (value == 0)) - value = 1; - - mb->un.varWords[0] = addr; - mb->un.varWords[1] = value; - - mb->mbxCommand = MBX_SET_SLIM; - mb->mbxOwner = OWN_HOST; - return; -} - /**********************************************/ /* lpfc_read_nv Issue a READ CONFIG */ /* mailbox command */ diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index c48ec631a33b..adebe626a23f 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -788,10 +788,6 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba, if (lpfc_reg_login (phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp, mbox, 0) == 0) { - /* set_slim mailbox command needs to - * execute first, queue this command to - * be processed later. - */ switch (ndlp->nlp_DID) { case NameServer_DID: mbox->mbox_cmpl = -- cgit v1.2.2 From 82d9a2a2900b17223117dc10b56503acc678c337 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:05 -0400 Subject: [SCSI] lpfc 8.1.5 : Fixed FC protocol violation in handling of PRLO. Fixed FC protocol violation in handling of PRLO. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 18 ++++++++++++++++++ drivers/scsi/lpfc/lpfc_hw.h | 2 ++ drivers/scsi/lpfc/lpfc_nportdisc.c | 32 ++++++++++++++++++-------------- 3 files changed, 38 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 45abc76ff898..e3d8b7f47f12 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1913,6 +1913,7 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag, uint8_t *pcmd; uint16_t cmdsize; int rc; + ELS_PKT *els_pkt_ptr; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ @@ -1951,6 +1952,23 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag, pcmd += sizeof (uint32_t); memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm)); break; + case ELS_CMD_PRLO: + cmdsize = sizeof (uint32_t) + sizeof (PRLO); + elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, + ndlp, ndlp->nlp_DID, ELS_CMD_PRLO); + if (!elsiocb) + return 1; + + icmd = &elsiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri */ + pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + + memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt, + sizeof (uint32_t) + sizeof (PRLO)); + *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC; + els_pkt_ptr = (ELS_PKT *) pcmd; + els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED; + break; default: return 1; } diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index b12569eefd1c..eedf98801366 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -449,6 +449,7 @@ struct serv_parm { /* Structure is in Big Endian format */ #define ELS_CMD_RRQ 0x12000000 #define ELS_CMD_PRLI 0x20100014 #define ELS_CMD_PRLO 0x21100014 +#define ELS_CMD_PRLO_ACC 0x02100014 #define ELS_CMD_PDISC 0x50000000 #define ELS_CMD_FDISC 0x51000000 #define ELS_CMD_ADISC 0x52000000 @@ -484,6 +485,7 @@ struct serv_parm { /* Structure is in Big Endian format */ #define ELS_CMD_RRQ 0x12 #define ELS_CMD_PRLI 0x14001020 #define ELS_CMD_PRLO 0x14001021 +#define ELS_CMD_PRLO_ACC 0x14001002 #define ELS_CMD_PDISC 0x50 #define ELS_CMD_FDISC 0x51 #define ELS_CMD_ADISC 0x52 diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index adebe626a23f..27d60ad897cd 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -465,14 +465,18 @@ lpfc_rcv_padisc(struct lpfc_hba * phba, static int lpfc_rcv_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, - struct lpfc_iocbq *cmdiocb) + struct lpfc_iocbq *cmdiocb, + uint32_t els_cmd) { /* Put ndlp on NPR list with 1 sec timeout for plogi, ACC logo */ /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary * PLOGIs during LOGO storms from a device. */ ndlp->nlp_flag |= NLP_LOGO_ACC; - lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); + if (els_cmd == ELS_CMD_PRLO) + lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0); + else + lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); if (!(ndlp->nlp_type & NLP_FABRIC) || (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { @@ -681,7 +685,7 @@ lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba, /* software abort outstanding PLOGI */ lpfc_els_abort(phba, ndlp, 1); - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -907,7 +911,7 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba, /* software abort outstanding ADISC */ lpfc_els_abort(phba, ndlp, 0); - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -934,7 +938,7 @@ lpfc_rcv_prlo_adisc_issue(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; /* Treat like rcv logo */ - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO); return ndlp->nlp_state; } @@ -1056,7 +1060,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1081,7 +1085,7 @@ lpfc_rcv_prlo_reglogin_issue(struct lpfc_hba * phba, struct lpfc_iocbq *cmdiocb; cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); + lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0); return ndlp->nlp_state; } @@ -1200,7 +1204,7 @@ lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba, /* Software abort outstanding PRLI before sending acc */ lpfc_els_abort(phba, ndlp, 1); - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1228,7 +1232,7 @@ lpfc_rcv_prlo_prli_issue(struct lpfc_hba * phba, struct lpfc_iocbq *cmdiocb; cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); + lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0); return ndlp->nlp_state; } @@ -1371,7 +1375,7 @@ lpfc_rcv_logo_unmap_node(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1395,7 +1399,7 @@ lpfc_rcv_prlo_unmap_node(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); + lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0); return ndlp->nlp_state; } @@ -1444,7 +1448,7 @@ lpfc_rcv_logo_mapped_node(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1476,7 +1480,7 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_hba * phba, spin_unlock_irq(phba->host->host_lock); /* Treat like rcv logo */ - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO); return ndlp->nlp_state; } @@ -1571,7 +1575,7 @@ lpfc_rcv_logo_npr_node(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } -- cgit v1.2.2 From defbcf11ab56e09965b2135d70f44a82a5ab5fc3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 16 Apr 2006 22:26:50 -0400 Subject: [SCSI] lpfc 8.1.5 : Fix cleanup code in the lpfc_pci_probe_one() error code path Fix cleanup code in the lpfc_pci_probe_one() error code path. This changes the original patch by: - hardsetting the return value from lpfc_pci_probe_one() to -ENODEV (negative value) if we fail attach - removes the checks from lpfc_pci_remove_one() validating the host and phba pointers as it's no longer needed. Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 033778ced16c..1b16ca0f5007 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1618,7 +1618,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) error = lpfc_alloc_sysfs_attr(phba); if (error) - goto out_kthread_stop; + goto out_remove_host; error = request_irq(phba->pcidev->irq, lpfc_intr_handler, SA_SHIRQ, LPFC_DRIVER_NAME, phba); @@ -1635,8 +1635,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; error = lpfc_sli_hba_setup(phba); - if (error) + if (error) { + error = -ENODEV; goto out_free_irq; + } if (phba->cfg_poll & DISABLE_FCP_RING_INT) { spin_lock_irq(phba->host->host_lock); @@ -1691,6 +1693,9 @@ out_free_irq: free_irq(phba->pcidev->irq, phba); out_free_sysfs_attr: lpfc_free_sysfs_attr(phba); +out_remove_host: + fc_remove_host(phba->host); + scsi_remove_host(phba->host); out_kthread_stop: kthread_stop(phba->worker_thread); out_free_iocbq: @@ -1712,12 +1717,14 @@ out_iounmap_slim: out_idr_remove: idr_remove(&lpfc_hba_index, phba->brd_no); out_put_host: + phba->host = NULL; scsi_host_put(host); out_release_regions: pci_release_regions(pdev); out_disable_device: pci_disable_device(pdev); out: + pci_set_drvdata(pdev, NULL); return error; } -- cgit v1.2.2 From 10d4e957e027b96adfed05c3af1d3fd782a242fe Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:15 -0400 Subject: [SCSI] lpfc 8.1.5 : Additional fixes to LOGO, PLOGI, and RSCN processing Additional fixes to LOGO, PLOGI, and RSCN processing Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 68 +++++++++++++++++++++------------------- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 ++ 2 files changed, 37 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index e3d8b7f47f12..806c337b630b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -777,25 +777,26 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, if (disc && phba->num_disc_nodes) { /* Check to see if there are more PLOGIs to be sent */ lpfc_more_plogi(phba); - } - if (phba->num_disc_nodes == 0) { - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(phba->host->host_lock); + if (phba->num_disc_nodes == 0) { + spin_lock_irq(phba->host->host_lock); + phba->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(phba->host->host_lock); - lpfc_can_disctmo(phba); - if (phba->fc_flag & FC_RSCN_MODE) { - /* Check to see if more RSCNs came in while we were - * processing this one. - */ - if ((phba->fc_rscn_id_cnt == 0) && - (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(phba->host->host_lock); - } else { - lpfc_els_handle_rscn(phba); + lpfc_can_disctmo(phba); + if (phba->fc_flag & FC_RSCN_MODE) { + /* + * Check to see if more RSCNs came in while + * we were processing this one. + */ + if ((phba->fc_rscn_id_cnt == 0) && + (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { + spin_lock_irq(phba->host->host_lock); + phba->fc_flag &= ~FC_RSCN_MODE; + spin_unlock_irq(phba->host->host_lock); + } else { + lpfc_els_handle_rscn(phba); + } } } } @@ -1259,7 +1260,7 @@ lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; - cmdsize = 2 * (sizeof (uint32_t) + sizeof (struct lpfc_name)); + cmdsize = (2 * sizeof (uint32_t)) + sizeof (struct lpfc_name); elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_LOGO); if (!elsiocb) @@ -1447,22 +1448,23 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp) * PLOGIs to be sent */ lpfc_more_plogi(phba); - } - if (phba->num_disc_nodes == 0) { - phba->fc_flag &= ~FC_NDISC_ACTIVE; - lpfc_can_disctmo(phba); - if (phba->fc_flag & FC_RSCN_MODE) { - /* Check to see if more RSCNs - * came in while we were - * processing this one. - */ - if((phba->fc_rscn_id_cnt==0) && - (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { - phba->fc_flag &= ~FC_RSCN_MODE; - } - else { - lpfc_els_handle_rscn(phba); + if (phba->num_disc_nodes == 0) { + phba->fc_flag &= ~FC_NDISC_ACTIVE; + lpfc_can_disctmo(phba); + if (phba->fc_flag & FC_RSCN_MODE) { + /* + * Check to see if more RSCNs + * came in while we were + * processing this one. + */ + if((phba->fc_rscn_id_cnt==0) && + !(phba->fc_flag & FC_RSCN_DISCOVERY)) { + phba->fc_flag &= ~FC_RSCN_MODE; + } + else { + lpfc_els_handle_rscn(phba); + } } } } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 2a2e2eb406ac..798977de1a66 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1404,6 +1404,8 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba, if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) return 1; case CMD_ELS_REQUEST64_CR: + if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID) + return 1; case CMD_XMIT_ELS_RSP64_CX: if (iocb->context1 == (uint8_t *) ndlp) return 1; -- cgit v1.2.2 From 071fbd3de93fdbe059d492e6a0b691e84cf7be68 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:20 -0400 Subject: [SCSI] lpfc 8.1.5 : Misc small fixes Contains the following misc fixes: - Fix build warnings - Race condition in lpfc_workq_post_event() could corrupt phba->work_list. - nlp_sid was not being initialized properly - Fix some RSCN handling during the re-discovery after Link Up event. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 2 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 14 ++++++-------- drivers/scsi/lpfc/lpfc_init.c | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 806c337b630b..283b7d824c34 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2511,7 +2511,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba, /* If we are about to begin discovery, just ACC the RSCN. * Discovery processing will satisfy it. */ - if (phba->hba_state < LPFC_NS_QRY) { + if (phba->hba_state <= LPFC_NS_QRY) { lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode); return 0; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 798977de1a66..adb086009ae0 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -311,8 +311,8 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2, evtp->evt_arg2 = arg2; evtp->evt = evt; - list_add_tail(&evtp->evt_listp, &phba->work_list); spin_lock_irq(phba->host->host_lock); + list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) wake_up(phba->work_wait); spin_unlock_irq(phba->host->host_lock); @@ -1071,10 +1071,6 @@ lpfc_register_remote_port(struct lpfc_hba * phba, /* initialize static port data */ rport->maxframe_size = ndlp->nlp_maxframe; rport->supported_classes = ndlp->nlp_class_sup; - if ((rport->scsi_target_id != -1) && - (rport->scsi_target_id < MAX_FCP_TARGET)) { - ndlp->nlp_sid = rport->scsi_target_id; - } rdata = rport->dd_data; rdata->pnode = ndlp; @@ -1087,6 +1083,10 @@ lpfc_register_remote_port(struct lpfc_hba * phba, if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) fc_remote_port_rolechg(rport, rport_ids.roles); + if ((rport->scsi_target_id != -1) && + (rport->scsi_target_id < MAX_FCP_TARGET)) { + ndlp->nlp_sid = rport->scsi_target_id; + } return; } @@ -1905,10 +1905,8 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) */ if (ndlp->nlp_flag & NLP_DELAY_TMO) lpfc_cancel_retry_delay_tmo(phba, ndlp); - } else { - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + } else ndlp = NULL; - } } else { flg = ndlp->nlp_flag & NLP_LIST_MASK; if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST)) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1b16ca0f5007..908d0f27706f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -795,7 +795,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) int max_speed; char * ports; char * bus; - } m; + } m = {"", 0, "", ""}; pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype); ports = (hdrtype == 0x80) ? "2-port " : ""; -- cgit v1.2.2 From 36ab26185c0b6060203829bce32eaeab0fa781ae Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:24 -0400 Subject: [SCSI] lpfc 8.1.5 : Change version number to 8.1.5 Change version number to 8.1.5 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 4cf1366108b7..d0f2dc310b00 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.4" +#define LPFC_DRIVER_VERSION "8.1.5" #define LPFC_DRIVER_NAME "lpfc" -- cgit v1.2.2 From 1a34456bbbdaa939ffa567d15a0797c269f901b7 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Tue, 18 Apr 2006 21:09:20 -0700 Subject: [SCSI] Overrun in drivers/scsi/sim710.c This fixes coverity bug id #480. Since id_array is declared as id_array[MAX_SLOTS], the check for i>MAX_SLOTS is obviously false. Signed-off-by: Eric Sesterhenn Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/sim710.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index 3274ab76c8d3..255886a9ac55 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -75,7 +75,7 @@ param_setup(char *str) else if(!strncmp(pos, "id:", 3)) { if(slot == -1) { printk(KERN_WARNING "sim710: Must specify slot for id parameter\n"); - } else if(slot > MAX_SLOTS) { + } else if(slot >= MAX_SLOTS) { printk(KERN_WARNING "sim710: Illegal slot %d for id %d\n", slot, val); } else { id_array[slot] = val; -- cgit v1.2.2 From 77347ff7554b317a0120cb774b3bd6258a2c4bb4 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 18 Apr 2006 21:09:22 -0700 Subject: [SCSI] qla2xxx: only free_irq() after request_irq() succeeds If qla2x00_probe_one() fails before calling request_irq() but gets to qla2x00_free_device() then it will mistakenly try to free an irq it didn't request. It's chosing to free based on ha->pdev->irq which is always set. host->irq is set after request_irq() succeeds so let's use that to decide to free or not. This was observed and tested when a silly set of circumstances lead to firmware loading failing on a 2100. Signed-off-by: Zach Brown Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 017729c59a49..bef84966d7ad 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1700,8 +1700,8 @@ qla2x00_free_device(scsi_qla_host_t *ha) ha->flags.online = 0; /* Detach interrupts */ - if (ha->pdev->irq) - free_irq(ha->pdev->irq, ha); + if (ha->host->irq) + free_irq(ha->host->irq, ha); /* release io space registers */ if (ha->iobase) -- cgit v1.2.2 From 52988410587db6b4992a8c1e6193777e27f37dc7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 18 Apr 2006 21:09:10 -0700 Subject: [SCSI] megaraid: unused variable drivers/scsi/megaraid.c: In function `mega_internal_command': drivers/scsi/megaraid.c:4474: warning: unused variable `flags' Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/megaraid.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 80b68a2481b3..de35ffe2f79d 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4471,7 +4471,6 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru) { Scsi_Cmnd *scmd; struct scsi_device *sdev; - unsigned long flags = 0; scb_t *scb; int rval; -- cgit v1.2.2 From c42bcefb5891c362b72e47070fbf7973e4eb8e1e Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Tue, 18 Apr 2006 21:09:22 -0700 Subject: [SCSI] aic7xxx: ahc_pci_write_config() fix Fix ahc_pci_write_config's (wrong order of arguments). Signed-off-by: Denis Vlasenko Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_pci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 5f586140e057..3adecef21783 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -2036,12 +2036,12 @@ ahc_pci_resume(struct ahc_softc *ahc) * that the OS doesn't know about and rely on our chip * reset handler to handle the rest. */ - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4, - ahc->bus_softc.pci_softc.devconfig); - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1, - ahc->bus_softc.pci_softc.command); - ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1, - ahc->bus_softc.pci_softc.csize_lattime); + ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, + ahc->bus_softc.pci_softc.devconfig, /*bytes*/4); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, + ahc->bus_softc.pci_softc.command, /*bytes*/1); + ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, + ahc->bus_softc.pci_softc.csize_lattime, /*bytes*/1); if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) { struct seeprom_descriptor sd; u_int sxfrctl1; -- cgit v1.2.2 From bd23e94cd70f18700fc366451a8f1427e56ed137 Mon Sep 17 00:00:00 2001 From: "Moore, Eric" Date: Mon, 17 Apr 2006 12:43:04 -0600 Subject: [SCSI] mptfusion: bug fix's for raid components adding/deleting This patch handles case where raid hidden components are not being removed when power turned off to device attached to expander, as well as the case of exposing raid components when power is turned back on to devices attached to an expander. (This is a repost of this patch, with mptsas_is_end_device declared further up in the code.) This patch contains some other miscellaneous bug fix's. Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 4 +- drivers/message/fusion/mptsas.c | 99 ++++++++++++++++++++++++++++----------- drivers/message/fusion/mptscsih.c | 2 +- 3 files changed, 73 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 266414ca2814..ac66a658aa11 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5741,6 +5741,7 @@ static void EventDescriptionStr(u8 event, u32 evData0, char *evStr) { char *ds; + char buf[50]; switch(event) { case MPI_EVENT_NONE: @@ -5841,7 +5842,6 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) break; case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: { - char buf[50]; u8 id = (u8)(evData0); u8 ReasonCode = (u8)(evData0 >> 16); switch (ReasonCode) { @@ -5878,7 +5878,6 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) break; case MPI_EVENT_SAS_PHY_LINK_STATUS: { - char buf[50]; u8 LinkRates = (u8)(evData0 >> 8); u8 PhyNumber = (u8)(evData0); LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >> @@ -5921,7 +5920,6 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) case MPI_EVENT_IR_RESYNC_UPDATE: { u8 resync_complete = (u8)(evData0 >> 16); - char buf[40]; sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete); ds = buf; break; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index e9716b10acea..af6ec553ff7c 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -91,6 +91,7 @@ enum mptsas_hotplug_action { MPTSAS_DEL_DEVICE, MPTSAS_ADD_RAID, MPTSAS_DEL_RAID, + MPTSAS_IGNORE_EVENT, }; struct mptsas_hotplug_event { @@ -298,6 +299,26 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) return rc; } +/* + * Returns true if there is a scsi end device + */ +static inline int +mptsas_is_end_device(struct mptsas_devinfo * attached) +{ + if ((attached->handle) && + (attached->device_info & + MPI_SAS_DEVICE_INFO_END_DEVICE) && + ((attached->device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) | + (attached->device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) | + (attached->device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE))) + return 1; + else + return 0; +} + static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, u32 form, u32 form_specific) @@ -872,7 +893,11 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, SasDevicePage0_t *buffer; dma_addr_t dma_handle; __le64 sas_address; - int error; + int error=0; + + if (ioc->sas_discovery_runtime && + mptsas_is_end_device(device_info)) + goto out; hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; hdr.ExtPageLength = 0; @@ -1009,7 +1034,11 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, CONFIGPARMS cfg; SasExpanderPage1_t *buffer; dma_addr_t dma_handle; - int error; + int error=0; + + if (ioc->sas_discovery_runtime && + mptsas_is_end_device(&phy_info->attached)) + goto out; hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; @@ -1068,26 +1097,6 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, return error; } -/* - * Returns true if there is a scsi end device - */ -static inline int -mptsas_is_end_device(struct mptsas_devinfo * attached) -{ - if ((attached->handle) && - (attached->device_info & - MPI_SAS_DEVICE_INFO_END_DEVICE) && - ((attached->device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) | - (attached->device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) | - (attached->device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE))) - return 1; - else - return 0; -} - static void mptsas_parse_device_info(struct sas_identify *identify, struct mptsas_devinfo *device_info) @@ -1737,6 +1746,9 @@ mptsas_hotplug_work(void *arg) break; case MPTSAS_ADD_DEVICE: + if (ev->phys_disk_num_valid) + mpt_findImVolumes(ioc); + /* * Refresh sas device pg0 data */ @@ -1868,6 +1880,9 @@ mptsas_hotplug_work(void *arg) scsi_device_put(sdev); mpt_findImVolumes(ioc); break; + case MPTSAS_IGNORE_EVENT: + default: + break; } kfree(ev); @@ -1940,7 +1955,8 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, EVENT_DATA_RAID *raid_event_data) { struct mptsas_hotplug_event *ev; - RAID_VOL0_STATUS * volumeStatus; + int status = le32_to_cpu(raid_event_data->SettingsStatus); + int state = (status >> 8) & 0xff; if (ioc->bus_type != SAS) return; @@ -1955,6 +1971,7 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, INIT_WORK(&ev->work, mptsas_hotplug_work, ev); ev->ioc = ioc; ev->id = raid_event_data->VolumeID; + ev->event_type = MPTSAS_IGNORE_EVENT; switch (raid_event_data->ReasonCode) { case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: @@ -1966,6 +1983,25 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, ev->phys_disk_num = raid_event_data->PhysDiskNum; ev->event_type = MPTSAS_DEL_DEVICE; break; + case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: + switch (state) { + case MPI_PD_STATE_ONLINE: + ioc->raid_data.isRaid = 1; + ev->phys_disk_num_valid = 1; + ev->phys_disk_num = raid_event_data->PhysDiskNum; + ev->event_type = MPTSAS_ADD_DEVICE; + break; + case MPI_PD_STATE_MISSING: + case MPI_PD_STATE_NOT_COMPATIBLE: + case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: + case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: + case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: + ev->event_type = MPTSAS_DEL_DEVICE; + break; + default: + break; + } + break; case MPI_EVENT_RAID_RC_VOLUME_DELETED: ev->event_type = MPTSAS_DEL_RAID; break; @@ -1973,11 +2009,18 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, ev->event_type = MPTSAS_ADD_RAID; break; case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: - volumeStatus = (RAID_VOL0_STATUS *) & - raid_event_data->SettingsStatus; - ev->event_type = (volumeStatus->State == - MPI_RAIDVOL0_STATUS_STATE_FAILED) ? - MPTSAS_DEL_RAID : MPTSAS_ADD_RAID; + switch (state) { + case MPI_RAIDVOL0_STATUS_STATE_FAILED: + case MPI_RAIDVOL0_STATUS_STATE_MISSING: + ev->event_type = MPTSAS_DEL_RAID; + break; + case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: + case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: + ev->event_type = MPTSAS_ADD_RAID; + break; + default: + break; + } break; default: break; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 3729062db317..6a71b066bd21 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -877,7 +877,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) struct scsi_cmnd *sc; dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", - vdevice->target_id, vdevice->lun, max)); + vdevice->vtarget->target_id, vdevice->lun, max)); for (ii=0; ii < max; ii++) { if ((sc = hd->ScsiLookup[ii]) != NULL) { -- cgit v1.2.2 From 65207fedcf57dcb854a3ebb9da43c745106fe8d5 Mon Sep 17 00:00:00 2001 From: "Moore, Eric" Date: Fri, 21 Apr 2006 16:14:35 -0600 Subject: [SCSI] - fusion - mptfc bug fix's to prevent deadlock situations mptbase.h bump version number to 3.03.09 remove unneeded flags define workq and remove old fc specific locks mptbase.c initialize new lock and don't initialize two removed locks mptscsih.c when firmware reports target is no longer there, return DID_REQUEUE for fc hosts so that i/o doesn't get killed until the transport has an opportunity to manage the loss via its dev loss timer when the "eh_abort" routine is called, check to see if the driver has the command or not before looking to see if a reset is pending. James Smart and I talked about this and believe that the API for this routine is: if driver doesn't have command, return SUCCESS. This change helps prevent a target from being taken offline. SUCCESS is returned because it's likely that the command completed after error recovery timed it out but before it could be aborted. provide a routine to queue work to newly created workq, and use it. remove "ioc" from mptscsih_abort() it was only used one time. the other references were via hd->ioc, so I just moved it.... net change in references to ioc via hd->ioc is zero move hd->resetPending test and hd->timeouts increment to after the test for whether the command to be aborted remains known to the driver Make certain that the workq exists before queuing work to it. mptfc.c no longer need to lock rport data structures as I was able to single thread the code! I fixed up the debug code to eliminate compilation messages due to type mismatch in the printk. Got rid of some no longer needed rport flags. Initialize and destroy the workq used for the rescan work. simplify the logic regarding the increment of fc_rescan_work_count. use post increment and test for zero vs. pre increment and test for one; eliminate work_count variable: queue_work can be called with the work_lock held as it doesn't sleep Signed-off-by: Michael Reed Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 1 - drivers/message/fusion/mptbase.h | 10 ++- drivers/message/fusion/mptfc.c | 125 +++++++++++++++++++++++--------------- drivers/message/fusion/mptscsih.c | 48 ++++++++------- 4 files changed, 107 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index ac66a658aa11..5fe6e8df50ab 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1189,7 +1189,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); spin_lock_init(&ioc->fc_rescan_work_lock); - spin_lock_init(&ioc->fc_rport_lock); spin_lock_init(&ioc->initializing_hba_lock); /* Initialize the event logging. diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index be7e8501b53c..f673cca507e1 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.03.08" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.08" +#define MPT_LINUX_VERSION_COMMON "3.03.09" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.09" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -489,7 +489,6 @@ typedef struct _RaidCfgData { #define MPT_RPORT_INFO_FLAGS_REGISTERED 0x01 /* rport registered */ #define MPT_RPORT_INFO_FLAGS_MISSING 0x02 /* missing from DevPage0 scan */ -#define MPT_RPORT_INFO_FLAGS_MAPPED_VDEV 0x04 /* target mapped in vdev */ /* * data allocated for each fc rport device @@ -501,7 +500,6 @@ struct mptfc_rport_info struct scsi_target *starget; FCDevicePage0_t pg0; u8 flags; - u8 remap_needed; }; /* @@ -628,11 +626,11 @@ typedef struct _MPT_ADAPTER struct work_struct mptscsih_persistTask; struct list_head fc_rports; - spinlock_t fc_rport_lock; /* list and ri flags */ spinlock_t fc_rescan_work_lock; int fc_rescan_work_count; struct work_struct fc_rescan_work; - + char fc_rescan_work_q_name[KOBJ_NAME_LEN]; + struct workqueue_struct *fc_rescan_work_q; } MPT_ADAPTER; /* diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index b343f2a68b1c..e1fb5a166366 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -355,15 +355,13 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) struct fc_rport *rport; struct mptfc_rport_info *ri; int new_ri = 1; - u64 pn; - unsigned long flags; + u64 pn, nn; VirtTarget *vtarget; if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) return; /* scan list looking for a match */ - spin_lock_irqsave(&ioc->fc_rport_lock, flags); list_for_each_entry(ri, &ioc->fc_rports, list) { pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; if (pn == rport_ids.port_name) { /* match */ @@ -373,11 +371,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) } } if (new_ri) { /* allocate one */ - spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL); if (!ri) return; - spin_lock_irqsave(&ioc->fc_rport_lock, flags); list_add_tail(&ri->list, &ioc->fc_rports); } @@ -387,14 +383,11 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */ if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) { ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED; - spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); rport = fc_remote_port_add(ioc->sh, channel, &rport_ids); - spin_lock_irqsave(&ioc->fc_rport_lock, flags); if (rport) { ri->rport = rport; if (new_ri) /* may have been reset by user */ rport->dev_loss_tmo = mptfc_dev_loss_tmo; - *((struct mptfc_rport_info **)rport->dd_data) = ri; /* * if already mapped, remap here. If not mapped, * target_alloc will allocate vtarget and map, @@ -406,16 +399,20 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) vtarget->target_id = pg0->CurrentTargetID; vtarget->bus_id = pg0->CurrentBus; } - ri->remap_needed = 0; } + /* once dd_data is filled in, commands will issue to hardware */ + *((struct mptfc_rport_info **)rport->dd_data) = ri; + + pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; + nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; dfcprintk ((MYIOC_s_INFO_FMT "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, " "rport tid %d, tmo %d\n", ioc->name, ioc->sh->host_no, pg0->PortIdentifier, - pg0->WWNN, - pg0->WWPN, + (unsigned long long)nn, + (unsigned long long)pn, pg0->CurrentTargetID, ri->rport->scsi_target_id, ri->rport->dev_loss_tmo)); @@ -425,8 +422,6 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) ri = NULL; } } - spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); - } /* @@ -476,7 +471,6 @@ mptfc_target_alloc(struct scsi_target *starget) vtarget->target_id = ri->pg0.CurrentTargetID; vtarget->bus_id = ri->pg0.CurrentBus; ri->starget = starget; - ri->remap_needed = 0; rc = 0; } } @@ -502,10 +496,10 @@ mptfc_slave_alloc(struct scsi_device *sdev) VirtDevice *vdev; struct scsi_target *starget; struct fc_rport *rport; - unsigned long flags; - rport = starget_to_rport(scsi_target(sdev)); + starget = scsi_target(sdev); + rport = starget_to_rport(starget); if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; @@ -519,10 +513,8 @@ mptfc_slave_alloc(struct scsi_device *sdev) return -ENOMEM; } - spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags); sdev->hostdata = vdev; - starget = scsi_target(sdev); vtarget = starget->hostdata; if (vtarget->num_luns == 0) { @@ -535,14 +527,16 @@ mptfc_slave_alloc(struct scsi_device *sdev) vdev->vtarget = vtarget; vdev->lun = sdev->lun; - spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags); - vtarget->num_luns++; + #ifdef DMPT_DEBUG_FC - { + { + u64 nn, pn; struct mptfc_rport_info *ri; ri = *((struct mptfc_rport_info **)rport->dd_data); + pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; + nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; dfcprintk ((MYIOC_s_INFO_FMT "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " "CurrentTargetID %d, %x %llx %llx\n", @@ -550,7 +544,9 @@ mptfc_slave_alloc(struct scsi_device *sdev) sdev->host->host_no, vtarget->num_luns, sdev->id, ri->pg0.CurrentTargetID, - ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN)); + ri->pg0.PortIdentifier, + (unsigned long long)pn, + (unsigned long long)nn)); } #endif @@ -570,11 +566,31 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) done(SCpnt); return 0; } + + /* dd_data is null until finished adding target */ ri = *((struct mptfc_rport_info **)rport->dd_data); - if (unlikely(ri->remap_needed)) - return SCSI_MLQUEUE_HOST_BUSY; + if (unlikely(!ri)) { + dfcprintk ((MYIOC_s_INFO_FMT + "mptfc_qcmd.%d: %d:%d, dd_data is null.\n", + ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, + ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, + SCpnt->device->id,SCpnt->device->lun)); + SCpnt->result = DID_IMM_RETRY << 16; + done(SCpnt); + return 0; + } - return mptscsih_qcmd(SCpnt,done); + err = mptscsih_qcmd(SCpnt,done); +#ifdef DMPT_DEBUG_FC + if (unlikely(err)) { + dfcprintk ((MYIOC_s_INFO_FMT + "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n", + ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, + ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, + SCpnt->device->id,SCpnt->device->lun)); + } +#endif + return err; } static void @@ -615,18 +631,17 @@ mptfc_rescan_devices(void *arg) MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; int ii; int work_to_do; + u64 pn; unsigned long flags; struct mptfc_rport_info *ri; do { /* start by tagging all ports as missing */ - spin_lock_irqsave(&ioc->fc_rport_lock,flags); list_for_each_entry(ri, &ioc->fc_rports, list) { if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; } } - spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); /* * now rescan devices known to adapter, @@ -639,33 +654,24 @@ mptfc_rescan_devices(void *arg) } /* delete devices still missing */ - spin_lock_irqsave(&ioc->fc_rport_lock, flags); list_for_each_entry(ri, &ioc->fc_rports, list) { /* if newly missing, delete it */ - if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED | - MPT_RPORT_INFO_FLAGS_MISSING)) - == (MPT_RPORT_INFO_FLAGS_REGISTERED | - MPT_RPORT_INFO_FLAGS_MISSING)) { + if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) { ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| MPT_RPORT_INFO_FLAGS_MISSING); - ri->remap_needed = 1; - fc_remote_port_delete(ri->rport); - /* - * remote port not really deleted 'cause - * binding is by WWPN and driver only - * registers FCP_TARGETs but cannot trust - * data structures. - */ + fc_remote_port_delete(ri->rport); /* won't sleep */ ri->rport = NULL; + + pn = (u64)ri->pg0.WWPN.High << 32 | + (u64)ri->pg0.WWPN.Low; dfcprintk ((MYIOC_s_INFO_FMT "mptfc_rescan.%d: %llx deleted\n", ioc->name, ioc->sh->host_no, - ri->pg0.WWPN)); + (unsigned long long)pn)); } } - spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); /* * allow multiple passes as target state @@ -870,10 +876,23 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_mptfc_probe; } - for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { - mptfc_init_host_attr(ioc,ii); - mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev); - } + /* initialize workqueue */ + + snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d", + sh->host_no); + ioc->fc_rescan_work_q = + create_singlethread_workqueue(ioc->fc_rescan_work_q_name); + if (!ioc->fc_rescan_work_q) + goto out_mptfc_probe; + + /* + * scan for rports - + * by doing it via the workqueue, some locking is eliminated + */ + + ioc->fc_rescan_work_count = 1; + queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work); + flush_workqueue(ioc->fc_rescan_work_q); return 0; @@ -949,8 +968,18 @@ mptfc_init(void) static void __devexit mptfc_remove(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct mptfc_rport_info *p, *n; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct mptfc_rport_info *p, *n; + struct workqueue_struct *work_q; + unsigned long flags; + + /* destroy workqueue */ + if ((work_q=ioc->fc_rescan_work_q)) { + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); + ioc->fc_rescan_work_q = NULL; + spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); + destroy_workqueue(work_q); + } fc_remove_host(ioc->sh); diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 6a71b066bd21..84fa271eb8f4 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -632,7 +632,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ /* Spoof to SCSI Selection Timeout! */ - sc->result = DID_NO_CONNECT << 16; + if (ioc->bus_type != FC) + sc->result = DID_NO_CONNECT << 16; + /* else fibre, just stall until rescan event */ + else + sc->result = DID_REQUEUE << 16; if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF) hd->sel_timeout[pScsiReq->TargetID]++; @@ -1645,7 +1649,6 @@ int mptscsih_abort(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; - MPT_ADAPTER *ioc; MPT_FRAME_HDR *mf; u32 ctx2abort; int scpnt_idx; @@ -1663,14 +1666,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) return FAILED; } - ioc = hd->ioc; - if (hd->resetPending) { - return FAILED; - } - - if (hd->timeouts < -1) - hd->timeouts++; - /* Find this command */ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { @@ -1684,6 +1679,13 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) return SUCCESS; } + if (hd->resetPending) { + return FAILED; + } + + if (hd->timeouts < -1) + hd->timeouts++; + printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n", hd->ioc->name, SCpnt); scsi_print_command(SCpnt); @@ -1703,7 +1705,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) vdev = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun, - ctx2abort, mptscsih_get_tm_timeout(ioc)); + ctx2abort, mptscsih_get_tm_timeout(hd->ioc)); printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n", hd->ioc->name, @@ -2521,15 +2523,15 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) /* 7. FC: Rescan for blocked rports which might have returned. */ - else if (ioc->bus_type == FC) { - int work_count; - unsigned long flags; - + if (ioc->bus_type == FC) { spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); - work_count = ++ioc->fc_rescan_work_count; + if (ioc->fc_rescan_work_q) { + if (ioc->fc_rescan_work_count++ == 0) { + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_rescan_work); + } + } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); - if (work_count == 1) - schedule_work(&ioc->fc_rescan_work); } dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name)); @@ -2544,7 +2546,6 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { MPT_SCSI_HOST *hd; u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - int work_count; unsigned long flags; devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", @@ -2569,10 +2570,13 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) case MPI_EVENT_RESCAN: /* 06 */ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); - work_count = ++ioc->fc_rescan_work_count; + if (ioc->fc_rescan_work_q) { + if (ioc->fc_rescan_work_count++ == 0) { + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_rescan_work); + } + } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); - if (work_count == 1) - schedule_work(&ioc->fc_rescan_work); break; /* -- cgit v1.2.2 From 4a6fae1d9c0d879d5d46a2a4962220dbf53ac72b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 23 Apr 2006 20:16:02 +0200 Subject: [SCSI] SCSI: aic7xxx_osm_pci resource leak fix. Fix resource leak in drivers/scsi/aic7xxx/aic7xxx_osm_pci.c::ahc_linux_pci_dev_probe() Found by the coverity checker (#668) Signed-off-by: Jesper Juhl Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index cb30d9c1153d..0c9c2f400bf6 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -219,6 +219,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc->flags |= AHC_39BIT_ADDRESSING; } else { if (dma_set_mask(dev, DMA_32BIT_MASK)) { + ahc_free(ahc); printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); return (-ENODEV); } -- cgit v1.2.2 From f3e93f735321ea75108b41cb654c16f92d3f264c Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 25 Apr 2006 16:48:30 -0500 Subject: [SCSI] Fix DVD burning issues. Some pioneer DVDs are apparently returning odd "not ready" status codes that the mid-layer doesn't recognise and so passes back to the user as errors. This patch overhauls our not-ready handling and adds transparent retries for: format in progress rebuild in progress recalculation in progress operation in progress Long write in progress self test in progress The Pioneer was actually returning "long write in progress" Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7b0f9a3810d2..764a8b375ead 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1067,16 +1067,29 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, break; case NOT_READY: /* - * If the device is in the process of becoming ready, - * retry. + * If the device is in the process of becoming + * ready, or has a temporary blockage, retry. */ - if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { - scsi_requeue_command(q, cmd); - return; + if (sshdr.asc == 0x04) { + switch (sshdr.ascq) { + case 0x01: /* becoming ready */ + case 0x04: /* format in progress */ + case 0x05: /* rebuild in progress */ + case 0x06: /* recalculation in progress */ + case 0x07: /* operation in progress */ + case 0x08: /* Long write in progress */ + case 0x09: /* self test in progress */ + scsi_requeue_command(q, cmd); + return; + default: + break; + } } - if (!(req->flags & REQ_QUIET)) + if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Device not ready.\n"); + "Device not ready: "); + scsi_print_sense_hdr("", &sshdr); + } scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: -- cgit v1.2.2 From f2536cbd12e5182558cce42efd41072bd558596b Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 26 Apr 2006 13:48:11 -0500 Subject: [SCSI] scsi: Add IBM 2104-DU3 to blist Some versions of the IBM 2104-DU3 disk enclosure have been observed to hang Inquiries to non zero LUNs to the SES device. This device only has LUN 0, so this patch adds it to the BLIST to prevent scsi core from scanning beyond LUN 0. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index c750d3399a97..941c1e15c899 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -56,6 +56,8 @@ static struct { {"DENON", "DRD-25X", "V", BLIST_NOLUN}, /* locks up */ {"HITACHI", "DK312C", "CM81", BLIST_NOLUN}, /* responds to all lun */ {"HITACHI", "DK314C", "CR21", BLIST_NOLUN}, /* responds to all lun */ + {"IBM", "2104-DU3", NULL, BLIST_NOLUN}, /* locks up */ + {"IBM", "2104-TU3", NULL, BLIST_NOLUN}, /* locks up */ {"IMS", "CDD521/10", "2.06", BLIST_NOLUN}, /* locks up */ {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN}, /* locks up */ {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN}, /* locks up */ -- cgit v1.2.2 From 509e5e5d206ff7ba08011b61a882d09369ec20c3 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Wed, 26 Apr 2006 13:22:37 -0600 Subject: [SCSI] fusion - bug fix stack overflow in mptbase Bug fix for stack overflow in EventDescriptionStr, (a function for debuging firmware events). We allocated 50 bytes on local stack for buff[], however there are places in the code where we've attempted copying in greater than 50 bytes into buff[]. Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 60 +++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 5fe6e8df50ab..9080853fe283 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5735,12 +5735,13 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) return rc; } +# define EVENT_DESCR_STR_SZ 100 + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void EventDescriptionStr(u8 event, u32 evData0, char *evStr) { - char *ds; - char buf[50]; + char *ds = NULL; switch(event) { case MPI_EVENT_NONE: @@ -5777,9 +5778,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) ds = "Loop State(LIP) Change"; else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) - ds = "Loop State(LPE) Change"; /* ??? */ + ds = "Loop State(LPE) Change"; /* ??? */ else - ds = "Loop State(LPB) Change"; /* ??? */ + ds = "Loop State(LPB) Change"; /* ??? */ break; case MPI_EVENT_LOGOUT: ds = "Logout"; @@ -5845,22 +5846,28 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) u8 ReasonCode = (u8)(evData0 >> 16); switch (ReasonCode) { case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: - sprintf(buf,"SAS Device Status Change: Added: id=%d", id); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Added: id=%d", id); break; case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: - sprintf(buf,"SAS Device Status Change: Deleted: id=%d", id); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Deleted: id=%d", id); break; case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - sprintf(buf,"SAS Device Status Change: SMART Data: id=%d", id); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: SMART Data: id=%d", + id); break; case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: - sprintf(buf,"SAS Device Status Change: No Persistancy Added: id=%d", id); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: No Persistancy " + "Added: id=%d", id); break; default: - sprintf(buf,"SAS Device Status Change: Unknown: id=%d", id); - break; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Unknown: id=%d", id); + break; } - ds = buf; break; } case MPI_EVENT_ON_BUS_TIMER_EXPIRED: @@ -5883,34 +5890,40 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT; switch (LinkRates) { case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Rate Unknown",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Phy Disabled",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Failed Speed Nego",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Sata OOB Completed",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_1_5: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Rate 1.5 Gbps",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_3_0: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Rate 3.0 Gpbs",PhyNumber); break; default: - sprintf(buf,"SAS PHY Link Status: Phy=%d", PhyNumber); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d", PhyNumber); break; } - ds = buf; break; } case MPI_EVENT_SAS_DISCOVERY_ERROR: @@ -5919,8 +5932,8 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) case MPI_EVENT_IR_RESYNC_UPDATE: { u8 resync_complete = (u8)(evData0 >> 16); - sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete); - ds = buf; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR Resync Update: Complete = %d:",resync_complete); break; } case MPI_EVENT_IR2: @@ -5973,7 +5986,8 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) ds = "Unknown"; break; } - strcpy(evStr,ds); + if (ds) + strncpy(evStr, ds, EVENT_DESCR_STR_SZ); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5995,7 +6009,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply int ii; int r = 0; int handlers = 0; - char evStr[100]; + char evStr[EVENT_DESCR_STR_SZ]; u8 event; /* -- cgit v1.2.2 From c005fb4fb2d23ba29ad21dee5042b2f8451ca8ba Mon Sep 17 00:00:00 2001 From: "Ju, Seokmann" Date: Thu, 27 Apr 2006 02:33:06 -0700 Subject: [SCSI] megaraid_{mm,mbox}: fix a bug in reset handler When abort failed, the driver gets reset handleer called. In the reset handler, driver calls 'scsi_done()' callback for same SCSI command packet (struct scsi_cmnd) multiple times if there are multiple SCSI command packet in the pend_list. More over, if there are entry in the pend_lsit with IOCTL packet associated, the driver returns it to wrong free_list so that, in turn, the driver could end up with 'NULL pointer dereference..' during I/O command building with incorrect resource. Also, the patch contains several minor/cosmetic changes besides this. Signed-off-by: Seokmann Ju Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_mbox.c | 59 ++++++++++++++++++++++++----------- drivers/scsi/megaraid/megaraid_mbox.h | 7 +++-- 2 files changed, 46 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index c11e5ce6865e..bec1424eda85 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_mbox.c - * Version : v2.20.4.7 (Nov 14 2005) + * Version : v2.20.4.8 (Apr 11 2006) * * Authors: * Atul Mukker @@ -2278,6 +2278,7 @@ megaraid_mbox_dpc(unsigned long devp) unsigned long flags; uint8_t c; int status; + uioc_t *kioc; if (!adapter) return; @@ -2320,6 +2321,9 @@ megaraid_mbox_dpc(unsigned long devp) // remove from local clist list_del_init(&scb->list); + kioc = (uioc_t *)scb->gp; + kioc->status = 0; + megaraid_mbox_mm_done(adapter, scb); continue; @@ -2636,6 +2640,7 @@ megaraid_reset_handler(struct scsi_cmnd *scp) int recovery_window; int recovering; int i; + uioc_t *kioc; adapter = SCP2ADAPTER(scp); raid_dev = ADAP2RAIDDEV(adapter); @@ -2655,32 +2660,51 @@ megaraid_reset_handler(struct scsi_cmnd *scp) // Also, reset all the commands currently owned by the driver spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { - list_del_init(&scb->list); // from pending list - con_log(CL_ANN, (KERN_WARNING - "megaraid: %ld:%d[%d:%d], reset from pending list\n", - scp->serial_number, scb->sno, - scb->dev_channel, scb->dev_target)); + if (scb->sno >= MBOX_MAX_SCSI_CMDS) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: IOCTL packet with %d[%d:%d] being reset\n", + scb->sno, scb->dev_channel, scb->dev_target)); - scp->result = (DID_RESET << 16); - scp->scsi_done(scp); + scb->status = -1; - megaraid_dealloc_scb(adapter, scb); + kioc = (uioc_t *)scb->gp; + kioc->status = -EFAULT; + + megaraid_mbox_mm_done(adapter, scb); + } else { + if (scb->scp == scp) { // Found command + con_log(CL_ANN, (KERN_WARNING + "megaraid: %ld:%d[%d:%d], reset from pending list\n", + scp->serial_number, scb->sno, + scb->dev_channel, scb->dev_target)); + } else { + con_log(CL_ANN, (KERN_WARNING + "megaraid: IO packet with %d[%d:%d] being reset\n", + scb->sno, scb->dev_channel, scb->dev_target)); + } + + scb->scp->result = (DID_RESET << 16); + scb->scp->scsi_done(scb->scp); + + megaraid_dealloc_scb(adapter, scb); + } } spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); if (adapter->outstanding_cmds) { con_log(CL_ANN, (KERN_NOTICE "megaraid: %d outstanding commands. Max wait %d sec\n", - adapter->outstanding_cmds, MBOX_RESET_WAIT)); + adapter->outstanding_cmds, + (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT))); } recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; recovering = adapter->outstanding_cmds; - for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) { + for (i = 0; i < recovery_window; i++) { megaraid_ack_sequence(adapter); @@ -2689,12 +2713,11 @@ megaraid_reset_handler(struct scsi_cmnd *scp) con_log(CL_ANN, ( "megaraid mbox: Wait for %d commands to complete:%d\n", adapter->outstanding_cmds, - MBOX_RESET_WAIT - i)); + (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i)); } // bailout if no recovery happended in reset time - if ((i == MBOX_RESET_WAIT) && - (recovering == adapter->outstanding_cmds)) { + if (adapter->outstanding_cmds == 0) { break; } @@ -2918,12 +2941,13 @@ mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[]) wmb(); WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); - for (i = 0; i < 0xFFFFF; i++) { + for (i = 0; i < MBOX_SYNC_WAIT_CNT; i++) { if (mbox->numstatus != 0xFF) break; rmb(); + udelay(MBOX_SYNC_DELAY_200); } - if (i == 0xFFFFF) { + if (i == MBOX_SYNC_WAIT_CNT) { // We may need to re-calibrate the counter con_log(CL_ANN, (KERN_CRIT "megaraid: fast sync command timed out\n")); @@ -3475,7 +3499,7 @@ megaraid_cmm_register(adapter_t *adapter) adp.drvr_data = (unsigned long)adapter; adp.pdev = adapter->pdev; adp.issue_uioc = megaraid_mbox_mm_handler; - adp.timeout = 300; + adp.timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; adp.max_kioc = MBOX_MAX_USER_CMDS; if ((rval = mraid_mm_register_adp(&adp)) != 0) { @@ -3702,7 +3726,6 @@ megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb) unsigned long flags; kioc = (uioc_t *)scb->gp; - kioc->status = 0; mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; mbox64->mbox32.status = scb->status; raw_mbox = (uint8_t *)&mbox64->mbox32; diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h index 882fb1a0b575..868fb0ec93e7 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.h +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -21,8 +21,8 @@ #include "megaraid_ioctl.h" -#define MEGARAID_VERSION "2.20.4.7" -#define MEGARAID_EXT_VERSION "(Release Date: Mon Nov 14 12:27:22 EST 2005)" +#define MEGARAID_VERSION "2.20.4.8" +#define MEGARAID_EXT_VERSION "(Release Date: Mon Apr 11 12:27:22 EST 2006)" /* @@ -100,6 +100,9 @@ #define MBOX_BUSY_WAIT 10 // max usec to wait for busy mailbox #define MBOX_RESET_WAIT 180 // wait these many seconds in reset #define MBOX_RESET_EXT_WAIT 120 // extended wait reset +#define MBOX_SYNC_WAIT_CNT 0xFFFF // wait loop index for synchronous mode + +#define MBOX_SYNC_DELAY_200 200 // 200 micro-seconds /* * maximum transfer that can happen through the firmware commands issued -- cgit v1.2.2 From 2ea0020250f6aeaec1ed3adf9069973a91eff57c Mon Sep 17 00:00:00 2001 From: Michael Reed Date: Thu, 27 Apr 2006 16:25:30 -0700 Subject: [SCSI] qla2xxx: Correct eh_abort recovery logic. Fix the driver to return SUCCESS if the firmware or driver doesn't have a command to abort, i.e., it's already been returned. Without this patch, error recovery will take the target offline as it tries harder and harder to get the driver to return the command it no longer has. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index bef84966d7ad..584fe5d8e507 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -599,6 +599,7 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) * Either SUCCESS or FAILED. * * Note: +* Only return FAILED if command not returned by firmware. **************************************************************************/ int qla2xxx_eh_abort(struct scsi_cmnd *cmd) @@ -609,11 +610,12 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) unsigned int id, lun; unsigned long serial; unsigned long flags; + int wait = 0; if (!CMD_SP(cmd)) - return FAILED; + return SUCCESS; - ret = FAILED; + ret = SUCCESS; id = cmd->device->id; lun = cmd->device->lun; @@ -642,7 +644,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) } else { DEBUG3(printk("%s(%ld): abort_command " "mbx success.\n", __func__, ha->host_no)); - ret = SUCCESS; + wait = 1; } spin_lock_irqsave(&ha->hardware_lock, flags); @@ -651,17 +653,18 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for the command to be returned. */ - if (ret == SUCCESS) { + if (wait) { if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) { qla_printk(KERN_ERR, ha, "scsi(%ld:%d:%d): Abort handler timed out -- %lx " "%x.\n", ha->host_no, id, lun, serial, ret); + ret = FAILED; } } qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d): Abort command issued -- %lx %x.\n", ha->host_no, - id, lun, serial, ret); + "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n", + ha->host_no, id, lun, wait, serial, ret); return ret; } -- cgit v1.2.2 From e5dbfa6621732a110514fb10f9a43f0e8f4befd4 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 14 Apr 2006 13:52:18 +0900 Subject: [SCSI] ibmvscsi: fix leak when failing to send srp event Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 0a8ad37ae899..2e9be83a697f 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -739,7 +739,8 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) { struct viosrp_adapter_info *req; struct srp_event_struct *evt_struct; - + dma_addr_t addr; + evt_struct = get_event_struct(&hostdata->pool); if (!evt_struct) { printk(KERN_ERR "ibmvscsi: couldn't allocate an event " @@ -757,10 +758,10 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) req->common.type = VIOSRP_ADAPTER_INFO_TYPE; req->common.length = sizeof(hostdata->madapter_info); - req->buffer = dma_map_single(hostdata->dev, - &hostdata->madapter_info, - sizeof(hostdata->madapter_info), - DMA_BIDIRECTIONAL); + req->buffer = addr = dma_map_single(hostdata->dev, + &hostdata->madapter_info, + sizeof(hostdata->madapter_info), + DMA_BIDIRECTIONAL); if (dma_mapping_error(req->buffer)) { printk(KERN_ERR @@ -770,8 +771,13 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) return; } - if (ibmvscsi_send_srp_event(evt_struct, hostdata)) + if (ibmvscsi_send_srp_event(evt_struct, hostdata)) { printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n"); + dma_unmap_single(hostdata->dev, + addr, + sizeof(hostdata->madapter_info), + DMA_BIDIRECTIONAL); + } }; /** @@ -1259,6 +1265,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, { struct viosrp_host_config *host_config; struct srp_event_struct *evt_struct; + dma_addr_t addr; int rc; evt_struct = get_event_struct(&hostdata->pool); @@ -1279,8 +1286,9 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, memset(host_config, 0x00, sizeof(*host_config)); host_config->common.type = VIOSRP_HOST_CONFIG_TYPE; host_config->common.length = length; - host_config->buffer = dma_map_single(hostdata->dev, buffer, length, - DMA_BIDIRECTIONAL); + host_config->buffer = addr = dma_map_single(hostdata->dev, buffer, + length, + DMA_BIDIRECTIONAL); if (dma_mapping_error(host_config->buffer)) { printk(KERN_ERR @@ -1291,11 +1299,9 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, init_completion(&evt_struct->comp); rc = ibmvscsi_send_srp_event(evt_struct, hostdata); - if (rc == 0) { + if (rc == 0) wait_for_completion(&evt_struct->comp); - dma_unmap_single(hostdata->dev, host_config->buffer, - length, DMA_BIDIRECTIONAL); - } + dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL); return rc; } -- cgit v1.2.2 From 68ac64cd3fd89fdaa091701f6ab98a9065e9b1b5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 30 Apr 2006 11:13:50 +0100 Subject: [SERIAL] Clean up serial locking when obtaining a reference to a port The locking for the uart_port is over complicated, and can be simplified if we introduce a flag to indicate that a port is "dead" and will be removed. This also helps the validator because it removes a case of non-nested unlock ordering. Signed-off-by: Russell King Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton --- drivers/serial/serial_core.c | 114 +++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index fcd7744c4253..aeb8153ccf24 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1500,20 +1500,18 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) static struct uart_state *uart_get(struct uart_driver *drv, int line) { struct uart_state *state; + int ret = 0; - mutex_lock(&port_mutex); state = drv->state + line; if (mutex_lock_interruptible(&state->mutex)) { - state = ERR_PTR(-ERESTARTSYS); - goto out; + ret = -ERESTARTSYS; + goto err; } state->count++; - if (!state->port) { - state->count--; - mutex_unlock(&state->mutex); - state = ERR_PTR(-ENXIO); - goto out; + if (!state->port || state->port->flags & UPF_DEAD) { + ret = -ENXIO; + goto err_unlock; } if (!state->info) { @@ -1531,15 +1529,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) tasklet_init(&state->info->tlet, uart_tasklet_action, (unsigned long)state); } else { - state->count--; - mutex_unlock(&state->mutex); - state = ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto err_unlock; } } - - out: - mutex_unlock(&port_mutex); return state; + + err_unlock: + state->count--; + mutex_unlock(&state->mutex); + err: + return ERR_PTR(ret); } /* @@ -2085,45 +2085,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, } } -/* - * This reverses the effects of uart_configure_port, hanging up the - * port before removal. - */ -static void -uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state) -{ - struct uart_port *port = state->port; - struct uart_info *info = state->info; - - if (info && info->tty) - tty_vhangup(info->tty); - - mutex_lock(&state->mutex); - - state->info = NULL; - - /* - * Free the port IO and memory resources, if any. - */ - if (port->type != PORT_UNKNOWN) - port->ops->release_port(port); - - /* - * Indicate that there isn't a port here anymore. - */ - port->type = PORT_UNKNOWN; - - /* - * Kill the tasklet, and free resources. - */ - if (info) { - tasklet_kill(&info->tlet); - kfree(info); - } - - mutex_unlock(&state->mutex); -} - static struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, @@ -2270,6 +2231,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) state = drv->state + port->line; mutex_lock(&port_mutex); + mutex_lock(&state->mutex); if (state->port) { ret = -EINVAL; goto out; @@ -2304,7 +2266,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) port->cons && !(port->cons->flags & CON_ENABLED)) register_console(port->cons); + /* + * Ensure UPF_DEAD is not set. + */ + port->flags &= ~UPF_DEAD; + out: + mutex_unlock(&state->mutex); mutex_unlock(&port_mutex); return ret; @@ -2322,6 +2290,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state = drv->state + port->line; + struct uart_info *info; BUG_ON(in_interrupt()); @@ -2331,12 +2300,49 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) mutex_lock(&port_mutex); + /* + * Mark the port "dead" - this prevents any opens from + * succeeding while we shut down the port. + */ + mutex_lock(&state->mutex); + port->flags |= UPF_DEAD; + mutex_unlock(&state->mutex); + /* * Remove the devices from devfs */ tty_unregister_device(drv->tty_driver, port->line); - uart_unconfigure_port(drv, state); + info = state->info; + if (info && info->tty) + tty_vhangup(info->tty); + + /* + * All users of this port should now be disconnected from + * this driver, and the port shut down. We should be the + * only thread fiddling with this port from now on. + */ + state->info = NULL; + + /* + * Free the port IO and memory resources, if any. + */ + if (port->type != PORT_UNKNOWN) + port->ops->release_port(port); + + /* + * Indicate that there isn't a port here anymore. + */ + port->type = PORT_UNKNOWN; + + /* + * Kill the tasklet, and free resources. + */ + if (info) { + tasklet_kill(&info->tlet); + kfree(info); + } + state->port = NULL; mutex_unlock(&port_mutex); -- cgit v1.2.2 From 85835f442e5bbf9d3b8f6e574751da8db77016d2 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 30 Apr 2006 11:15:58 +0100 Subject: [SERIAL] AMD Alchemy UART: claim memory range I've noticed that the 8250/Au1x00 driver (drivers/serial/8250_au1x00.c) doesn't claim UART memory ranges and uses wrong (KSEG1-based) UART addresses instead of the physical ones. Signed-off-by: Sergei Shtylyov Signed-off-by: Russell King --- drivers/serial/8250.c | 6 ++++++ drivers/serial/8250_au1x00.c | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 674b15c78f68..d641ac4e976e 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1906,6 +1906,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) int ret = 0; switch (up->port.iotype) { + case UPIO_AU: + size = 0x100000; + /* fall thru */ case UPIO_MEM: if (!up->port.mapbase) break; @@ -1938,6 +1941,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) unsigned int size = 8 << up->port.regshift; switch (up->port.iotype) { + case UPIO_AU: + size = 0x100000; + /* fall thru */ case UPIO_MEM: if (!up->port.mapbase) break; diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c index 3d1bfd07208d..58015fd14be9 100644 --- a/drivers/serial/8250_au1x00.c +++ b/drivers/serial/8250_au1x00.c @@ -30,13 +30,12 @@ { \ .iobase = _base, \ .membase = (void __iomem *)_base,\ - .mapbase = _base, \ + .mapbase = CPHYSADDR(_base), \ .irq = _irq, \ .uartclk = 0, /* filled */ \ .regshift = 2, \ .iotype = UPIO_AU, \ - .flags = UPF_SKIP_TEST | \ - UPF_IOREMAP, \ + .flags = UPF_SKIP_TEST \ } static struct plat_serial8250_port au1x00_data[] = { -- cgit v1.2.2 From b32b19b8ffc05cbd3bf91c65e205f6a912ca15d9 Mon Sep 17 00:00:00 2001 From: Jon Anders Haugum Date: Sun, 30 Apr 2006 11:20:56 +0100 Subject: [SERIAL] 8250: set divisor register correctly for AMD Alchemy SoC uart Alchemy SoC uart have got a non-standard divisor register that needs some special handling. This patch adds divisor read/write functions with test and special handling for Alchemy internal uart. Signed-off-by: Jon Anders Haugum Signed-off-by: Russell King --- drivers/serial/8250.c | 55 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index d641ac4e976e..9cc74712795d 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -362,6 +362,40 @@ serial_out(struct uart_8250_port *up, int offset, int value) #define serial_inp(up, offset) serial_in(up, offset) #define serial_outp(up, offset, value) serial_out(up, offset, value) +/* Uart divisor latch read */ +static inline int _serial_dl_read(struct uart_8250_port *up) +{ + return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8; +} + +/* Uart divisor latch write */ +static inline void _serial_dl_write(struct uart_8250_port *up, int value) +{ + serial_outp(up, UART_DLL, value & 0xff); + serial_outp(up, UART_DLM, value >> 8 & 0xff); +} + +#ifdef CONFIG_SERIAL_8250_AU1X00 +/* Au1x00 haven't got a standard divisor latch */ +static int serial_dl_read(struct uart_8250_port *up) +{ + if (up->port.iotype == UPIO_AU) + return __raw_readl(up->port.membase + 0x28); + else + return _serial_dl_read(up); +} + +static void serial_dl_write(struct uart_8250_port *up, int value) +{ + if (up->port.iotype == UPIO_AU) + __raw_writel(value, up->port.membase + 0x28); + else + _serial_dl_write(up, value); +} +#else +#define serial_dl_read(up) _serial_dl_read(up) +#define serial_dl_write(up, value) _serial_dl_write(up, value) +#endif /* * For the 16C950 @@ -494,7 +528,8 @@ static void disable_rsa(struct uart_8250_port *up) */ static int size_fifo(struct uart_8250_port *up) { - unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr; + unsigned char old_fcr, old_mcr, old_lcr; + unsigned short old_dl; int count; old_lcr = serial_inp(up, UART_LCR); @@ -505,10 +540,8 @@ static int size_fifo(struct uart_8250_port *up) UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); serial_outp(up, UART_MCR, UART_MCR_LOOP); serial_outp(up, UART_LCR, UART_LCR_DLAB); - old_dll = serial_inp(up, UART_DLL); - old_dlm = serial_inp(up, UART_DLM); - serial_outp(up, UART_DLL, 0x01); - serial_outp(up, UART_DLM, 0x00); + old_dl = serial_dl_read(up); + serial_dl_write(up, 0x0001); serial_outp(up, UART_LCR, 0x03); for (count = 0; count < 256; count++) serial_outp(up, UART_TX, count); @@ -519,8 +552,7 @@ static int size_fifo(struct uart_8250_port *up) serial_outp(up, UART_FCR, old_fcr); serial_outp(up, UART_MCR, old_mcr); serial_outp(up, UART_LCR, UART_LCR_DLAB); - serial_outp(up, UART_DLL, old_dll); - serial_outp(up, UART_DLM, old_dlm); + serial_dl_write(up, old_dl); serial_outp(up, UART_LCR, old_lcr); return count; @@ -750,8 +782,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) serial_outp(up, UART_LCR, 0xE0); - quot = serial_inp(up, UART_DLM) << 8; - quot += serial_inp(up, UART_DLL); + quot = serial_dl_read(up); quot <<= 3; status1 = serial_in(up, 0x04); /* EXCR1 */ @@ -759,8 +790,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ serial_outp(up, 0x04, status1); - serial_outp(up, UART_DLL, quot & 0xff); - serial_outp(up, UART_DLM, quot >> 8); + serial_dl_write(up, quot); serial_outp(up, UART_LCR, 0); @@ -1862,8 +1892,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ } - serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ + serial_dl_write(up, quot); /* * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR -- cgit v1.2.2 From a88d75b257b2b28b26d7d4d2b640f05feb00ad53 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 30 Apr 2006 11:30:15 +0100 Subject: [SERIAL] Remove unconditional enable of TX irq for console A bug report from Gerd Hoffmann has highlighted that unconditionally enabling the transmit interrupt at the end of console writes is very bad. In Gerd's case, it causes the test for buggy UARTs to give false positives, incorrectly identifying ports as buggy when they are not. Moreover, if we unconditionally enable the interrupt, and the port is sharing it's interrupt with other ports, there is the very real possibility that we'll cause an interrupt storm. (Not all ports use OUT2 as an interrupt mask.) Hence, revert part of f91a3715db2bb44fcf08cec642e68f919b70f7f4 and all of f5968b37b3ad35b682b574b578843a0361218aff until a better solution can be found. Signed-off-by: Russell King --- drivers/serial/8250.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 9cc74712795d..e001ea0606ec 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2256,8 +2256,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) * and restore the IER */ wait_for_xmitr(up, BOTH_EMPTY); - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, ier | UART_IER_THRI); + serial_out(up, UART_IER, ier); } static int serial8250_console_setup(struct console *co, char *options) -- cgit v1.2.2 From cd95842ca0ffb0e3df3b459832a60f9f4544ed9e Mon Sep 17 00:00:00 2001 From: Markus Gutschke Date: Sun, 30 Apr 2006 15:34:29 +0100 Subject: [ARM] 3486/1: Mark memory as clobbered by the ARM _syscallX() macros Patch from Markus Gutschke In order to prevent gcc from making incorrect optimizations, all asm() statements that define system calls should report memory as clobbered. Recent versions of the headers for i386 have been changed accordingly, but the ARM headers are still defective. This patch fixes the bug tracked at http://bugzilla.kernel.org/show_bug.cgi?id=6205 Signed-off-by: Markus Gutschke Signed-off-by: Russell King --- drivers/input/touchscreen/corgi_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 1042987856f7..5013703db0e6 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -17,7 +17,7 @@ #include #include #include -#include +//#include #include #include -- cgit v1.2.2 From 81d38428df26377c91e7e193aa4d2fdfdcda300a Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Sun, 30 Apr 2006 15:35:54 +0100 Subject: [ARM] 3485/1: i.MX: MX1 SD/MMC fix of unintentional double start possibility Patch from Pavel Pisa The clock starting imxmci_start_clock() function contains hardware issue workaround, which repeats start attempt, if SDHC does not react on the first trial. But the second start attempt can be taken even, if the first succeed and test code misses time limited clock running phase due to delay caused by schedule to other task or some another device interrupt. This change enables to detect such situation. The performance is not issue, because usually at full clock rate only about six loops in delay cycle are needed. Signed-off-by: Pavel Pisa Acked-by: Sascha Hauer Signed-off-by: Russell King --- drivers/mmc/imxmmc.c | 54 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index ffb7f55d3467..07f36c454bd6 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -102,6 +102,7 @@ struct imxmci_host { #define IMXMCI_PEND_CPU_DATA_b 5 #define IMXMCI_PEND_CARD_XCHG_b 6 #define IMXMCI_PEND_SET_INIT_b 7 +#define IMXMCI_PEND_STARTED_b 8 #define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b) #define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b) @@ -111,6 +112,7 @@ struct imxmci_host { #define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b) #define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b) #define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b) +#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b) static void imxmci_stop_clock(struct imxmci_host *host) { @@ -131,23 +133,52 @@ static void imxmci_stop_clock(struct imxmci_host *host) dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n"); } -static void imxmci_start_clock(struct imxmci_host *host) +static int imxmci_start_clock(struct imxmci_host *host) { - int i = 0; + unsigned int trials = 0; + unsigned int delay_limit = 128; + unsigned long flags; + MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK; - while(i < 0x1000) { - if(!(i & 0x7f)) - MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; - if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) { - /* Check twice before cut */ + clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); + + /* + * Command start of the clock, this usually succeeds in less + * then 6 delay loops, but during card detection (low clockrate) + * it takes up to 5000 delay loops and sometimes fails for the first time + */ + MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; + + do { + unsigned int delay = delay_limit; + + while(delay--){ if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) - return; + /* Check twice before cut */ + if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) + return 0; + + if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) + return 0; } - i++; - } - dev_dbg(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); + local_irq_save(flags); + /* + * Ensure, that request is not doubled under all possible circumstances. + * It is possible, that cock running state is missed, because some other + * IRQ or schedule delays this function execution and the clocks has + * been already stopped by other means (response processing, SDHC HW) + */ + if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) + MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; + local_irq_restore(flags); + + } while(++trials<256); + + dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); + + return -1; } static void imxmci_softreset(void) @@ -622,6 +653,7 @@ static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs) atomic_set(&host->stuck_timeout, 0); host->status_reg = stat; set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); + set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); tasklet_schedule(&host->tasklet); return IRQ_RETVAL(handled);; -- cgit v1.2.2 From cc873e1aa1fa916a485294117a9846e668505671 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 30 Apr 2006 23:59:16 +0200 Subject: kbuild: drivers/video/logo/ - fix ident glitch Jan Engelhardt wrote: while compiling 2.6.17-rc2 with allyesconfig, this showed up: ... LOGO drivers/video/logo/logo_superh_clut224.c CC drivers/video/logo/logo_linux_mono.o ... A tab had sneaked in. Convert it to a few spaces. Signed-off-by: Sam Ravnborg --- drivers/video/logo/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index 4ef5cd19609d..b985dfad6c63 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -34,7 +34,7 @@ extra-y += $(call logo-cfiles,_clut224,ppm) extra-y += $(call logo-cfiles,_gray256,pgm) # Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..." -quiet_cmd_logo = LOGO $@ +quiet_cmd_logo = LOGO $@ cmd_logo = scripts/pnmtologo \ -t $(patsubst $*_%,%,$(notdir $(basename $<))) \ -n $(notdir $(basename $<)) -o $@ $< -- cgit v1.2.2 From d8a5a8d7cc32e4474326e0ecc1b959063490efc9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 May 2006 16:04:29 +0100 Subject: [SERIAL] 8250: add locking to console write function x86 SMP breaks as a result of the previous change, we have no real option other than to add locking to the 8250 console write function. If an oops is in progress, try to acquire the lock. If we fail to do so, continue anyway. Signed-off-by: Russell King --- drivers/serial/8250.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index e001ea0606ec..bbf78aaf9e01 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2235,10 +2235,17 @@ static void serial8250_console_write(struct console *co, const char *s, unsigned int count) { struct uart_8250_port *up = &serial8250_ports[co->index]; + unsigned long flags; unsigned int ier; + int locked = 1; touch_nmi_watchdog(); + if (oops_in_progress) { + locked = spin_trylock_irqsave(&up->port.lock, flags); + } else + spin_lock_irqsave(&up->port.lock, flags); + /* * First save the IER then disable the interrupts */ @@ -2257,6 +2264,9 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) */ wait_for_xmitr(up, BOTH_EMPTY); serial_out(up, UART_IER, ier); + + if (locked) + spin_unlock_irqrestore(&up->port.lock, flags); } static int serial8250_console_setup(struct console *co, char *options) -- cgit v1.2.2 From 37be4e7809e0581db85387e126ae4da68c3d6286 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 May 2006 17:24:59 +0100 Subject: [MMC] extend data timeout for writes The CSD contains a "read2write factor" which determines the multiplier to be applied to the read timeout to obtain the write timeout. We were ignoring this parameter, resulting in the possibility for writes being timed out too early. Signed-off-by: Russell King --- drivers/mmc/mmc.c | 2 ++ drivers/mmc/mmc_block.c | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index da6ddd910fc5..05aa4d6b4f24 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -549,6 +549,7 @@ static void mmc_decode_csd(struct mmc_card *card) csd->read_partial = UNSTUFF_BITS(resp, 79, 1); csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } else { @@ -583,6 +584,7 @@ static void mmc_decode_csd(struct mmc_card *card) csd->read_partial = UNSTUFF_BITS(resp, 79, 1); csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 8eb2a2ede64b..06bd1f4cb9b1 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -187,6 +187,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.cmd.opcode = MMC_WRITE_BLOCK; brq.data.flags |= MMC_DATA_WRITE; brq.data.blocks = 1; + + /* + * Scale up the timeout by the r2w factor + */ + brq.data.timeout_ns <<= card->csd.r2w_factor; + brq.data.timeout_clks <<= card->csd.r2w_factor; } if (brq.data.blocks > 1) { -- cgit v1.2.2 From 58741e8b3603e56c3699550e8bc89cb136329343 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 May 2006 20:02:39 +0100 Subject: [MMC] PXA and i.MX: don't avoid sending stop command on error Always send a stop command at the end of a data transfer. If we avoid sending the stop command, some cards remain in data transfer mode, and refuse to accept further read/write commands. Signed-off-by: Russell King --- drivers/mmc/imxmmc.c | 2 +- drivers/mmc/pxamci.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index 07f36c454bd6..bc271925099a 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -529,7 +529,7 @@ static int imxmci_data_done(struct imxmci_host *host, unsigned int stat) data_error = imxmci_finish_data(host, stat); - if (host->req->stop && (data_error == MMC_ERR_NONE)) { + if (host->req->stop) { imxmci_stop_clock(host); imxmci_start_cmd(host, host->req->stop, 0); } else { diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index eb42cb349420..15a5caa0bdeb 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -291,7 +291,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) pxamci_disable_irq(host, DATA_TRAN_DONE); host->data = NULL; - if (host->mrq->stop && data->error == MMC_ERR_NONE) { + if (host->mrq->stop) { pxamci_stop_clock(host); pxamci_start_cmd(host, host->mrq->stop, 0); } else { -- cgit v1.2.2 From d78e9079af7526c4661ff484322094832776ef41 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 May 2006 20:18:53 +0100 Subject: [MMC] PXA: reduce the number of lines PXAMCI debug uses There's no reason for the PXAMCI debug code to print so many lines - it causes the kernel buffer to overflow when trying to debug this driver. Remove some debug messages which are duplicated by core code, and combine other messages, resulting in fewer characters written to the kernel log. Signed-off-by: Russell King --- drivers/mmc/pxamci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 15a5caa0bdeb..40970c4ae3e6 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -198,7 +198,6 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) { - pr_debug("PXAMCI: request done\n"); host->mrq = NULL; host->cmd = NULL; host->data = NULL; @@ -309,12 +308,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs) ireg = readl(host->base + MMC_I_REG); - pr_debug("PXAMCI: irq %08x\n", ireg); - if (ireg) { unsigned stat = readl(host->base + MMC_STAT); - pr_debug("PXAMCI: stat %08x\n", stat); + pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); if (ireg & END_CMD_RES) handled |= pxamci_cmd_done(host, stat); @@ -368,7 +365,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct pxamci_host *host = mmc_priv(mmc); - pr_debug("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", + pr_debug("PXAMCI: clock %u power %u vdd %u.%02u\n", ios->clock, ios->power_mode, ios->vdd / 100, ios->vdd % 100); @@ -397,7 +394,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->cmdat |= CMDAT_INIT; } - pr_debug("pxamci_set_ios: clkrt = %x cmdat = %x\n", + pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", host->clkrt, host->cmdat); } -- cgit v1.2.2 From 61f5657c50341198ff05e375e6f1fc0476556562 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Sat, 29 Apr 2006 22:32:44 +0400 Subject: [PATCH] ppc32 CPM_UART: Fixed break send on SCC SCC uart sends a break sequence each time it is stopped with the CPM_CR_STOP_TX command. That means that each time an application closes the serial device, a break is transmitted. To fix this, graceful tx stop is issued for SCC. Signed-off-by: David Jander Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras --- drivers/serial/cpm_uart/cpm_uart_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index ced193bf9e1e..b9d1185df20c 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -457,7 +457,11 @@ static void cpm_uart_shutdown(struct uart_port *port) } /* Shut them really down and reinit buffer descriptors */ - cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + if (IS_SMC(pinfo)) + cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + else + cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX); + cpm_uart_initbd(pinfo); } } -- cgit v1.2.2 From 6e1976961c9bd9a3dc368139fab1883961efc879 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Sat, 29 Apr 2006 23:06:00 +0400 Subject: [PATCH] ppc32 CPM_UART: fixes and improvements A number of small issues are fixed, and added the header file, missed from the original series. With this, driver should be pretty stable as tested among both platform-device-driven and "old way" boards. Also added missing GPL statement , and updated year field on existing ones to reflect code update. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras --- drivers/serial/cpm_uart/cpm_uart.h | 19 ++++++++++++++----- drivers/serial/cpm_uart/cpm_uart_core.c | 31 +++++++++++++++++++++++++------ drivers/serial/cpm_uart/cpm_uart_cpm1.c | 2 ++ drivers/serial/cpm_uart/cpm_uart_cpm2.c | 2 ++ 4 files changed, 43 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index aa5eb7ddeda9..3b35cb779539 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -5,6 +5,13 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * + * 2006 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * */ #ifndef CPM_UART_H #define CPM_UART_H @@ -101,12 +108,13 @@ static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo int offset; u32 val = (u32)addr; /* sane check */ - if ((val >= (u32)pinfo->mem_addr) && + if (likely((val >= (u32)pinfo->mem_addr)) && (val<((u32)pinfo->mem_addr + pinfo->mem_size))) { offset = val - (u32)pinfo->mem_addr; return pinfo->dma_addr+offset; } - printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val); + /* something nasty happened */ + BUG(); return 0; } @@ -115,12 +123,13 @@ static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo int offset; u32 val = addr; /* sane check */ - if ((val >= pinfo->dma_addr) && - (val<(pinfo->dma_addr + pinfo->mem_size))) { + if (likely((val >= pinfo->dma_addr) && + (val<(pinfo->dma_addr + pinfo->mem_size)))) { offset = val - (u32)pinfo->dma_addr; return (void*)(pinfo->mem_addr+offset); } - printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val); + /* something nasty happened */ + BUG(); return 0; } diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index b9d1185df20c..969f94900431 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -12,7 +12,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. - * (C) 2005 MontaVista Software, Inc. by Vitaly Bordug + * (C) 2005-2006 MontaVista Software, Inc. + * Vitaly Bordug * * 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 @@ -81,7 +82,7 @@ early_uart_get_pdev(int index) } -void cpm_uart_count(void) +static void cpm_uart_count(void) { cpm_uart_nr = 0; #ifdef CONFIG_SERIAL_CPM_SMC1 @@ -104,6 +105,21 @@ void cpm_uart_count(void) #endif } +/* Get UART number by its id */ +static int cpm_uart_id2nr(int id) +{ + int i; + if (id < UART_NR) { + for (i=0; ifs_no; line++); + line = cpm_uart_id2nr(idx); + if(line < 0) { + printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); + return -1; + } pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx]; @@ -1245,8 +1265,7 @@ static int cpm_uart_drv_probe(struct device *dev) } pdata = pdev->dev.platform_data; - pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", - cpm_uart_port_map[pdata->fs_no]); + pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) return ret; @@ -1265,7 +1284,7 @@ static int cpm_uart_drv_remove(struct device *dev) struct fs_uart_platform_info *pdata = pdev->dev.platform_data; pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n", - cpm_uart_port_map[pdata->fs_no]); + cpm_uart_id2nr(pdata->fs_no)); uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); return 0; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index a5a30622637a..17406a05ce1f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -8,6 +8,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. + * (C) 2006 MontaVista Software, Inc. + * Vitaly Bordug * * 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 diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 7c6b07aeea92..4b2de08f46d0 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -8,6 +8,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. + * (C) 2006 MontaVista Software, Inc. + * Vitaly Bordug * * 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 -- cgit v1.2.2 From 6e1cad02763edec83dba8559d4be8d518a6562a5 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 25 Apr 2006 17:38:58 -0600 Subject: [SCSI] mptspi: revalidate negotiation parameters after host reset and resume This is a bug fix for mptspi driver, where after a host reset or resume, we revalidate the negotiation parameters for all devices. This bug was introduced when the driver was ported to use the spi transport layer. Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptspi.c | 68 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 09c745b19cc8..f2a4d382ea19 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -783,6 +783,70 @@ static struct pci_device_id mptspi_pci_table[] = { }; MODULE_DEVICE_TABLE(pci, mptspi_pci_table); + +/* + * renegotiate for a given target + */ +static void +mptspi_dv_renegotiate_work(void *data) +{ + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct _MPT_SCSI_HOST *hd = wqw->hd; + struct scsi_device *sdev; + + kfree(wqw); + + shost_for_each_device(sdev, hd->ioc->sh) + mptspi_dv_device(hd, sdev); +} + +static void +mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd) +{ + struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); + + if (!wqw) + return; + + INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work, wqw); + wqw->hd = hd; + + schedule_work(&wqw->work); +} + +/* + * spi module reset handler + */ +static int +mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +{ + struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + int rc; + + rc = mptscsih_ioc_reset(ioc, reset_phase); + + if (reset_phase == MPT_IOC_POST_RESET) + mptspi_dv_renegotiate(hd); + + return rc; +} + +/* + * spi module resume handler + */ +static int +mptspi_resume(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + int rc; + + rc = mptscsih_resume(pdev); + mptspi_dv_renegotiate(hd); + + return rc; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -1032,7 +1096,7 @@ static struct pci_driver mptspi_driver = { .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, - .resume = mptscsih_resume, + .resume = mptspi_resume, #endif }; @@ -1061,7 +1125,7 @@ mptspi_init(void) ": Registered for IOC event notifications\n")); } - if (mpt_reset_register(mptspiDoneCtx, mptscsih_ioc_reset) == 0) { + if (mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset) == 0) { dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); } -- cgit v1.2.2 From 0b18ac42aa036c7fa217f178aa6a02c66e19e0a1 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 1 May 2006 21:50:40 -0400 Subject: [SCSI] lpfc 8.1.6 : Fix Data Corruption in Bus Reset Path This patch updates the lpfc driver to revision 8.1.6, which includes the following changes: - Fix data corruption in SCSI BUS reset path, due to reusing the same request structure for each target. - Change version number to 8.1.6 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 68 +++++++++++----------------------------- drivers/scsi/lpfc/lpfc_version.h | 2 +- 2 files changed, 20 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index f93799873721..7dc4c2e6bed2 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -629,8 +629,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq; IOCB_t *piocb; struct fcp_cmnd *fcp_cmnd; - struct scsi_device *scsi_dev = lpfc_cmd->pCmd->device; - struct lpfc_rport_data *rdata = scsi_dev->hostdata; + struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *ndlp = rdata->pnode; if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { @@ -665,56 +664,18 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, piocb->ulpTimeout = lpfc_cmd->timeout; } - lpfc_cmd->rdata = rdata; - - switch (task_mgmt_cmd) { - case FCP_LUN_RESET: - /* Issue LUN Reset to TGT LUN */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_FCP, - "%d:0703 Issue LUN Reset to TGT %d LUN %d " - "Data: x%x x%x\n", - phba->brd_no, - scsi_dev->id, scsi_dev->lun, - ndlp->nlp_rpi, ndlp->nlp_flag); - - break; - case FCP_ABORT_TASK_SET: - /* Issue Abort Task Set to TGT LUN */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_FCP, - "%d:0701 Issue Abort Task Set to TGT %d LUN %d " - "Data: x%x x%x\n", - phba->brd_no, - scsi_dev->id, scsi_dev->lun, - ndlp->nlp_rpi, ndlp->nlp_flag); - - break; - case FCP_TARGET_RESET: - /* Issue Target Reset to TGT */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_FCP, - "%d:0702 Issue Target Reset to TGT %d " - "Data: x%x x%x\n", - phba->brd_no, - scsi_dev->id, ndlp->nlp_rpi, - ndlp->nlp_flag); - break; - } - return (1); } static int -lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba) +lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, + unsigned tgt_id, struct lpfc_rport_data *rdata) { struct lpfc_iocbq *iocbq; struct lpfc_iocbq *iocbqrsp; int ret; + lpfc_cmd->rdata = rdata; ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET); if (!ret) return FAILED; @@ -726,6 +687,13 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba) if (!iocbqrsp) return FAILED; + /* Issue Target Reset to TGT */ + lpfc_printf_log(phba, KERN_INFO, LOG_FCP, + "%d:0702 Issue Target Reset to TGT %d " + "Data: x%x x%x\n", + phba->brd_no, tgt_id, rdata->pnode->nlp_rpi, + rdata->pnode->nlp_flag); + ret = lpfc_sli_issue_iocb_wait(phba, &phba->sli.ring[phba->sli.fcp_ring], iocbq, iocbqrsp, lpfc_cmd->timeout); @@ -1021,6 +989,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) lpfc_cmd->pCmd = cmnd; lpfc_cmd->timeout = 60; lpfc_cmd->scsi_hba = phba; + lpfc_cmd->rdata = rdata; ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET); if (!ret) @@ -1033,6 +1002,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) if (iocbqrsp == NULL) goto out_free_scsi_buf; + lpfc_printf_log(phba, KERN_INFO, LOG_FCP, + "%d:0703 Issue LUN Reset to TGT %d LUN %d " + "Data: x%x x%x\n", phba->brd_no, cmnd->device->id, + cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); + ret = lpfc_sli_issue_iocb_wait(phba, &phba->sli.ring[phba->sli.fcp_ring], iocbq, iocbqrsp, lpfc_cmd->timeout); @@ -1104,7 +1078,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) int match; int ret = FAILED, i, err_count = 0; int cnt, loopcnt; - unsigned int midlayer_id = 0; struct lpfc_scsi_buf * lpfc_cmd; lpfc_block_requests(phba); @@ -1124,7 +1097,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) * targets known to the driver. Should any target reset * fail, this routine returns failure to the midlayer. */ - midlayer_id = cmnd->device->id; for (i = 0; i < MAX_FCP_TARGET; i++) { /* Search the mapped list for this target ID */ match = 0; @@ -1137,9 +1109,8 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) if (!match) continue; - lpfc_cmd->pCmd->device->id = i; - lpfc_cmd->pCmd->device->hostdata = ndlp->rport->dd_data; - ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba); + ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, + i, ndlp->rport->dd_data); if (ret != SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_FCP, "%d:0713 Bus Reset on target %d failed\n", @@ -1158,7 +1129,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) * the targets. Unfortunately, some targets do not abide by * this forcing the driver to double check. */ - cmnd->device->id = midlayer_id; cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], 0, 0, LPFC_CTX_HOST); if (cnt) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index d0f2dc310b00..6b737568b831 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.5" +#define LPFC_DRIVER_VERSION "8.1.6" #define LPFC_DRIVER_NAME "lpfc" -- cgit v1.2.2 From 96941026a51e9cb8c2d2be7499301b7fcd9ee225 Mon Sep 17 00:00:00 2001 From: mark gross Date: Wed, 3 May 2006 19:55:07 -0700 Subject: [PATCH] EDAC Coexistence with BIOS Address the issue of EDAC/BIOS coexistence for the e752x chip-sets. We have found a problem where the BIOS will start the system with the error registers (dev0:fun1) hidden and assuming it has exclusive access to them. The edac driver violates this assumption. The workaround this patch offers is to honor the hidden-ness as an indication that it is not safe to use those registers. Signed-off-by: Mark Gross Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/edac/e752x_edac.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 66572c5323ad..fce31936e6d7 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -25,6 +25,8 @@ #include #include "edac_mc.h" +static int force_function_unhide; + #define e752x_printk(level, fmt, arg...) \ edac_printk(level, "e752x", fmt, ##arg) @@ -782,8 +784,16 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); debugf0("Starting Probe1\n"); - /* enable device 0 function 1 */ + /* check to see if device 0 function 1 is enabled; if it isn't, we + * assume the BIOS has reserved it for a reason and is expecting + * exclusive access, we take care not to violate that assumption and + * fail the probe. */ pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8); + if (!force_function_unhide && !(stat8 & (1 << 5))) { + printk(KERN_INFO "Contact your BIOS vendor to see if the " + "E752x error registers can be safely un-hidden\n"); + goto fail; + } stat8 |= (1 << 5); pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); @@ -1063,3 +1073,8 @@ module_exit(e752x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); + +module_param(force_function_unhide, int, 0444); +MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" +" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access"); + -- cgit v1.2.2 From 8683dc9990158c221e05959935e7dd50a956c574 Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Wed, 3 May 2006 19:55:10 -0700 Subject: [PATCH] Altix: correct ioc4 port order Currently loading the ioc3 as a module will cause the ports to be numbered in reverse order. This mod maintains the proper order of cards for port numbering. Signed-off-by: Brent Casavant Cc: Pat Gefre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/sn/ioc4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c index 67140a5804f5..cdeff909403e 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/sn/ioc4.c @@ -310,7 +310,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) pci_set_drvdata(idd->idd_pdev, idd); mutex_lock(&ioc4_mutex); - list_add(&idd->idd_list, &ioc4_devices); + list_add_tail(&idd->idd_list, &ioc4_devices); /* Add this IOC4 to all submodules */ list_for_each_entry(is, &ioc4_submodules, is_list) { -- cgit v1.2.2 From 3ab33dcc82e014c69ebad3b524d0053378ef76c3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle DL5RB Date: Wed, 3 May 2006 23:24:35 -0700 Subject: [HAMRADIO]: Remove remaining SET_MODULE_OWNER calls from hamradio drivers. Signed-off-by: Ralf Baechle DL5RB Signed-off-by: David S. Miller --- drivers/net/hamradio/dmascc.c | 1 - drivers/net/hamradio/scc.c | 1 - drivers/net/hamradio/yam.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 79a8fbcf5f93..0d5fccc984bb 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -582,7 +582,6 @@ static int __init setup_adapter(int card_base, int type, int n) INIT_WORK(&priv->rx_work, rx_bh, priv); dev->priv = priv; sprintf(dev->name, "dmascc%i", 2 * n + i); - SET_MODULE_OWNER(dev); dev->base_addr = card_base; dev->irq = irq; dev->open = scc_open; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 6ace0e914fd1..5927784df3f9 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1550,7 +1550,6 @@ static unsigned char ax25_nocall[AX25_ADDR_LEN] = static void scc_net_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->tx_queue_len = 16; /* should be enough... */ dev->open = scc_net_open; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index fe22479eb202..b49884048caa 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -1098,7 +1098,6 @@ static void yam_setup(struct net_device *dev) dev->base_addr = yp->iobase; dev->irq = yp->irq; - SET_MODULE_OWNER(dev); dev->open = yam_open; dev->stop = yam_close; -- cgit v1.2.2 From fe10c6abea8bc83291a13e0580b3e4c355710b09 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 May 2006 13:51:45 +0100 Subject: [MMC] Correct mmc_request_done comments mmc_request_done should be called at the end of handling a request, not between the data and initial command parts of the request. Signed-off-by: Russell King --- drivers/mmc/mmc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 05aa4d6b4f24..91c6b10dda9a 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -59,13 +59,12 @@ static const unsigned int tacc_mant[] = { /** - * mmc_request_done - finish processing an MMC command - * @host: MMC host which completed command - * @mrq: MMC request which completed + * mmc_request_done - finish processing an MMC request + * @host: MMC host which completed request + * @mrq: MMC request which request * * MMC drivers should call this function when they have completed - * their processing of a command. This should be called before the - * data part of the command has completed. + * their processing of a request. */ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) { -- cgit v1.2.2 From 5b802344357338a4d645beac8ca97470bcbe3542 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 4 May 2006 14:07:42 +0100 Subject: [ARM] 3490/1: i.MX: move uart resources to board files Patch from Sascha Hauer This patch moves the i.MX uart resources and the gpio pin setup to the board files. This allows the boards to decide how many internal uarts are connected to the outside world and whether they use rts/cts or not. Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- drivers/serial/imx.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index c3b7a6673e9c..d202eb4f3848 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -45,6 +45,7 @@ #include #include #include +#include /* We've been assigned a range on the "Low-density serial ports" major */ #define SERIAL_IMX_MAJOR 204 @@ -73,7 +74,8 @@ struct imx_port { struct uart_port port; struct timer_list timer; unsigned int old_status; - int txirq,rxirq,rtsirq; + int txirq,rxirq,rtsirq; + int have_rtscts:1; }; /* @@ -491,8 +493,12 @@ imx_set_termios(struct uart_port *port, struct termios *termios, ucr2 = UCR2_SRST | UCR2_IRTS; if (termios->c_cflag & CRTSCTS) { - ucr2 &= ~UCR2_IRTS; - ucr2 |= UCR2_CTSC; + if( sport->have_rtscts ) { + ucr2 &= ~UCR2_IRTS; + ucr2 |= UCR2_CTSC; + } else { + termios->c_cflag &= ~CRTSCTS; + } } if (termios->c_cflag & CSTOPB) @@ -719,27 +725,6 @@ static void __init imx_init_ports(void) imx_ports[i].timer.function = imx_timeout; imx_ports[i].timer.data = (unsigned long)&imx_ports[i]; } - - imx_gpio_mode(PC9_PF_UART1_CTS); - imx_gpio_mode(PC10_PF_UART1_RTS); - imx_gpio_mode(PC11_PF_UART1_TXD); - imx_gpio_mode(PC12_PF_UART1_RXD); - imx_gpio_mode(PB28_PF_UART2_CTS); - imx_gpio_mode(PB29_PF_UART2_RTS); - - imx_gpio_mode(PB30_PF_UART2_TXD); - imx_gpio_mode(PB31_PF_UART2_RXD); - -#if 0 /* We don't need these, on the mx1 the _modem_ side of the uart - * is implemented. - */ - imx_gpio_mode(PD7_AF_UART2_DTR); - imx_gpio_mode(PD8_AF_UART2_DCD); - imx_gpio_mode(PD9_AF_UART2_RI); - imx_gpio_mode(PD10_AF_UART2_DSR); -#endif - - } #ifdef CONFIG_SERIAL_IMX_CONSOLE @@ -932,7 +917,14 @@ static int serial_imx_resume(struct platform_device *dev) static int serial_imx_probe(struct platform_device *dev) { + struct imxuart_platform_data *pdata; + imx_ports[dev->id].port.dev = &dev->dev; + + pdata = (struct imxuart_platform_data *)dev->dev.platform_data; + if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) + imx_ports[dev->id].have_rtscts = 1; + uart_add_one_port(&imx_reg, &imx_ports[dev->id].port); platform_set_drvdata(dev, &imx_ports[dev->id]); return 0; -- cgit v1.2.2 From 920e70c5c603ada05dd480ca0ccc0ae12a5fdc39 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 May 2006 18:22:51 +0100 Subject: [MMC] Move set_ios debugging into mmc.c Rather than having every driver duplicate the set_ios debugging, provide a single version in mmc.c which can be expanded as we add additional functionality. Signed-off-by: Russell King --- drivers/mmc/at91_mci.c | 3 --- drivers/mmc/au1xmmc.c | 4 ---- drivers/mmc/imxmmc.c | 4 ---- drivers/mmc/mmc.c | 51 +++++++++++++++++++++++++++++++++----------------- drivers/mmc/mmci.c | 3 --- drivers/mmc/pxamci.c | 4 ---- drivers/mmc/sdhci.c | 4 ---- drivers/mmc/wbsd.c | 4 ---- 8 files changed, 34 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 6061c2d101a0..88f0eef9cf33 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -621,9 +621,6 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct at91mci_host *host = mmc_priv(mmc); unsigned long at91_master_clock = clk_get_rate(mci_clk); - DBG("Clock %uHz, busmode %u, powermode %u, Vdd %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); - if (host) host->bus_mode = ios->bus_mode; else diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index c0326bbc5f28..914d62b24064 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -720,10 +720,6 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) { struct au1xmmc_host *host = mmc_priv(mmc); - DBG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n", - host->id, ios->power_mode, ios->clock, ios->vdd, - ios->bus_mode); - if (ios->power_mode == MMC_POWER_OFF) au1xmmc_set_power(host, 0); else if (ios->power_mode == MMC_POWER_ON) { diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index bc271925099a..79358e223f57 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -807,10 +807,6 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct imxmci_host *host = mmc_priv(mmc); int prescaler; - dev_dbg(mmc_dev(host->mmc), "clock %u power %u vdd %u width %u\n", - ios->clock, ios->power_mode, ios->vdd, - (ios->bus_width==MMC_BUS_WIDTH_4)?4:1); - if( ios->bus_width==MMC_BUS_WIDTH_4 ) { host->actual_bus_width = MMC_BUS_WIDTH_4; imx_gpio_mode(PB11_PF_SD_DAT3); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 91c6b10dda9a..1ca2c8b9c9b5 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -69,10 +69,13 @@ static const unsigned int tacc_mant[] = { void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) { struct mmc_command *cmd = mrq->cmd; - int err = mrq->cmd->error; - pr_debug("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", - cmd->opcode, err, cmd->resp[0], cmd->resp[1], - cmd->resp[2], cmd->resp[3]); + int err = cmd->error; + + pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n", + mmc_hostname(host), cmd->opcode, err, + mrq->data ? mrq->data->error : 0, + mrq->stop ? mrq->stop->error : 0, + cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); if (err && cmd->retries) { cmd->retries--; @@ -96,8 +99,9 @@ EXPORT_SYMBOL(mmc_request_done); void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { - pr_debug("MMC: starting cmd %02x arg %08x flags %08x\n", - mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); + pr_debug("%s: starting CMD%u arg %08x flags %08x\n", + mmc_hostname(host), mrq->cmd->opcode, + mrq->cmd->arg, mrq->cmd->flags); WARN_ON(host->card_busy == NULL); @@ -311,6 +315,18 @@ void mmc_release_host(struct mmc_host *host) EXPORT_SYMBOL(mmc_release_host); +static inline void mmc_set_ios(struct mmc_host *host) +{ + struct mmc_ios *ios = &host->ios; + + pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", + mmc_hostname(host), ios->clock, ios->bus_mode, + ios->power_mode, ios->chip_select, ios->vdd, + ios->bus_width); + + host->ops->set_ios(host, ios); +} + static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) { int err; @@ -363,7 +379,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) } } - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); return MMC_ERR_NONE; } @@ -414,7 +430,7 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) ocr = 3 << bit; host->ios.vdd = bit; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } else { ocr = 0; } @@ -667,7 +683,7 @@ static void mmc_idle_cards(struct mmc_host *host) struct mmc_command cmd; host->ios.chip_select = MMC_CS_HIGH; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); @@ -680,7 +696,7 @@ static void mmc_idle_cards(struct mmc_host *host) mmc_delay(1); host->ios.chip_select = MMC_CS_DONTCARE; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); } @@ -705,13 +721,13 @@ static void mmc_power_up(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(2); } @@ -724,7 +740,7 @@ static void mmc_power_off(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) @@ -972,7 +988,8 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) max_dtr = card->csd.max_dtr; - pr_debug("MMC: selected %d.%03dMHz transfer rate\n", + pr_debug("%s: selected %d.%03dMHz transfer rate\n", + mmc_hostname(host), max_dtr / 1000000, (max_dtr / 1000) % 1000); return max_dtr; @@ -1047,7 +1064,7 @@ static void mmc_setup(struct mmc_host *host) } else { host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.clock = host->f_min; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); /* * We should remember the OCR mask from the existing @@ -1083,7 +1100,7 @@ static void mmc_setup(struct mmc_host *host) * Ok, now switch to push-pull mode. */ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_read_csds(host); @@ -1129,7 +1146,7 @@ static void mmc_rescan(void *data) * attached cards and the host support. */ host->ios.clock = mmc_calculate_clock(host); - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } mmc_release_host(host); diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index df7e861e2fc7..da8e4d7339cc 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -402,9 +402,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct mmci_host *host = mmc_priv(mmc); u32 clk = 0, pwr = 0; - DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); - if (ios->clock) { if (ios->clock >= host->mclk) { clk = MCI_CLK_BYPASS; diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 40970c4ae3e6..f97b472085cb 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -365,10 +365,6 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct pxamci_host *host = mmc_priv(mmc); - pr_debug("PXAMCI: clock %u power %u vdd %u.%02u\n", - ios->clock, ios->power_mode, ios->vdd / 100, - ios->vdd % 100); - if (ios->clock) { unsigned int clk = CLOCKRATE / ios->clock; if (CLOCKRATE / clk > ios->clock) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index bdbfca050029..b0053280ff2d 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -570,10 +570,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); - DBG("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, - ios->vdd, ios->bus_width); - /* * Reset the chip on each power off. * Should clear out any weird states. diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 511f7b0b31d2..39b3d97f891e 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -931,10 +931,6 @@ static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct wbsd_host *host = mmc_priv(mmc); u8 clk, setup, pwr; - DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, - ios->vdd, ios->bus_width); - spin_lock_bh(&host->lock); /* -- cgit v1.2.2 From 5b4b9775a00c20ade1b1ac8aa25e0e4059d6243e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 1 May 2006 22:43:00 +0200 Subject: [PATCH] bcm43xx: fix iwmode crash when down This fixes a crash when iwconfig ethX mode foo is done before ifconfig ethX up or after ifconfig ethX down Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 3edbb481a0a0..b45063974ae9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -182,8 +182,11 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, mode = BCM43xx_INITIAL_IWMODE; bcm43xx_lock_mmio(bcm, flags); - if (bcm->ieee->iw_mode != mode) - bcm43xx_set_iwmode(bcm, mode); + if (bcm->initialized) { + if (bcm->ieee->iw_mode != mode) + bcm43xx_set_iwmode(bcm, mode); + } else + bcm->ieee->iw_mode = mode; bcm43xx_unlock_mmio(bcm, flags); return 0; -- cgit v1.2.2 From f9f7b9602ecb66f55718d6d1afa3e2b1e721b22d Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 5 May 2006 01:26:29 +0200 Subject: [PATCH] bcm43xx: check for valid MAC address in SPROM Check for valid MAC address in SPROM fields instead of relying on PHY type while setting the MAC address in the networking subsystem, as some devices have multiple PHYs. Signed-off-by: Stefano Brivio Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 9a06e61df0a2..4be2d9b5749b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3482,7 +3482,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_crystal(bcm, 0); /* Set the MAC address in the networking subsystem */ - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) + if (is_valid_ether_addr(bcm->sprom.et1macaddr)) memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); else memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); -- cgit v1.2.2 From 869aaab1812c4212e65fb181e94b824cf49f9509 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 5 May 2006 17:23:51 +0200 Subject: [PATCH] bcm43xx: Fix array overrun in bcm43xx_geo_init The problem here is that the bcm34xx driver and the ieee80211 stack do not agree on what channels are possible for 802.11a. The ieee80211 stack only wants channels between 34 and 165, while the bcm43xx driver accepts anything from 0 to 200. I made the bcm43xx driver comply with the ieee80211 stack expectations, by using the proper constants. Signed-off-by: Jean Delvare [mb]: Reduce stack usage by kzalloc-ing ieee80211_geo Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 43 +++++++++++++++++------------ drivers/net/wireless/bcm43xx/bcm43xx_main.h | 6 ++-- 2 files changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4be2d9b5749b..e2982a83ae42 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -939,9 +939,9 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) return 0; } -static void bcm43xx_geo_init(struct bcm43xx_private *bcm) +static int bcm43xx_geo_init(struct bcm43xx_private *bcm) { - struct ieee80211_geo geo; + struct ieee80211_geo *geo; struct ieee80211_channel *chan; int have_a = 0, have_bg = 0; int i; @@ -949,7 +949,10 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) struct bcm43xx_phyinfo *phy; const char *iso_country; - memset(&geo, 0, sizeof(geo)); + geo = kzalloc(sizeof(*geo), GFP_KERNEL); + if (!geo) + return -ENOMEM; + for (i = 0; i < bcm->nr_80211_available; i++) { phy = &(bcm->core_80211_ext[i].phy); switch (phy->type) { @@ -967,31 +970,36 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) iso_country = bcm43xx_locale_iso(bcm->sprom.locale); if (have_a) { - for (i = 0, channel = 0; channel < 201; channel++) { - chan = &geo.a[i++]; + for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL; + channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) { + chan = &geo->a[i++]; chan->freq = bcm43xx_channel_to_freq_a(channel); chan->channel = channel; } - geo.a_channels = i; + geo->a_channels = i; } if (have_bg) { - for (i = 0, channel = 1; channel < 15; channel++) { - chan = &geo.bg[i++]; + for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL; + channel <= IEEE80211_24GHZ_MAX_CHANNEL; channel++) { + chan = &geo->bg[i++]; chan->freq = bcm43xx_channel_to_freq_bg(channel); chan->channel = channel; } - geo.bg_channels = i; + geo->bg_channels = i; } - memcpy(geo.name, iso_country, 2); + memcpy(geo->name, iso_country, 2); if (0 /*TODO: Outdoor use only */) - geo.name[2] = 'O'; + geo->name[2] = 'O'; else if (0 /*TODO: Indoor use only */) - geo.name[2] = 'I'; + geo->name[2] = 'I'; else - geo.name[2] = ' '; - geo.name[3] = '\0'; + geo->name[2] = ' '; + geo->name[3] = '\0'; + + ieee80211_set_geo(bcm->ieee, geo); + kfree(geo); - ieee80211_set_geo(bcm->ieee, &geo); + return 0; } /* DummyTransmission function, as documented on @@ -3479,6 +3487,9 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) goto err_80211_unwind; bcm43xx_wireless_core_disable(bcm); } + err = bcm43xx_geo_init(bcm); + if (err) + goto err_80211_unwind; bcm43xx_pctl_set_crystal(bcm, 0); /* Set the MAC address in the networking subsystem */ @@ -3487,8 +3498,6 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) else memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); - bcm43xx_geo_init(bcm); - snprintf(bcm->nick, IW_ESSID_MAX_SIZE, "Broadcom %04X", bcm->chip_id); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index eca79a38594a..30a202b258b5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -118,12 +118,14 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, static inline int bcm43xx_is_valid_channel_a(u8 channel) { - return (channel <= 200); + return (channel >= IEEE80211_52GHZ_MIN_CHANNEL + && channel <= IEEE80211_52GHZ_MAX_CHANNEL); } static inline int bcm43xx_is_valid_channel_bg(u8 channel) { - return (channel >= 1 && channel <= 14); + return (channel >= IEEE80211_24GHZ_MIN_CHANNEL + && channel <= IEEE80211_24GHZ_MAX_CHANNEL); } static inline int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, -- cgit v1.2.2 From 178e0cc5ff249965c6cfbd78b1af6a5e614d837c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 5 May 2006 18:19:37 +0100 Subject: [PATCH] bcm43xx: Fix access to non-existent PHY registers Fix the conditions under which we poke at the APHY registers in bcm43xx_phy_initg() to avoid a machine check on chips where they don't exist. Signed-off-by: David Woodhouse Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 33137165727f..b0abac515530 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1287,7 +1287,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) if (radio->revision == 8) bcm43xx_phy_write(bcm, 0x0805, 0x3230); bcm43xx_phy_init_pctl(bcm); - if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) { + if (bcm->chip_id == 0x4306 && bcm->chip_package == 2) { bcm43xx_phy_write(bcm, 0x0429, bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF); bcm43xx_phy_write(bcm, 0x04C3, -- cgit v1.2.2 From f12267011d16b1722e71aa12cd3e89eb70a9edd6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 May 2006 11:29:21 +0100 Subject: [ARM] rtc-sa1100: fix compiler warnings and error cleanup Fix: drivers/rtc/rtc-sa1100.c: In function `sa1100_rtc_proc': drivers/rtc/rtc-sa1100.c:298: warning: unsigned int format, long unsigned int arg (arg 3) and arrange for sa1100_rtc_open() to pass the devid to free_irq() rather than NULL. Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index a23ec54989f6..2bc8aad47219 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -178,9 +178,9 @@ static int sa1100_rtc_open(struct device *dev) return 0; fail_pi: - free_irq(IRQ_RTCAlrm, NULL); + free_irq(IRQ_RTCAlrm, dev); fail_ai: - free_irq(IRQ_RTC1Hz, NULL); + free_irq(IRQ_RTC1Hz, dev); fail_ui: return ret; } @@ -295,7 +295,7 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { - seq_printf(seq, "trim/divider\t: 0x%08x\n", RTTR); + seq_printf(seq, "trim/divider\t: 0x%08lx\n", RTTR); seq_printf(seq, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" ); seq_printf(seq, "update_IRQ\t: %s\n", -- cgit v1.2.2 From 1498221d51a43d5fa1a580618591497d90f957d9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 6 May 2006 17:55:11 -0700 Subject: [CLASS DEVICE]: add attribute_group creation Extend the support of attribute groups in class_device's to allow groups to be created as part of the registration process. This allows network device's to avoid race between registration and creating groups. Note that unlike attributes that are a property of the class object, the groups are a property of the class_device object. This is done because there are different types of network devices (wireless for example). Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/base/class.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/base/class.c b/drivers/base/class.c index 0e71dff327cd..b1ea4df85c7d 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -456,6 +456,35 @@ static void class_device_remove_attrs(struct class_device * cd) } } +static int class_device_add_groups(struct class_device * cd) +{ + int i; + int error = 0; + + if (cd->groups) { + for (i = 0; cd->groups[i]; i++) { + error = sysfs_create_group(&cd->kobj, cd->groups[i]); + if (error) { + while (--i >= 0) + sysfs_remove_group(&cd->kobj, cd->groups[i]); + goto out; + } + } + } +out: + return error; +} + +static void class_device_remove_groups(struct class_device * cd) +{ + int i; + if (cd->groups) { + for (i = 0; cd->groups[i]; i++) { + sysfs_remove_group(&cd->kobj, cd->groups[i]); + } + } +} + static ssize_t show_dev(struct class_device *class_dev, char *buf) { return print_dev_t(buf, class_dev->devt); @@ -559,6 +588,8 @@ int class_device_add(struct class_device *class_dev) class_name); } + class_device_add_groups(class_dev); + kobject_uevent(&class_dev->kobj, KOBJ_ADD); /* notify any interfaces this device is now here */ @@ -672,6 +703,7 @@ void class_device_del(struct class_device *class_dev) if (class_dev->devt_attr) class_device_remove_file(class_dev, class_dev->devt_attr); class_device_remove_attrs(class_dev); + class_device_remove_groups(class_dev); kobject_uevent(&class_dev->kobj, KOBJ_REMOVE); kobject_del(&class_dev->kobj); -- cgit v1.2.2 From 0eb1bd210d94e9f2c87551d794bb2755e5e24eed Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 6 May 2006 18:34:10 -0700 Subject: [IRDA] irda-usb: use NULL instead of 0 Use NULL instead of 0 for a null pointer value (sparse warning): drivers/net/irda/irda-usb.c:1781:30: warning: Using plain integer as NULL pointer Also, correct timeout argument to use milliseconds instead of jiffies. Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/irda/irda-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 96bdb73c2283..cd87593e4e8a 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1778,7 +1778,7 @@ static int irda_usb_probe(struct usb_interface *intf, if (self->needspatch) { ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), - 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500)); + 0x02, 0x40, 0, 0, NULL, 0, 500); if (ret < 0) { IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret); goto err_out_3; -- cgit v1.2.2 From 6810b548b25114607e0814612d84125abccc0a4f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 8 May 2006 15:17:31 +0200 Subject: [PATCH] x86_64: Move ondemand timer into own work queue Taking the cpu hotplug semaphore in a normal events workqueue is unsafe because other tasks can wait for any workqueues with it hold. This results in a deadlock. Move the DBS timer into its own work queue which is not affected by other work queue flushes to avoid this. Has been acked by Venkatesh. Cc: venkatesh.pallipadi@intel.com Cc: cpufreq@lists.linux.org.uk Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- drivers/cpufreq/cpufreq_ondemand.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 956d121cb161..3e6ffcaa5af4 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -74,6 +74,8 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */ static DEFINE_MUTEX (dbs_mutex); static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); +static struct workqueue_struct *dbs_workq; + struct dbs_tuners { unsigned int sampling_rate; unsigned int sampling_down_factor; @@ -364,23 +366,29 @@ static void do_dbs_timer(void *data) mutex_lock(&dbs_mutex); for_each_online_cpu(i) dbs_check_cpu(i); - schedule_delayed_work(&dbs_work, - usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); + queue_delayed_work(dbs_workq, &dbs_work, + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); mutex_unlock(&dbs_mutex); } static inline void dbs_timer_init(void) { INIT_WORK(&dbs_work, do_dbs_timer, NULL); - schedule_delayed_work(&dbs_work, - usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); + if (!dbs_workq) + dbs_workq = create_singlethread_workqueue("ondemand"); + if (!dbs_workq) { + printk(KERN_ERR "ondemand: Cannot initialize kernel thread\n"); + return; + } + queue_delayed_work(dbs_workq, &dbs_work, + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); return; } static inline void dbs_timer_exit(void) { - cancel_delayed_work(&dbs_work); - return; + if (dbs_workq) + cancel_rearming_delayed_workqueue(dbs_workq, &dbs_work); } static int cpufreq_governor_dbs(struct cpufreq_policy *policy, @@ -489,8 +497,12 @@ static int __init cpufreq_gov_dbs_init(void) static void __exit cpufreq_gov_dbs_exit(void) { - /* Make sure that the scheduled work is indeed not running */ - flush_scheduled_work(); + /* Make sure that the scheduled work is indeed not running. + Assumes the timer has been cancelled first. */ + if (dbs_workq) { + flush_workqueue(dbs_workq); + destroy_workqueue(dbs_workq); + } cpufreq_unregister_governor(&cpufreq_gov_dbs); } -- cgit v1.2.2 From d324031245abbb54e4e0321004430826052b6c37 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:26 -0700 Subject: sky2: backout NAPI reschedule This is a backout of earlier patch. The whole rescheduling hack was a bad idea. It doesn't really solve the problem and it makes the code more complicated for no good reason. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 227df9876a2c..76da74fbe859 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2105,7 +2105,6 @@ static int sky2_poll(struct net_device *dev0, int *budget) int work_done = 0; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); - restart_poll: if (unlikely(status & ~Y2_IS_STAT_BMU)) { if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); @@ -2136,7 +2135,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) } if (status & Y2_IS_STAT_BMU) { - work_done += sky2_status_intr(hw, work_limit - work_done); + work_done = sky2_status_intr(hw, work_limit); *budget -= work_done; dev0->quota -= work_done; @@ -2148,22 +2147,9 @@ static int sky2_poll(struct net_device *dev0, int *budget) mod_timer(&hw->idle_timer, jiffies + HZ); - local_irq_disable(); - __netif_rx_complete(dev0); + netif_rx_complete(dev0); status = sky2_read32(hw, B0_Y2_SP_LISR); - - if (unlikely(status)) { - /* More work pending, try and keep going */ - if (__netif_rx_schedule_prep(dev0)) { - __netif_rx_reschedule(dev0, work_done); - status = sky2_read32(hw, B0_Y2_SP_EISR); - local_irq_enable(); - goto restart_poll; - } - } - - local_irq_enable(); return 0; } @@ -2181,6 +2167,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) prefetch(&hw->st_le[hw->st_idx]); if (likely(__netif_rx_schedule_prep(dev0))) __netif_rx_schedule(dev0); + else + printk(KERN_DEBUG PFX "irq race detected\n"); return IRQ_HANDLED; } -- cgit v1.2.2 From 1e5f1283a2aed429f4457e2eb875b1928a6643df Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:27 -0700 Subject: sky2: status irq hang fix The status interrupt flag should be cleared before processing, not afterwards to avoid race. Need to process in poll routine even if no new interrupt status. This is a normal occurrence when more than 64 frames (NAPI weight) are processed in one poll routine. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 76da74fbe859..552aca76b283 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2105,45 +2105,42 @@ static int sky2_poll(struct net_device *dev0, int *budget) int work_done = 0; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); - if (unlikely(status & ~Y2_IS_STAT_BMU)) { - if (status & Y2_IS_HW_ERR) - sky2_hw_intr(hw); + if (status & Y2_IS_HW_ERR) + sky2_hw_intr(hw); - if (status & Y2_IS_IRQ_PHY1) - sky2_phy_intr(hw, 0); + if (status & Y2_IS_IRQ_PHY1) + sky2_phy_intr(hw, 0); - if (status & Y2_IS_IRQ_PHY2) - sky2_phy_intr(hw, 1); + if (status & Y2_IS_IRQ_PHY2) + sky2_phy_intr(hw, 1); - if (status & Y2_IS_IRQ_MAC1) - sky2_mac_intr(hw, 0); + if (status & Y2_IS_IRQ_MAC1) + sky2_mac_intr(hw, 0); - if (status & Y2_IS_IRQ_MAC2) - sky2_mac_intr(hw, 1); + if (status & Y2_IS_IRQ_MAC2) + sky2_mac_intr(hw, 1); - if (status & Y2_IS_CHK_RX1) - sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1); + if (status & Y2_IS_CHK_RX1) + sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1); - if (status & Y2_IS_CHK_RX2) - sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2); + if (status & Y2_IS_CHK_RX2) + sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2); - if (status & Y2_IS_CHK_TXA1) - sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1); + if (status & Y2_IS_CHK_TXA1) + sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1); - if (status & Y2_IS_CHK_TXA2) - sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2); - } + if (status & Y2_IS_CHK_TXA2) + sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2); - if (status & Y2_IS_STAT_BMU) { - work_done = sky2_status_intr(hw, work_limit); - *budget -= work_done; - dev0->quota -= work_done; + if (status & Y2_IS_STAT_BMU) + sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); - if (work_done >= work_limit) - return 1; + work_done = sky2_status_intr(hw, work_limit); + *budget -= work_done; + dev0->quota -= work_done; - sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); - } + if (work_done >= work_limit) + return 1; mod_timer(&hw->idle_timer, jiffies + HZ); -- cgit v1.2.2 From f55925d7eb04f936ab4c001f10e3e9c74c1297ae Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:28 -0700 Subject: sky2: tx ring index mask fix Mask for transmit ring status was picking up bits from the unused sync ring. They were always zero, so far... Also, make sure to remind self not to make tx ring too big. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 552aca76b283..4bb6ea13efdd 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1927,7 +1927,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) case OP_TXINDEXLE: /* TX index reports status for both ports */ - sky2_tx_done(hw->dev[0], status & 0xffff); + BUILD_BUG_ON(TX_RING_SIZE > 0x1000); + sky2_tx_done(hw->dev[0], status & 0xfff); if (hw->dev[1]) sky2_tx_done(hw->dev[1], ((status >> 24) & 0xff) -- cgit v1.2.2 From cb5d9547307f44f210f88c829bad4249eeb24bc3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:29 -0700 Subject: sky2: use mask instead of modulo operation Gcc isn't smart enough to know that it can do a modulo operation with power of 2 constant by doing a mask. So add macro to do it for us. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4bb6ea13efdd..d9cce50cffd1 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -79,6 +79,8 @@ #define NAPI_WEIGHT 64 #define PHY_RETRIES 1000 +#define RING_NEXT(x,s) (((x)+1) & ((s)-1)) + static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR @@ -719,7 +721,7 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) { struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod; - sky2->tx_prod = (sky2->tx_prod + 1) % TX_RING_SIZE; + sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE); return le; } @@ -735,7 +737,7 @@ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2) { struct sky2_rx_le *le = sky2->rx_le + sky2->rx_put; - sky2->rx_put = (sky2->rx_put + 1) % RX_LE_SIZE; + sky2->rx_put = RING_NEXT(sky2->rx_put, RX_LE_SIZE); return le; } @@ -1078,7 +1080,7 @@ err_out: /* Modular subtraction in ring */ static inline int tx_dist(unsigned tail, unsigned head) { - return (head - tail) % TX_RING_SIZE; + return (head - tail) & (TX_RING_SIZE - 1); } /* Number of list elements available for next tx */ @@ -1255,7 +1257,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->opcode = OP_BUFFER | HW_OWNER; fre = sky2->tx_ring - + ((re - sky2->tx_ring) + i + 1) % TX_RING_SIZE; + + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE); pci_unmap_addr_set(fre, mapaddr, mapping); } @@ -1315,7 +1317,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct tx_ring_info *fre; - fre = sky2->tx_ring + (put + i + 1) % TX_RING_SIZE; + fre = sky2->tx_ring + RING_NEXT(put + i, TX_RING_SIZE); pci_unmap_page(pdev, pci_unmap_addr(fre, mapaddr), skb_shinfo(skb)->frags[i].size, PCI_DMA_TODEVICE); @@ -1876,7 +1878,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) break; opcode &= ~HW_OWNER; - hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; + hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE); le->opcode = 0; link = le->link; -- cgit v1.2.2 From 01bd75645f94d49cb7ffd61022890166ce00ec2a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:30 -0700 Subject: sky2: edge triggered workaround enhancement Need to make the edge-triggered workaround timer faster to get marginally better peformance. The test_and_set_bit in schedule_prep() acts as a barrier already. Make it a module parameter so that laptops who are concerned about power can set it to 0; and user's stuck with broken BIOS's can turn the driver into pure polling. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d9cce50cffd1..940ed699a702 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -98,6 +98,10 @@ static int disable_msi = 0; module_param(disable_msi, int, 0); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); +static int idle_timeout = 100; +module_param(idle_timeout, int, 0); +MODULE_PARM_DESC(idle_timeout, "Idle timeout workaround for lost interrupts (ms)"); + static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, @@ -2092,12 +2096,13 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port, */ static void sky2_idle(unsigned long arg) { - struct net_device *dev = (struct net_device *) arg; + struct sky2_hw *hw = (struct sky2_hw *) arg; + struct net_device *dev = hw->dev[0]; - local_irq_disable(); if (__netif_rx_schedule_prep(dev)) __netif_rx_schedule(dev); - local_irq_enable(); + + mod_timer(&hw->idle_timer, jiffies + msecs_to_jiffies(idle_timeout)); } @@ -2145,8 +2150,6 @@ static int sky2_poll(struct net_device *dev0, int *budget) if (work_done >= work_limit) return 1; - mod_timer(&hw->idle_timer, jiffies + HZ); - netif_rx_complete(dev0); status = sky2_read32(hw, B0_Y2_SP_LISR); @@ -2167,8 +2170,6 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) prefetch(&hw->st_le[hw->st_idx]); if (likely(__netif_rx_schedule_prep(dev0))) __netif_rx_schedule(dev0); - else - printk(KERN_DEBUG PFX "irq race detected\n"); return IRQ_HANDLED; } @@ -3290,7 +3291,10 @@ static int __devinit sky2_probe(struct pci_dev *pdev, sky2_write32(hw, B0_IMSK, Y2_IS_BASE); - setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) dev); + setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); + if (idle_timeout > 0) + mod_timer(&hw->idle_timer, + jiffies + msecs_to_jiffies(idle_timeout)); pci_set_drvdata(pdev, hw); -- cgit v1.2.2 From e71ebd73276cc21efc74aba4118ef037cd32e50a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:31 -0700 Subject: sky2: dont write status ring It is more efficient not to write the status ring from the processor and just read the active portion. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 940ed699a702..ea23da53677b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1865,35 +1865,28 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) static int sky2_status_intr(struct sky2_hw *hw, int to_do) { int work_done = 0; + u16 hwidx = sky2_read16(hw, STAT_PUT_IDX); rmb(); - for(;;) { + while (hw->st_idx != hwidx) { struct sky2_status_le *le = hw->st_le + hw->st_idx; struct net_device *dev; struct sky2_port *sky2; struct sk_buff *skb; u32 status; u16 length; - u8 link, opcode; - - opcode = le->opcode; - if (!opcode) - break; - opcode &= ~HW_OWNER; hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE); - le->opcode = 0; - link = le->link; - BUG_ON(link >= 2); - dev = hw->dev[link]; + BUG_ON(le->link >= 2); + dev = hw->dev[le->link]; sky2 = netdev_priv(dev); length = le->length; status = le->status; - switch (opcode) { + switch (le->opcode & ~HW_OWNER) { case OP_RXSTAT: skb = sky2_receive(sky2, length, status); if (!skb) @@ -1944,8 +1937,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) default: if (net_ratelimit()) printk(KERN_WARNING PFX - "unknown status opcode 0x%x\n", opcode); - break; + "unknown status opcode 0x%x\n", le->opcode); + goto exit_loop; } } -- cgit v1.2.2 From 72cb8529208020484cecd69bbf87719b50ee6313 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:32 -0700 Subject: sky2: synchronize irq on remove Need to make sure interrupt is not racing with unregister of network device. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ea23da53677b..9b16c2a899e0 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3327,6 +3327,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev) del_timer_sync(&hw->idle_timer); sky2_write32(hw, B0_IMSK, 0); + synchronize_irq(hw->pdev->irq); + dev0 = hw->dev[0]; dev1 = hw->dev[1]; if (dev1) -- cgit v1.2.2 From ed6d32c7a927bfccf921d15a3e25160f4528c3eb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:33 -0700 Subject: Add more support for the Yukon Ultra chip found in dual core centino laptops. The newest Yukon Ultra chipset's require more special tweaks. They seem to be like the Yukon XL chipsets. This code is transliterated from the latest SysKonnect driver; I don't have any Ultra hardware. Signed-off-by: Stephe Hemminger Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 88 ++++++++++++++++++++++++++++++++++++------------------ drivers/net/sky2.h | 3 ++ 2 files changed, 62 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 9b16c2a899e0..16a99f1ed171 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -304,7 +304,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv, pg, ledctrl, ledover; - if (sky2->autoneg == AUTONEG_ENABLE && hw->chip_id != CHIP_ID_YUKON_XL) { + if (sky2->autoneg == AUTONEG_ENABLE && + (hw->chip_id != CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | @@ -332,7 +333,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); if (sky2->autoneg == AUTONEG_ENABLE && - hw->chip_id == CHIP_ID_YUKON_XL) { + (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { ctrl &= ~PHY_M_PC_DSC_MSK; ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; } @@ -448,10 +449,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); /* set LED Function Control register */ - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ - PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */ - PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ - PHY_M_LEDC_STA0_CTRL(7))); /* 1000 Mbps */ + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, + (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ + PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */ + PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ + PHY_M_LEDC_STA0_CTRL(7))); /* 1000 Mbps */ /* set Polarity Control register */ gm_phy_write(hw, port, PHY_MARV_PHY_STAT, @@ -465,6 +467,25 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* restore page register */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); break; + case CHIP_ID_YUKON_EC_U: + pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); + + /* select page 3 to access LED control register */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); + + /* set LED Function Control register */ + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, + (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ + PHY_M_LEDC_INIT_CTRL(8) | /* 10 Mbps */ + PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ + PHY_M_LEDC_STA0_CTRL(7)));/* 1000 Mbps */ + + /* set Blink Rate in LED Timer Control Register */ + gm_phy_write(hw, port, PHY_MARV_INT_MASK, + ledctrl | PHY_M_LED_BLINK_RT(BLINK_84MS)); + /* restore page register */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); + break; default: /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ @@ -473,19 +494,21 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); } - if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev >= 2) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) { /* apply fixes in PHY AFE */ - gm_phy_write(hw, port, 22, 255); + pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255); + /* increase differential signal amplitude in 10BASE-T */ - gm_phy_write(hw, port, 24, 0xaa99); - gm_phy_write(hw, port, 23, 0x2011); + gm_phy_write(hw, port, 0x18, 0xaa99); + gm_phy_write(hw, port, 0x17, 0x2011); /* fix for IEEE A/B Symmetry failure in 1000BASE-T */ - gm_phy_write(hw, port, 24, 0xa204); - gm_phy_write(hw, port, 23, 0x2002); + gm_phy_write(hw, port, 0x18, 0xa204); + gm_phy_write(hw, port, 0x17, 0x2002); /* set page register to 0 */ - gm_phy_write(hw, port, 22, 0); + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } else { gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); @@ -559,6 +582,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) if (sky2->duplex == DUPLEX_FULL) reg |= GM_GPCR_DUP_FULL; + + /* turn off pause in 10/100mbps half duplex */ + else if (sky2->speed != SPEED_1000 && + hw->chip_id != CHIP_ID_YUKON_EC_U) + sky2->tx_pause = sky2->rx_pause = 0; } else reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL; @@ -1504,17 +1532,26 @@ static void sky2_link_up(struct sky2_port *sky2) sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF); - if (hw->chip_id == CHIP_ID_YUKON_XL) { + if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) { u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); + u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */ + + switch(sky2->speed) { + case SPEED_10: + led |= PHY_M_LEDC_INIT_CTRL(7); + break; + + case SPEED_100: + led |= PHY_M_LEDC_STA1_CTRL(7); + break; + + case SPEED_1000: + led |= PHY_M_LEDC_STA0_CTRL(7); + break; + } gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ - PHY_M_LEDC_INIT_CTRL(sky2->speed == - SPEED_10 ? 7 : 0) | - PHY_M_LEDC_STA1_CTRL(sky2->speed == - SPEED_100 ? 7 : 0) | - PHY_M_LEDC_STA0_CTRL(sky2->speed == - SPEED_1000 ? 7 : 0)); + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, led); gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } @@ -1589,7 +1626,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) sky2->speed = sky2_phy_speed(hw, aux); /* Pause bits are offset (9..8) */ - if (hw->chip_id == CHIP_ID_YUKON_XL) + if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) aux >>= 6; sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0; @@ -2226,13 +2263,6 @@ static int __devinit sky2_reset(struct sky2_hw *hw) return -EOPNOTSUPP; } - /* This chip is new and not tested yet */ - if (hw->chip_id == CHIP_ID_YUKON_EC_U) { - pr_info(PFX "%s: is a version of Yukon 2 chipset that has not been tested yet.\n", - pci_name(hw->pdev)); - pr_info("Please report success/failure to maintainer \n"); - } - /* disable ASF */ if (hw->chip_id <= CHIP_ID_YUKON_EC) { sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index b026f5653f04..8012994c9b93 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -378,6 +378,9 @@ enum { CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */ CHIP_REV_YU_EC_A2 = 1, /* Chip Rev. for Yukon-EC A2 */ CHIP_REV_YU_EC_A3 = 2, /* Chip Rev. for Yukon-EC A3 */ + + CHIP_REV_YU_EC_U_A0 = 0, + CHIP_REV_YU_EC_U_A1 = 1, }; /* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */ -- cgit v1.2.2 From 6d4b0f617d577975108ccc7e3b0c7dbe50144df6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:34 -0700 Subject: sky2: version 1.3 Update version number, to track changes. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 16a99f1ed171..60cdfcabe1fd 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.2" +#define DRV_VERSION "1.3" #define PFX DRV_NAME " " /* -- cgit v1.2.2 From 8cd35da094bed8a41eb722c1d03eab24d57bf706 Mon Sep 17 00:00:00 2001 From: Herbert Valerio Riedel Date: Mon, 1 May 2006 15:37:09 +0200 Subject: au1000_eth.c: use ether_crc() from since the au1000 driver already selects the CRC32 routines, simply replace the internal ether_crc() implementation with the semantically equivalent one from Signed-off-by: Herbert Valerio Riedel Signed-off-by: Stephen Hemminger --- drivers/net/au1000_eth.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 1363083b4d83..14dbad14afb6 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -2070,23 +2071,6 @@ static void au1000_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? - ethernet_polynomial : 0); - } - return crc; -} - static void set_rx_mode(struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; -- cgit v1.2.2 From aedc0e520e5ae9ba1342c25c4604d18fb236c2bc Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 9 May 2006 00:58:28 +0400 Subject: Fix RTL8019AS init for Toshiba RBTX49xx boards Ensure that 8-bit mode is selected for the on-board Realtek RTL8019AS chip on Toshiba RBHMA4x00, get rid of the duplicate #ifdef's when setting ei_status.word16. The chip's datasheet says that the PSTOP register shouldn't exceed 0x60 in 8-bit mode -- ensure this too. Signed-off-by: Sergei Shtylyov Signed-off-by: Stephen Hemminger --- drivers/net/ne.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 93c494bcd18d..b32765215f75 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -139,8 +139,9 @@ bad_clone_list[] __initdata = { #if defined(CONFIG_PLAT_MAPPI) # define DCR_VAL 0x4b -#elif defined(CONFIG_PLAT_OAKS32R) -# define DCR_VAL 0x48 +#elif defined(CONFIG_PLAT_OAKS32R) || \ + defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) +# define DCR_VAL 0x48 /* 8-bit mode */ #else # define DCR_VAL 0x49 #endif @@ -396,10 +397,22 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) /* We must set the 8390 for word mode. */ outb_p(DCR_VAL, ioaddr + EN0_DCFG); start_page = NESM_START_PG; - stop_page = NESM_STOP_PG; + + /* + * Realtek RTL8019AS datasheet says that the PSTOP register + * shouldn't exceed 0x60 in 8-bit mode. + * This chip can be identified by reading the signature from + * the remote byte count registers (otherwise write-only)... + */ + if ((DCR_VAL & 0x01) == 0 && /* 8-bit mode */ + inb(ioaddr + EN0_RCNTLO) == 0x50 && + inb(ioaddr + EN0_RCNTHI) == 0x70) + stop_page = 0x60; + else + stop_page = NESM_STOP_PG; } else { start_page = NE1SM_START_PG; - stop_page = NE1SM_STOP_PG; + stop_page = NE1SM_STOP_PG; } #if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R) @@ -509,15 +522,9 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.name = name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; -#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) - wordlength = 1; -#endif -#ifdef CONFIG_PLAT_OAKS32R - ei_status.word16 = 0; -#else - ei_status.word16 = (wordlength == 2); -#endif + /* Use 16-bit mode only if this wasn't overridden by DCR_VAL */ + ei_status.word16 = (wordlength == 2 && (DCR_VAL & 0x01)); ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE -- cgit v1.2.2 From b636d17a3bee8ba988e78e4bc8262f0dc3fad8ab Mon Sep 17 00:00:00 2001 From: Jens Osterkamp Date: Thu, 4 May 2006 05:59:56 -0400 Subject: spidernet: introduce new setting We found a new chip setting that we need in order to make the driver work more reliable. Signed-off-by: Arnd Bergmann Signed-off-by: Stephen Hemminger --- drivers/net/spider_net.c | 2 ++ drivers/net/spider_net.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 43f5e86fc559..b36838bfb8dc 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1652,6 +1652,8 @@ spider_net_enable_card(struct spider_net_card *card) { SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE }, { SPIDER_NET_GMRWOLCTRL, 0 }, + { SPIDER_NET_GTESTMD, 0x10000000 }, + { SPIDER_NET_GTTQMSK, 0x00400040 }, { SPIDER_NET_GTESTMD, 0 }, { SPIDER_NET_GMACINTEN, 0 }, diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 5922b529a048..3b8d951cf73c 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -120,6 +120,8 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_GMRUAFILnR 0x00000500 #define SPIDER_NET_GMRUA0FIL15R 0x00000578 +#define SPIDER_NET_GTTQMSK 0x00000934 + /* RX DMA controller registers, all 0x00000a.. are for DMA controller A, * 0x00000b.. for DMA controller B, etc. */ #define SPIDER_NET_GDADCHA 0x00000a00 -- cgit v1.2.2 From 8ec93459655a3618dedec6360bb28d63f0010ef6 Mon Sep 17 00:00:00 2001 From: Jens Osterkamp Date: Thu, 4 May 2006 05:59:41 -0400 Subject: spidernet: enable support for bcm5461 ethernet phy A newer board revision changed the type of ethernet phy. Moreover, this generalizes the way that a phy gets switched into fiber mode when autodetection is not available. Signed-off-by: Jens Osterkamp Signed-off-by: Arnd Bergmann Signed-off-by: Stephen Hemminger --- drivers/net/spider_net.c | 10 +--------- drivers/net/sungem_phy.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ drivers/net/sungem_phy.h | 1 + 3 files changed, 47 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index b36838bfb8dc..394339d5e87c 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1794,15 +1794,7 @@ spider_net_setup_phy(struct spider_net_card *card) if (phy->def->ops->setup_forced) phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL); - /* the following two writes could be moved to sungem_phy.c */ - /* enable fiber mode */ - spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x9020); - /* LEDs active in both modes, autosense prio = fiber */ - spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f); - - /* switch off fibre autoneg */ - spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0xfc01); - spider_net_write_phy(card->netdev, 1, 0x0b, 0x0004); + phy->def->ops->enable_fiber(phy); phy->def->ops->read_link(phy); pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index 046371ee5bbe..b2ddd5e79303 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -329,6 +329,30 @@ static int bcm5421_init(struct mii_phy* phy) return 0; } +static int bcm5421_enable_fiber(struct mii_phy* phy) +{ + /* enable fiber mode */ + phy_write(phy, MII_NCONFIG, 0x9020); + /* LEDs active in both modes, autosense prio = fiber */ + phy_write(phy, MII_NCONFIG, 0x945f); + + /* switch off fibre autoneg */ + phy_write(phy, MII_NCONFIG, 0xfc01); + phy_write(phy, 0x0b, 0x0004); + + return 0; +} + +static int bcm5461_enable_fiber(struct mii_phy* phy) +{ + phy_write(phy, MII_NCONFIG, 0xfc0c); + phy_write(phy, MII_BMCR, 0x4140); + phy_write(phy, MII_NCONFIG, 0xfc0b); + phy_write(phy, MII_BMCR, 0x0140); + + return 0; +} + static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise) { u16 ctl, adv; @@ -762,6 +786,7 @@ static struct mii_phy_ops bcm5421_phy_ops = { .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, .read_link = bcm54xx_read_link, + .enable_fiber = bcm5421_enable_fiber, }; static struct mii_phy_def bcm5421_phy_def = { @@ -792,6 +817,25 @@ static struct mii_phy_def bcm5421k2_phy_def = { .ops = &bcm5421k2_phy_ops }; +static struct mii_phy_ops bcm5461_phy_ops = { + .init = bcm5421_init, + .suspend = generic_suspend, + .setup_aneg = bcm54xx_setup_aneg, + .setup_forced = bcm54xx_setup_forced, + .poll_link = genmii_poll_link, + .read_link = bcm54xx_read_link, + .enable_fiber = bcm5461_enable_fiber, +}; + +static struct mii_phy_def bcm5461_phy_def = { + .phy_id = 0x002060c0, + .phy_id_mask = 0xfffffff0, + .name = "BCM5461", + .features = MII_GBIT_FEATURES, + .magic_aneg = 1, + .ops = &bcm5461_phy_ops +}; + /* Broadcom BCM 5462 built-in Vesta */ static struct mii_phy_ops bcm5462V_phy_ops = { .init = bcm5421_init, @@ -857,6 +901,7 @@ static struct mii_phy_def* mii_phy_table[] = { &bcm5411_phy_def, &bcm5421_phy_def, &bcm5421k2_phy_def, + &bcm5461_phy_def, &bcm5462V_phy_def, &marvell_phy_def, &genmii_phy_def, diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h index 430544496c52..69e125197fcf 100644 --- a/drivers/net/sungem_phy.h +++ b/drivers/net/sungem_phy.h @@ -12,6 +12,7 @@ struct mii_phy_ops int (*setup_forced)(struct mii_phy *phy, int speed, int fd); int (*poll_link)(struct mii_phy *phy); int (*read_link)(struct mii_phy *phy); + int (*enable_fiber)(struct mii_phy *phy); }; /* Structure used to statically define an mii/gii based PHY */ -- cgit v1.2.2 From 839ab1d4ce4dfd7e6c189391a82c584292488b41 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 26 Apr 2006 14:39:11 -0700 Subject: [PATCH] USB: fix bug in ohci-hcd.c ohci_restart() A loop on a power-lost resume path used the wrong index. I suspect khubd has been working around such bugs. Noticed by Andreas Mohr . Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 544f7589912f..73f5a379d9b3 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -863,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci) i = ohci->num_ports; while (i--) ohci_writel (ohci, RH_PS_PSS, - &ohci->regs->roothub.portstatus [temp]); + &ohci->regs->roothub.portstatus [i]); ohci_dbg (ohci, "restart complete\n"); } return 0; -- cgit v1.2.2 From 67c752b41a4238c1a2d7eebcd061ff8c1127d3e9 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Fri, 28 Apr 2006 18:44:06 +0200 Subject: [PATCH] USBATM: change the default speedtouch iso altsetting The maximum possible bandwidth for a speedtouch modem is about 7Mbaud. You can only get this by using isochronous urbs (enable_isoc=1) and altsetting 3. With the current default altsetting of 2, the modem maxes out at about 4Mbaud. So change the default altsetting to 3 when using isochronous urbs. It would be nice to base the altsetting on the detected line speed, but that's hard given the current design. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 7860c8a5800d..956b7a1e8af9 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -69,7 +69,7 @@ static const char speedtch_driver_name[] = "speedtch"; #define RESUBMIT_DELAY 1000 /* milliseconds */ #define DEFAULT_BULK_ALTSETTING 1 -#define DEFAULT_ISOC_ALTSETTING 2 +#define DEFAULT_ISOC_ALTSETTING 3 #define DEFAULT_DL_512_FIRST 0 #define DEFAULT_ENABLE_ISOC 0 #define DEFAULT_SW_BUFFERING 0 -- cgit v1.2.2 From 6275cdfa0fe032208937a3567ebb8bcfd42d20b1 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Fri, 28 Apr 2006 18:52:16 +0200 Subject: [PATCH] USBATM: fix modinfo output Because of the way stringify works, using an expression like 64 * 1024 for UDSL_MAX_BUF_SIZE results in 64 * 1024 turning up in the modinfo output instead of 65536. So use 65536 directly (this was the only way I found of fixing this). Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index c1211fc037d9..546249843b8e 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -99,11 +99,11 @@ static const char usbatm_driver_name[] = "usbatm"; #define UDSL_MAX_RCV_URBS 16 #define UDSL_MAX_SND_URBS 16 -#define UDSL_MAX_BUF_SIZE 64 * 1024 /* bytes */ +#define UDSL_MAX_BUF_SIZE 65536 #define UDSL_DEFAULT_RCV_URBS 4 #define UDSL_DEFAULT_SND_URBS 4 -#define UDSL_DEFAULT_RCV_BUF_SIZE 64 * ATM_CELL_SIZE /* bytes */ -#define UDSL_DEFAULT_SND_BUF_SIZE 64 * ATM_CELL_SIZE /* bytes */ +#define UDSL_DEFAULT_RCV_BUF_SIZE 3392 /* 64 * ATM_CELL_SIZE */ +#define UDSL_DEFAULT_SND_BUF_SIZE 3392 /* 64 * ATM_CELL_SIZE */ #define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD) @@ -135,7 +135,7 @@ MODULE_PARM_DESC(rcv_buf_bytes, module_param(snd_buf_bytes, uint, S_IRUGO); MODULE_PARM_DESC(snd_buf_bytes, "Size of the buffers used for transmission, in bytes (range: 1-" - __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: " + __MODULE_STRING(UDSL_MAX_BUF_SIZE) ", default: " __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")"); -- cgit v1.2.2 From 7e713b825610de9a9584c189c72e2d9f2326359c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 1 May 2006 14:02:45 -0700 Subject: [PATCH] USB: pegasus fixes (logstorm, suspend) Teach "pegasus" to handle a few of the disconnect fault paths without hundreds of usless syslog messages. Handle the carrier check workqueue entry even if the driver has not been opened. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/pegasus.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 2deb4c01539e..7683926a1b6f 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -318,6 +318,8 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) set_register(pegasus, PhyCtrl, (indx | PHY_READ)); for (i = 0; i < REG_TIMEOUT; i++) { ret = get_registers(pegasus, PhyCtrl, 1, data); + if (ret == -ESHUTDOWN) + goto fail; if (data[0] & PHY_DONE) break; } @@ -326,6 +328,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) *regd = le16_to_cpu(regdi); return ret; } +fail: if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); @@ -354,12 +357,15 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) set_register(pegasus, PhyCtrl, (indx | PHY_WRITE)); for (i = 0; i < REG_TIMEOUT; i++) { ret = get_registers(pegasus, PhyCtrl, 1, data); + if (ret == -ESHUTDOWN) + goto fail; if (data[0] & PHY_DONE) break; } if (i < REG_TIMEOUT) return ret; +fail: if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); return -ETIMEDOUT; @@ -387,6 +393,8 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) ret = get_registers(pegasus, EpromCtrl, 1, &tmp); if (tmp & EPROM_DONE) break; + if (ret == -ESHUTDOWN) + goto fail; } if (i < REG_TIMEOUT) { ret = get_registers(pegasus, EpromData, 2, &retdatai); @@ -394,6 +402,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) return ret; } +fail: if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); return -ETIMEDOUT; @@ -433,12 +442,15 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) for (i = 0; i < REG_TIMEOUT; i++) { ret = get_registers(pegasus, EpromCtrl, 1, &tmp); + if (ret == -ESHUTDOWN) + goto fail; if (tmp & EPROM_DONE) break; } disable_eprom_write(pegasus); if (i < REG_TIMEOUT) return ret; +fail: if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); return -ETIMEDOUT; @@ -1378,9 +1390,8 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) struct pegasus *pegasus = usb_get_intfdata(intf); netif_device_detach (pegasus->net); + cancel_delayed_work(&pegasus->carrier_check); if (netif_running(pegasus->net)) { - cancel_delayed_work(&pegasus->carrier_check); - usb_kill_urb(pegasus->rx_urb); usb_kill_urb(pegasus->intr_urb); } @@ -1400,10 +1411,9 @@ static int pegasus_resume (struct usb_interface *intf) pegasus->intr_urb->status = 0; pegasus->intr_urb->actual_length = 0; intr_callback(pegasus->intr_urb, NULL); - - queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, - CARRIER_CHECK_DELAY); } + queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, + CARRIER_CHECK_DELAY); return 0; } -- cgit v1.2.2 From db4cefaaea4c6d67cdaebfd315abc791c5c9d22f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 1 May 2006 22:07:13 -0700 Subject: [PATCH] USB: fix OHCI PM regression This fixes a small regression in USB controller power usage for many OHCI controllers, notably including every non-PCI version of OHCI: on those systems, the runtime autosuspend mechanism is no longer enabled. The change moves to saner defaults. All root hubs are expected to handle remote wakeup (and hence autosuspend), although drivers for buggy silicon may override that default. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fbd938d4ea58..e2e00ba4e1e6 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1805,6 +1805,12 @@ int usb_add_hcd(struct usb_hcd *hcd, USB_SPEED_FULL; hcd->self.root_hub = rhdev; + /* wakeup flag init defaults to "everything works" for root hubs, + * but drivers can override it in reset() if needed, along with + * recording the overall controller's system wakeup capability. + */ + device_init_wakeup(&rhdev->dev, 1); + /* "reset" is misnamed; its role is now one-time init. the controller * should already have been reset (and boot firmware kicked off etc). */ @@ -1813,13 +1819,6 @@ int usb_add_hcd(struct usb_hcd *hcd, goto err_hcd_driver_setup; } - /* wakeup flag init is in transition; for now we can't rely on PCI to - * initialize these bits properly, so we let reset() override it. - * This init should _precede_ the reset() once PCI behaves. - */ - device_init_wakeup(&rhdev->dev, - device_can_wakeup(hcd->self.controller)); - /* NOTE: root hub and controller capabilities may not be the same */ if (device_can_wakeup(hcd->self.controller) && device_can_wakeup(&hcd->self.root_hub->dev)) -- cgit v1.2.2 From 436f5762bcd4929825a0725d4bc78337e6fc0d8f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 May 2006 15:22:41 -0400 Subject: [PATCH] USB: usbcore: don't check the device's power source The choose_configuration() routine contains code the determine the device's power source, so that configurations requiring external power can be ruled out if the device is running on bus power. Unfortunately it turns out that some devices have errors in their config descriptors and other devices don't like the GET_DEVICE_STATUS request. Since that information wasn't used for anything else, this patch (as673) removes the code, leaving only a comment. It fixes bugzilla entry #6448. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0c87f73f2933..90b8d43c6b33 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1168,19 +1168,9 @@ static inline const char *plural(int n) static int choose_configuration(struct usb_device *udev) { int i; - u16 devstatus; - int bus_powered; int num_configs; struct usb_host_config *c, *best; - /* If this fails, assume the device is bus-powered */ - devstatus = 0; - usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); - le16_to_cpus(&devstatus); - bus_powered = ((devstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0); - dev_dbg(&udev->dev, "device is %s-powered\n", - bus_powered ? "bus" : "self"); - best = NULL; c = udev->config; num_configs = udev->descriptor.bNumConfigurations; @@ -1197,6 +1187,19 @@ static int choose_configuration(struct usb_device *udev) * similar errors in their descriptors. If the next test * were allowed to execute, such configurations would always * be rejected and the devices would not work as expected. + * In the meantime, we run the risk of selecting a config + * that requires external power at a time when that power + * isn't available. It seems to be the lesser of two evils. + * + * Bugzilla #6448 reports a device that appears to crash + * when it receives a GET_DEVICE_STATUS request! We don't + * have any other way to tell whether a device is self-powered, + * but since we don't use that information anywhere but here, + * the call has been removed. + * + * Maybe the GET_DEVICE_STATUS call and the test below can + * be reinstated when device firmwares become more reliable. + * Don't hold your breath. */ #if 0 /* Rule out self-powered configs for a bus-powered device */ -- cgit v1.2.2 From 77ef6c4d6e23653a79eedacdd6d1d0da7083e59c Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Wed, 3 May 2006 00:16:00 -0700 Subject: [PATCH] USB: ub oops in block_uevent In kernel 2.6.16, if a mounted storage device is removed, an oops happens because ub supplies an interface device (and kobject) to the block layer, but neglects to pin it. And apparently, the block layer expects its users to pin device structures. The code in ub was broken this way for years. But the bug was exposed only by 2.6.16 when it started to call block_uevent on close, which traverses device structures (kobjects actually). Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/block/ub.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ub.c b/drivers/block/ub.c index f73446f580df..c688c25992e4 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -536,6 +536,9 @@ static void ub_cleanup(struct ub_dev *sc) kfree(lun); } + usb_set_intfdata(sc->intf, NULL); + usb_put_intf(sc->intf); + usb_put_dev(sc->dev); kfree(sc); } @@ -2221,7 +2224,12 @@ static int ub_probe(struct usb_interface *intf, // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; usb_set_intfdata(intf, sc); usb_get_dev(sc->dev); - // usb_get_intf(sc->intf); /* Do we need this? */ + /* + * Since we give the interface struct to the block level through + * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent + * oopses on close after a disconnect (kernels 2.6.16 and up). + */ + usb_get_intf(sc->intf); snprintf(sc->name, 12, DRV_NAME "(%d.%d)", sc->dev->bus->busnum, sc->dev->devnum); @@ -2286,7 +2294,7 @@ static int ub_probe(struct usb_interface *intf, err_dev_desc: usb_set_intfdata(intf, NULL); - // usb_put_intf(sc->intf); + usb_put_intf(sc->intf); usb_put_dev(sc->dev); kfree(sc); err_core: @@ -2461,12 +2469,6 @@ static void ub_disconnect(struct usb_interface *intf) * and no URBs left in transit. */ - usb_set_intfdata(intf, NULL); - // usb_put_intf(sc->intf); - sc->intf = NULL; - usb_put_dev(sc->dev); - sc->dev = NULL; - ub_put(sc); } -- cgit v1.2.2 From 20a0f47e18c646bcc772282512fc59e56b2fc968 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 4 May 2006 11:34:25 +0100 Subject: [PATCH] USB: ftdi_sio: Add support for HCG HF Dual ISO RFID Reader This patch adds support for ACG Identification Technologies GmbH's HF Dual ISO Reader (an RFID tag reader) to the ftdi_sio driver's device ID table. The product ID was supplied by anotonios (anton at goto10 dot org) on the ftdi-usb-sio-devel list and subsequently verified by myself (Ian Abbott). Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 82151207d814..9498da461036 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -498,6 +498,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 2c55a5ea9c99..3e4123f09e0d 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -426,6 +426,11 @@ #define PAPOUCH_VID 0x5050 /* Vendor ID */ #define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */ +/* + * ACG Identification Technologies GmbH products (http://www.acg.de/). + * Submitted by anton -at- goto10 -dot- org. + */ +#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ -- cgit v1.2.2 From 72a9f958421a519e69b3e7b409948c3a294f4a32 Mon Sep 17 00:00:00 2001 From: Razvan Gavril Date: Thu, 4 May 2006 11:35:49 +0300 Subject: [PATCH] USB: ftdi_sio: add device id for ACT Solutions HomePro ZWave interface Signed-off-by: Razvan Gavril Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9498da461036..986d7622273d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -307,6 +307,7 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 3e4123f09e0d..d69a917e768f 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -32,6 +32,10 @@ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ +/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */ +#define FTDI_ACTZWAVE_PID 0xF2D0 + + /* www.irtrans.de device */ #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ -- cgit v1.2.2 From d8b9f23b23e080d820e3c0aa5ccd7834c26ebf96 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Tue, 9 May 2006 10:50:28 -0700 Subject: IB: Fix display of 4-bit port counters in sysfs The code to display local_link_integrity_errors and excessive_buffer_overrun_errors in /sys/class/infiniband//ports//counters/ uses the wrong shift to extract the 4 bit values. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/core/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 15121cb5a1f6..21f9282c1b25 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -336,7 +336,7 @@ static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr, switch (width) { case 4: ret = sprintf(buf, "%u\n", (out_mad->data[40 + offset / 8] >> - (offset % 4)) & 0xf); + (4 - (offset % 8))) & 0xf); break; case 8: ret = sprintf(buf, "%u\n", out_mad->data[40 + offset / 8]); -- cgit v1.2.2 From d945e1df28ca07642b3e1a9b9d07074ba5f76be0 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 May 2006 10:50:28 -0700 Subject: IB/srp: Fix tracking of pending requests during error handling If a SCSI abort completes, or the command completes successfully, then the driver must remove the command from its queue of pending commands. Similarly, if a device reset succeeds, then all commands queued for the given device must be removed from the queue. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 195 +++++++++++++++++++++--------------- drivers/infiniband/ulp/srp/ib_srp.h | 4 +- 2 files changed, 115 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 5bb55742ada6..c32ce4348e1b 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -409,6 +409,34 @@ static int srp_connect_target(struct srp_target_port *target) } } +static void srp_unmap_data(struct scsi_cmnd *scmnd, + struct srp_target_port *target, + struct srp_request *req) +{ + struct scatterlist *scat; + int nents; + + if (!scmnd->request_buffer || + (scmnd->sc_data_direction != DMA_TO_DEVICE && + scmnd->sc_data_direction != DMA_FROM_DEVICE)) + return; + + /* + * This handling of non-SG commands can be killed when the + * SCSI midlayer no longer generates non-SG commands. + */ + if (likely(scmnd->use_sg)) { + nents = scmnd->use_sg; + scat = scmnd->request_buffer; + } else { + nents = 1; + scat = &req->fake_sg; + } + + dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, + scmnd->sc_data_direction); +} + static int srp_reconnect_target(struct srp_target_port *target) { struct ib_cm_id *new_cm_id; @@ -455,16 +483,16 @@ static int srp_reconnect_target(struct srp_target_port *target) list_for_each_entry(req, &target->req_queue, list) { req->scmnd->result = DID_RESET << 16; req->scmnd->scsi_done(req->scmnd); + srp_unmap_data(req->scmnd, target, req); } target->rx_head = 0; target->tx_head = 0; target->tx_tail = 0; - target->req_head = 0; - for (i = 0; i < SRP_SQ_SIZE - 1; ++i) - target->req_ring[i].next = i + 1; - target->req_ring[SRP_SQ_SIZE - 1].next = -1; + INIT_LIST_HEAD(&target->free_reqs); INIT_LIST_HEAD(&target->req_queue); + for (i = 0; i < SRP_SQ_SIZE; ++i) + list_add_tail(&target->req_ring[i].list, &target->free_reqs); ret = srp_connect_target(target); if (ret) @@ -589,40 +617,10 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, return len; } -static void srp_unmap_data(struct scsi_cmnd *scmnd, - struct srp_target_port *target, - struct srp_request *req) -{ - struct scatterlist *scat; - int nents; - - if (!scmnd->request_buffer || - (scmnd->sc_data_direction != DMA_TO_DEVICE && - scmnd->sc_data_direction != DMA_FROM_DEVICE)) - return; - - /* - * This handling of non-SG commands can be killed when the - * SCSI midlayer no longer generates non-SG commands. - */ - if (likely(scmnd->use_sg)) { - nents = scmnd->use_sg; - scat = scmnd->request_buffer; - } else { - nents = 1; - scat = &req->fake_sg; - } - - dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, - scmnd->sc_data_direction); -} - -static void srp_remove_req(struct srp_target_port *target, struct srp_request *req, - int index) +static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) { - list_del(&req->list); - req->next = target->req_head; - target->req_head = index; + srp_unmap_data(req->scmnd, target, req); + list_move_tail(&req->list, &target->free_reqs); } static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) @@ -647,7 +645,7 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) req->tsk_status = rsp->data[3]; complete(&req->done); } else { - scmnd = req->scmnd; + scmnd = req->scmnd; if (!scmnd) printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n", (unsigned long long) rsp->tag); @@ -665,14 +663,11 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt); - srp_unmap_data(scmnd, target, req); - if (!req->tsk_mgmt) { - req->scmnd = NULL; scmnd->host_scribble = (void *) -1L; scmnd->scsi_done(scmnd); - srp_remove_req(target, req, rsp->tag & ~SRP_TAG_TSK_MGMT); + srp_remove_req(target, req); } else req->cmd_done = 1; } @@ -859,7 +854,6 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, struct srp_request *req; struct srp_iu *iu; struct srp_cmd *cmd; - long req_index; int len; if (target->state == SRP_TARGET_CONNECTING) @@ -879,22 +873,20 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma, SRP_MAX_IU_LEN, DMA_TO_DEVICE); - req_index = target->req_head; + req = list_entry(target->free_reqs.next, struct srp_request, list); scmnd->scsi_done = done; scmnd->result = 0; - scmnd->host_scribble = (void *) req_index; + scmnd->host_scribble = (void *) (long) req->index; cmd = iu->buf; memset(cmd, 0, sizeof *cmd); cmd->opcode = SRP_CMD; cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48); - cmd->tag = req_index; + cmd->tag = req->index; memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); - req = &target->req_ring[req_index]; - req->scmnd = scmnd; req->cmd = iu; req->cmd_done = 0; @@ -919,8 +911,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, goto err_unmap; } - target->req_head = req->next; - list_add_tail(&req->list, &target->req_queue); + list_move_tail(&req->list, &target->req_queue); return 0; @@ -1143,30 +1134,20 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) return 0; } -static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) +static int srp_send_tsk_mgmt(struct srp_target_port *target, + struct srp_request *req, u8 func) { - struct srp_target_port *target = host_to_target(scmnd->device->host); - struct srp_request *req; struct srp_iu *iu; struct srp_tsk_mgmt *tsk_mgmt; - int req_index; - int ret = FAILED; spin_lock_irq(target->scsi_host->host_lock); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) { - scmnd->result = DID_BAD_TARGET << 16; + req->scmnd->result = DID_BAD_TARGET << 16; goto out; } - if (scmnd->host_scribble == (void *) -1L) - goto out; - - req_index = (long) scmnd->host_scribble; - printk(KERN_ERR "Abort for req_index %d\n", req_index); - - req = &target->req_ring[req_index]; init_completion(&req->done); iu = __srp_get_tx_iu(target); @@ -1177,10 +1158,10 @@ static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) memset(tsk_mgmt, 0, sizeof *tsk_mgmt); tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = cpu_to_be64((u64) scmnd->device->lun << 48); - tsk_mgmt->tag = req_index | SRP_TAG_TSK_MGMT; + tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48); + tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT; tsk_mgmt->tsk_mgmt_func = func; - tsk_mgmt->task_tag = req_index; + tsk_mgmt->task_tag = req->index; if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) goto out; @@ -1188,37 +1169,85 @@ static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) req->tsk_mgmt = iu; spin_unlock_irq(target->scsi_host->host_lock); + if (!wait_for_completion_timeout(&req->done, msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) - return FAILED; - spin_lock_irq(target->scsi_host->host_lock); + return -1; - if (req->cmd_done) { - srp_remove_req(target, req, req_index); - scmnd->scsi_done(scmnd); - } else if (!req->tsk_status) { - srp_remove_req(target, req, req_index); - scmnd->result = DID_ABORT << 16; - ret = SUCCESS; - } + return 0; out: spin_unlock_irq(target->scsi_host->host_lock); - return ret; + return -1; +} + +static int srp_find_req(struct srp_target_port *target, + struct scsi_cmnd *scmnd, + struct srp_request **req) +{ + if (scmnd->host_scribble == (void *) -1L) + return -1; + + *req = &target->req_ring[(long) scmnd->host_scribble]; + + return 0; } static int srp_abort(struct scsi_cmnd *scmnd) { + struct srp_target_port *target = host_to_target(scmnd->device->host); + struct srp_request *req; + int ret = SUCCESS; + printk(KERN_ERR "SRP abort called\n"); - return srp_send_tsk_mgmt(scmnd, SRP_TSK_ABORT_TASK); + if (srp_find_req(target, scmnd, &req)) + return FAILED; + if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) + return FAILED; + + spin_lock_irq(target->scsi_host->host_lock); + + if (req->cmd_done) { + srp_remove_req(target, req); + scmnd->scsi_done(scmnd); + } else if (!req->tsk_status) { + srp_remove_req(target, req); + scmnd->result = DID_ABORT << 16; + } else + ret = FAILED; + + spin_unlock_irq(target->scsi_host->host_lock); + + return ret; } static int srp_reset_device(struct scsi_cmnd *scmnd) { + struct srp_target_port *target = host_to_target(scmnd->device->host); + struct srp_request *req, *tmp; + printk(KERN_ERR "SRP reset_device called\n"); - return srp_send_tsk_mgmt(scmnd, SRP_TSK_LUN_RESET); + if (srp_find_req(target, scmnd, &req)) + return FAILED; + if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) + return FAILED; + if (req->tsk_status) + return FAILED; + + spin_lock_irq(target->scsi_host->host_lock); + + list_for_each_entry_safe(req, tmp, &target->req_queue, list) + if (req->scmnd->device == scmnd->device) { + req->scmnd->result = DID_RESET << 16; + scmnd->scsi_done(scmnd); + srp_remove_req(target, req); + } + + spin_unlock_irq(target->scsi_host->host_lock); + + return SUCCESS; } static int srp_reset_host(struct scsi_cmnd *scmnd) @@ -1518,10 +1547,12 @@ static ssize_t srp_create_target(struct class_device *class_dev, INIT_WORK(&target->work, srp_reconnect_work, target); - for (i = 0; i < SRP_SQ_SIZE - 1; ++i) - target->req_ring[i].next = i + 1; - target->req_ring[SRP_SQ_SIZE - 1].next = -1; + INIT_LIST_HEAD(&target->free_reqs); INIT_LIST_HEAD(&target->req_queue); + for (i = 0; i < SRP_SQ_SIZE; ++i) { + target->req_ring[i].index = i; + list_add_tail(&target->req_ring[i].list, &target->free_reqs); + } ret = srp_parse_options(buf, target); if (ret) diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index bd7f7c3115de..c5cd43aae860 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -101,7 +101,7 @@ struct srp_request { */ struct scatterlist fake_sg; struct completion done; - short next; + short index; u8 cmd_done; u8 tsk_status; }; @@ -133,7 +133,7 @@ struct srp_target_port { unsigned tx_tail; struct srp_iu *tx_ring[SRP_SQ_SIZE + 1]; - int req_head; + struct list_head free_reqs; struct list_head req_queue; struct srp_request req_ring[SRP_SQ_SIZE]; -- cgit v1.2.2 From a3285aa4eecd722508dab01c4932b11b4ba80134 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 May 2006 10:50:29 -0700 Subject: IB/mthca: Fix race in reference counting Fix races in in destroying various objects. If a destroy routine waits for an object to become free by doing wait_event(&obj->wait, !atomic_read(&obj->refcount)); /* now clean up and destroy the object */ and another place drops a reference to the object by doing if (atomic_dec_and_test(&obj->refcount)) wake_up(&obj->wait); then this is susceptible to a race where the wait_event() and final freeing of the object occur between the atomic_dec_and_test() and the wake_up(). And this is a use-after-free, since wake_up() will be called on part of the already-freed object. Fix this in mthca by replacing the atomic_t refcounts with plain old integers protected by a spinlock. This makes it possible to do the decrement of the reference count and the wake_up() so that it appears as a single atomic operation to the code waiting on the wait queue. While touching this code, also simplify mthca_cq_clean(): the CQ being cleaned cannot go away, because it still has a QP attached to it. So there's no reason to be paranoid and look up the CQ by number; it's perfectly safe to use the pointer that the callers already have. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cq.c | 41 ++++++++++++++-------------- drivers/infiniband/hw/mthca/mthca_dev.h | 2 +- drivers/infiniband/hw/mthca/mthca_provider.h | 22 ++++++++------- drivers/infiniband/hw/mthca/mthca_qp.c | 31 +++++++++++++++------ drivers/infiniband/hw/mthca/mthca_srq.c | 23 ++++++++++++---- 5 files changed, 74 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 312cf90731ea..205854e9c662 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -238,9 +238,9 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn, spin_lock(&dev->cq_table.lock); cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); + ++cq->refcount; + spin_unlock(&dev->cq_table.lock); if (!cq) { @@ -254,8 +254,10 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn, if (cq->ibcq.event_handler) cq->ibcq.event_handler(&event, cq->ibcq.cq_context); - if (atomic_dec_and_test(&cq->refcount)) + spin_lock(&dev->cq_table.lock); + if (!--cq->refcount) wake_up(&cq->wait); + spin_unlock(&dev->cq_table.lock); } static inline int is_recv_cqe(struct mthca_cqe *cqe) @@ -267,23 +269,13 @@ static inline int is_recv_cqe(struct mthca_cqe *cqe) return !(cqe->is_send & 0x80); } -void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, +void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn, struct mthca_srq *srq) { - struct mthca_cq *cq; struct mthca_cqe *cqe; u32 prod_index; int nfreed = 0; - spin_lock_irq(&dev->cq_table.lock); - cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); - spin_unlock_irq(&dev->cq_table.lock); - - if (!cq) - return; - spin_lock_irq(&cq->lock); /* @@ -301,7 +293,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, if (0) mthca_dbg(dev, "Cleaning QPN %06x from CQN %06x; ci %d, pi %d\n", - qpn, cqn, cq->cons_index, prod_index); + qpn, cq->cqn, cq->cons_index, prod_index); /* * Now sweep backwards through the CQ, removing CQ entries @@ -325,8 +317,6 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, } spin_unlock_irq(&cq->lock); - if (atomic_dec_and_test(&cq->refcount)) - wake_up(&cq->wait); } void mthca_cq_resize_copy_cqes(struct mthca_cq *cq) @@ -821,7 +811,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, } spin_lock_init(&cq->lock); - atomic_set(&cq->refcount, 1); + cq->refcount = 1; init_waitqueue_head(&cq->wait); memset(cq_context, 0, sizeof *cq_context); @@ -896,6 +886,17 @@ err_out: return err; } +static inline int get_cq_refcount(struct mthca_dev *dev, struct mthca_cq *cq) +{ + int c; + + spin_lock_irq(&dev->cq_table.lock); + c = cq->refcount; + spin_unlock_irq(&dev->cq_table.lock); + + return c; +} + void mthca_free_cq(struct mthca_dev *dev, struct mthca_cq *cq) { @@ -929,6 +930,7 @@ void mthca_free_cq(struct mthca_dev *dev, spin_lock_irq(&dev->cq_table.lock); mthca_array_clear(&dev->cq_table.cq, cq->cqn & (dev->limits.num_cqs - 1)); + --cq->refcount; spin_unlock_irq(&dev->cq_table.lock); if (dev->mthca_flags & MTHCA_FLAG_MSI_X) @@ -936,8 +938,7 @@ void mthca_free_cq(struct mthca_dev *dev, else synchronize_irq(dev->pdev->irq); - atomic_dec(&cq->refcount); - wait_event(cq->wait, !atomic_read(&cq->refcount)); + wait_event(cq->wait, !get_cq_refcount(dev, cq)); if (cq->is_kernel) { mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 4c1dcb4c1822..f8160b8de090 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -496,7 +496,7 @@ void mthca_free_cq(struct mthca_dev *dev, void mthca_cq_completion(struct mthca_dev *dev, u32 cqn); void mthca_cq_event(struct mthca_dev *dev, u32 cqn, enum ib_event_type event_type); -void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, +void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn, struct mthca_srq *srq); void mthca_cq_resize_copy_cqes(struct mthca_cq *cq); int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 6676a786d690..179a8f610d0f 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -139,11 +139,12 @@ struct mthca_ah { * a qp may be locked, with the send cq locked first. No other * nesting should be done. * - * Each struct mthca_cq/qp also has an atomic_t ref count. The - * pointer from the cq/qp_table to the struct counts as one reference. - * This reference also is good for access through the consumer API, so - * modifying the CQ/QP etc doesn't need to take another reference. - * Access because of a completion being polled does need a reference. + * Each struct mthca_cq/qp also has an ref count, protected by the + * corresponding table lock. The pointer from the cq/qp_table to the + * struct counts as one reference. This reference also is good for + * access through the consumer API, so modifying the CQ/QP etc doesn't + * need to take another reference. Access to a QP because of a + * completion being polled does not need a reference either. * * Finally, each struct mthca_cq/qp has a wait_queue_head_t for the * destroy function to sleep on. @@ -159,8 +160,9 @@ struct mthca_ah { * - decrement ref count; if zero, wake up waiters * * To destroy a CQ/QP, we can do the following: - * - lock cq/qp_table, remove pointer, unlock cq/qp_table lock - * - decrement ref count + * - lock cq/qp_table + * - remove pointer and decrement ref count + * - unlock cq/qp_table lock * - wait_event until ref count is zero * * It is the consumer's responsibilty to make sure that no QP @@ -197,7 +199,7 @@ struct mthca_cq_resize { struct mthca_cq { struct ib_cq ibcq; spinlock_t lock; - atomic_t refcount; + int refcount; int cqn; u32 cons_index; struct mthca_cq_buf buf; @@ -217,7 +219,7 @@ struct mthca_cq { struct mthca_srq { struct ib_srq ibsrq; spinlock_t lock; - atomic_t refcount; + int refcount; int srqn; int max; int max_gs; @@ -254,7 +256,7 @@ struct mthca_wq { struct mthca_qp { struct ib_qp ibqp; - atomic_t refcount; + int refcount; u32 qpn; int is_direct; u8 port; /* for SQP and memfree use only */ diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index f37b0e367323..19765f6f8d58 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -240,7 +240,7 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn, spin_lock(&dev->qp_table.lock); qp = mthca_array_get(&dev->qp_table.qp, qpn & (dev->limits.num_qps - 1)); if (qp) - atomic_inc(&qp->refcount); + ++qp->refcount; spin_unlock(&dev->qp_table.lock); if (!qp) { @@ -257,8 +257,10 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn, if (qp->ibqp.event_handler) qp->ibqp.event_handler(&event, qp->ibqp.qp_context); - if (atomic_dec_and_test(&qp->refcount)) + spin_lock(&dev->qp_table.lock); + if (!--qp->refcount) wake_up(&qp->wait); + spin_unlock(&dev->qp_table.lock); } static int to_mthca_state(enum ib_qp_state ib_state) @@ -833,10 +835,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) * entries and reinitialize the QP. */ if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) { - mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); if (qp->ibqp.send_cq != qp->ibqp.recv_cq) - mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); mthca_wq_init(&qp->sq); @@ -1096,7 +1098,7 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, int ret; int i; - atomic_set(&qp->refcount, 1); + qp->refcount = 1; init_waitqueue_head(&qp->wait); qp->state = IB_QPS_RESET; qp->atomic_rd_en = 0; @@ -1318,6 +1320,17 @@ int mthca_alloc_sqp(struct mthca_dev *dev, return err; } +static inline int get_qp_refcount(struct mthca_dev *dev, struct mthca_qp *qp) +{ + int c; + + spin_lock_irq(&dev->qp_table.lock); + c = qp->refcount; + spin_unlock_irq(&dev->qp_table.lock); + + return c; +} + void mthca_free_qp(struct mthca_dev *dev, struct mthca_qp *qp) { @@ -1339,14 +1352,14 @@ void mthca_free_qp(struct mthca_dev *dev, spin_lock(&dev->qp_table.lock); mthca_array_clear(&dev->qp_table.qp, qp->qpn & (dev->limits.num_qps - 1)); + --qp->refcount; spin_unlock(&dev->qp_table.lock); if (send_cq != recv_cq) spin_unlock(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); - atomic_dec(&qp->refcount); - wait_event(qp->wait, !atomic_read(&qp->refcount)); + wait_event(qp->wait, !get_qp_refcount(dev, qp)); if (qp->state != IB_QPS_RESET) mthca_MODIFY_QP(dev, qp->state, IB_QPS_RESET, qp->qpn, 0, @@ -1358,10 +1371,10 @@ void mthca_free_qp(struct mthca_dev *dev, * unref the mem-free tables and free the QPN in our table. */ if (!qp->ibqp.uobject) { - mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); if (qp->ibqp.send_cq != qp->ibqp.recv_cq) - mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); mthca_free_memfree(dev, qp); diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index adcaf85355ae..1ea433291fa7 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -241,7 +241,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, goto err_out_mailbox; spin_lock_init(&srq->lock); - atomic_set(&srq->refcount, 1); + srq->refcount = 1; init_waitqueue_head(&srq->wait); if (mthca_is_memfree(dev)) @@ -308,6 +308,17 @@ err_out: return err; } +static inline int get_srq_refcount(struct mthca_dev *dev, struct mthca_srq *srq) +{ + int c; + + spin_lock_irq(&dev->srq_table.lock); + c = srq->refcount; + spin_unlock_irq(&dev->srq_table.lock); + + return c; +} + void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) { struct mthca_mailbox *mailbox; @@ -329,10 +340,10 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) spin_lock_irq(&dev->srq_table.lock); mthca_array_clear(&dev->srq_table.srq, srq->srqn & (dev->limits.num_srqs - 1)); + --srq->refcount; spin_unlock_irq(&dev->srq_table.lock); - atomic_dec(&srq->refcount); - wait_event(srq->wait, !atomic_read(&srq->refcount)); + wait_event(srq->wait, !get_srq_refcount(dev, srq)); if (!srq->ibsrq.uobject) { mthca_free_srq_buf(dev, srq); @@ -414,7 +425,7 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn, spin_lock(&dev->srq_table.lock); srq = mthca_array_get(&dev->srq_table.srq, srqn & (dev->limits.num_srqs - 1)); if (srq) - atomic_inc(&srq->refcount); + ++srq->refcount; spin_unlock(&dev->srq_table.lock); if (!srq) { @@ -431,8 +442,10 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn, srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context); out: - if (atomic_dec_and_test(&srq->refcount)) + spin_lock(&dev->srq_table.lock); + if (!--srq->refcount) wake_up(&srq->wait); + spin_unlock(&dev->srq_table.lock); } /* -- cgit v1.2.2 From 6f9c2963888e60e46a9e0bd09a25740abce29262 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Apr 2006 22:50:32 +0200 Subject: [PATCH] scx200_acb: Fix return on init error The scx200_acb driver shouldn't return failure after initialization if it successfully registered at least one i2c_adapter, else we are leaking resources. The driver was OK in that respect up to 2.6.16, a recent change broke it. This is part of the fix to bug #6445. Signed-off-by: Jean Delvare Cc: Ben Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/scx200_acb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 8bd305e47f0d..f2dae6831142 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -524,6 +524,9 @@ static int __init scx200_acb_init(void) } else if (pci_dev_present(divil_pci)) rc = scx200_add_cs553x(); + /* If at least one bus was created, init must succeed */ + if (scx200_acb_list) + return 0; return rc; } -- cgit v1.2.2 From b33d0798e6cfae1fcee75afc808fe5690a48a814 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Apr 2006 23:00:16 +0200 Subject: [PATCH] scx200_acb: Fix resource name use after free We can't pass a string on the stack to request_region. As soon as we leave the function that stack is gone and the string is lost. Let's use the same string we identify the i2c_adapter with instead, it's more simple, more consistent, and just works. This is the second half of fix to bug #6445. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/scx200_acb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index f2dae6831142..42e4e00d6c32 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -415,7 +415,6 @@ static int __init scx200_acb_create(const char *text, int base, int index) struct scx200_acb_iface *iface; struct i2c_adapter *adapter; int rc; - char description[64]; iface = kzalloc(sizeof(*iface), GFP_KERNEL); if (!iface) { @@ -434,10 +433,7 @@ static int __init scx200_acb_create(const char *text, int base, int index) mutex_init(&iface->mutex); - snprintf(description, sizeof(description), "%s ACCESS.bus [%s]", - text, adapter->name); - - if (request_region(base, 8, description) == 0) { + if (!request_region(base, 8, adapter->name)) { printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", base, base + 8-1); rc = -EBUSY; -- cgit v1.2.2 From 95563d343fec8d3e2f667c95230ac4ab7674b757 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 28 Apr 2006 22:53:30 +0200 Subject: [PATCH] scx200_acb: Fix for the CS5535 errata This is a fix for the CS5535 errata 111: When the SMBus controller tries to access a non-existing device, it sets the NEGACK bit, SMBus I/O offset 01h[4], to 1 after it detects no acknowledge at the ninth clock. The specification states that the bit can be cleared by writing a 1 to it, but under certain circumstances it is possible for this bit to not clear. Writing a 0 to the bit resets the internal state machine and clears the issue. Since all writable bits in ACBST are W1C bits (write-one-to-clear) the second write doesn't affect any other logic except the buggy NEGACK state machine. The second write clears an internal register which is responsible for "overwriting" the NEGACK bit in ACBST. Signed-off-by: Jordan Crouse Signed-off-by: Andrew Morton Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/scx200_acb.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 42e4e00d6c32..a140e4536a4e 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -133,6 +133,9 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); outb(ACBST_STASTR | ACBST_NEGACK, ACBST); + + /* Reset the status register */ + outb(0, ACBST); return; } @@ -228,6 +231,10 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface) timeout = jiffies + POLL_TIMEOUT; while (time_before(jiffies, timeout)) { status = inb(ACBST); + + /* Reset the status register to avoid the hang */ + outb(0, ACBST); + if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) { scx200_acb_machine(iface, status); return; -- cgit v1.2.2 From d94c77b9b55f2c868ffd63cbd1f9749755c4b3d0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 May 2006 15:26:11 -0700 Subject: [IRDA]: smsc-ircc: Minimal hotplug support. Minimal PNP hotplug support for the smsc-ircc2 driver. A modular driver will be modprobed via hotplug, but still bypasses driver model probing. Signed-off-by: David Brownell Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/smsc-ircc2.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 58f76cefbc83..a4674044bd6f 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -358,6 +359,16 @@ static inline void register_bank(int iobase, int bank) iobase + IRCC_MASTER); } +#ifdef CONFIG_PNP +/* PNP hotplug support */ +static const struct pnp_device_id smsc_ircc_pnp_table[] = { + { .id = "SMCf010", .driver_data = 0 }, + /* and presumably others */ + { } +}; +MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table); +#endif + /******************************************************************************* * @@ -2072,7 +2083,8 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) /* PROBING * - * + * REVISIT we can be told about the device by PNP, and should use that info + * instead of probing hardware and creating a platform_device ... */ static int __init smsc_ircc_look_for_chips(void) -- cgit v1.2.2 From 788252e6616afc75098397cc6b0bcb5482ad07ac Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 May 2006 15:27:04 -0700 Subject: [IRDA]: Switching to a workqueue for the SIR work Since sir_kthread.c pretty much duplicates the workqueue functionality, we'd better switch. The SIR fsm has been merged into sir_dev.c and thus sir_kthread.c is deleted. Signed-off-by: Christoph Hellwig Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/Makefile | 2 +- drivers/net/irda/sir-dev.h | 13 +- drivers/net/irda/sir_dev.c | 315 ++++++++++++++++++++++++- drivers/net/irda/sir_kthread.c | 508 ----------------------------------------- 4 files changed, 314 insertions(+), 524 deletions(-) delete mode 100644 drivers/net/irda/sir_kthread.c (limited to 'drivers') diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 27ab75f20799..c1ce2398efea 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -46,4 +46,4 @@ obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o # The SIR helper module -sir-dev-objs := sir_dev.o sir_dongle.o sir_kthread.o +sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h index f69fb4cec76f..9fa294a546d6 100644 --- a/drivers/net/irda/sir-dev.h +++ b/drivers/net/irda/sir-dev.h @@ -15,23 +15,14 @@ #define IRDA_SIR_H #include +#include #include #include // iobuff_t -/* FIXME: unify irda_request with sir_fsm! */ - -struct irda_request { - struct list_head lh_request; - unsigned long pending; - void (*func)(void *); - void *data; - struct timer_list timer; -}; - struct sir_fsm { struct semaphore sem; - struct irda_request rq; + struct work_struct work; unsigned state, substate; int param; int result; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index ea7c9464d46a..3b5854d10c17 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -23,6 +23,298 @@ #include "sir-dev.h" + +static struct workqueue_struct *irda_sir_wq; + +/* STATE MACHINE */ + +/* substate handler of the config-fsm to handle the cases where we want + * to wait for transmit completion before changing the port configuration + */ + +static int sirdev_tx_complete_fsm(struct sir_dev *dev) +{ + struct sir_fsm *fsm = &dev->fsm; + unsigned next_state, delay; + unsigned bytes_left; + + do { + next_state = fsm->substate; /* default: stay in current substate */ + delay = 0; + + switch(fsm->substate) { + + case SIRDEV_STATE_WAIT_XMIT: + if (dev->drv->chars_in_buffer) + bytes_left = dev->drv->chars_in_buffer(dev); + else + bytes_left = 0; + if (!bytes_left) { + next_state = SIRDEV_STATE_WAIT_UNTIL_SENT; + break; + } + + if (dev->speed > 115200) + delay = (bytes_left*8*10000) / (dev->speed/100); + else if (dev->speed > 0) + delay = (bytes_left*10*10000) / (dev->speed/100); + else + delay = 0; + /* expected delay (usec) until remaining bytes are sent */ + if (delay < 100) { + udelay(delay); + delay = 0; + break; + } + /* sleep some longer delay (msec) */ + delay = (delay+999) / 1000; + break; + + case SIRDEV_STATE_WAIT_UNTIL_SENT: + /* block until underlaying hardware buffer are empty */ + if (dev->drv->wait_until_sent) + dev->drv->wait_until_sent(dev); + next_state = SIRDEV_STATE_TX_DONE; + break; + + case SIRDEV_STATE_TX_DONE: + return 0; + + default: + IRDA_ERROR("%s - undefined state\n", __FUNCTION__); + return -EINVAL; + } + fsm->substate = next_state; + } while (delay == 0); + return delay; +} + +/* + * Function sirdev_config_fsm + * + * State machine to handle the configuration of the device (and attached dongle, if any). + * This handler is scheduled for execution in kIrDAd context, so we can sleep. + * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too + * long. Instead, for longer delays we start a timer to reschedule us later. + * On entry, fsm->sem is always locked and the netdev xmit queue stopped. + * Both must be unlocked/restarted on completion - but only on final exit. + */ + +static void sirdev_config_fsm(void *data) +{ + struct sir_dev *dev = data; + struct sir_fsm *fsm = &dev->fsm; + int next_state; + int ret = -1; + unsigned delay; + + IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); + + do { + IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n", + __FUNCTION__, fsm->state, fsm->substate); + + next_state = fsm->state; + delay = 0; + + switch(fsm->state) { + + case SIRDEV_STATE_DONGLE_OPEN: + if (dev->dongle_drv != NULL) { + ret = sirdev_put_dongle(dev); + if (ret) { + fsm->result = -EINVAL; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + + /* Initialize dongle */ + ret = sirdev_get_dongle(dev, fsm->param); + if (ret) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + + /* Dongles are powered through the modem control lines which + * were just set during open. Before resetting, let's wait for + * the power to stabilize. This is what some dongle drivers did + * in open before, while others didn't - should be safe anyway. + */ + + delay = 50; + fsm->substate = SIRDEV_STATE_DONGLE_RESET; + next_state = SIRDEV_STATE_DONGLE_RESET; + + fsm->param = 9600; + + break; + + case SIRDEV_STATE_DONGLE_CLOSE: + /* shouldn't we just treat this as success=? */ + if (dev->dongle_drv == NULL) { + fsm->result = -EINVAL; + next_state = SIRDEV_STATE_ERROR; + break; + } + + ret = sirdev_put_dongle(dev); + if (ret) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_SET_DTR_RTS: + ret = sirdev_set_dtr_rts(dev, + (fsm->param&0x02) ? TRUE : FALSE, + (fsm->param&0x01) ? TRUE : FALSE); + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_SET_SPEED: + fsm->substate = SIRDEV_STATE_WAIT_XMIT; + next_state = SIRDEV_STATE_DONGLE_CHECK; + break; + + case SIRDEV_STATE_DONGLE_CHECK: + ret = sirdev_tx_complete_fsm(dev); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + if ((delay=ret) != 0) + break; + + if (dev->dongle_drv) { + fsm->substate = SIRDEV_STATE_DONGLE_RESET; + next_state = SIRDEV_STATE_DONGLE_RESET; + } + else { + dev->speed = fsm->param; + next_state = SIRDEV_STATE_PORT_SPEED; + } + break; + + case SIRDEV_STATE_DONGLE_RESET: + if (dev->dongle_drv->reset) { + ret = dev->dongle_drv->reset(dev); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + else + ret = 0; + if ((delay=ret) == 0) { + /* set serial port according to dongle default speed */ + if (dev->drv->set_speed) + dev->drv->set_speed(dev, dev->speed); + fsm->substate = SIRDEV_STATE_DONGLE_SPEED; + next_state = SIRDEV_STATE_DONGLE_SPEED; + } + break; + + case SIRDEV_STATE_DONGLE_SPEED: + if (dev->dongle_drv->reset) { + ret = dev->dongle_drv->set_speed(dev, fsm->param); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + else + ret = 0; + if ((delay=ret) == 0) + next_state = SIRDEV_STATE_PORT_SPEED; + break; + + case SIRDEV_STATE_PORT_SPEED: + /* Finally we are ready to change the serial port speed */ + if (dev->drv->set_speed) + dev->drv->set_speed(dev, dev->speed); + dev->new_speed = 0; + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_DONE: + /* Signal network layer so it can send more frames */ + netif_wake_queue(dev->netdev); + next_state = SIRDEV_STATE_COMPLETE; + break; + + default: + IRDA_ERROR("%s - undefined state\n", __FUNCTION__); + fsm->result = -EINVAL; + /* fall thru */ + + case SIRDEV_STATE_ERROR: + IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result); + +#if 0 /* don't enable this before we have netdev->tx_timeout to recover */ + netif_stop_queue(dev->netdev); +#else + netif_wake_queue(dev->netdev); +#endif + /* fall thru */ + + case SIRDEV_STATE_COMPLETE: + /* config change finished, so we are not busy any longer */ + sirdev_enable_rx(dev); + up(&fsm->sem); + return; + } + fsm->state = next_state; + } while(!delay); + + queue_delayed_work(irda_sir_wq, &fsm->work, msecs_to_jiffies(delay)); +} + +/* schedule some device configuration task for execution by kIrDAd + * on behalf of the above state machine. + * can be called from process or interrupt/tasklet context. + */ + +int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param) +{ + struct sir_fsm *fsm = &dev->fsm; + + IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); + + if (down_trylock(&fsm->sem)) { + if (in_interrupt() || in_atomic() || irqs_disabled()) { + IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__); + return -EWOULDBLOCK; + } else + down(&fsm->sem); + } + + if (fsm->state == SIRDEV_STATE_DEAD) { + /* race with sirdev_close should never happen */ + IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__); + up(&fsm->sem); + return -ESTALE; /* or better EPIPE? */ + } + + netif_stop_queue(dev->netdev); + atomic_set(&dev->enable_rx, 0); + + fsm->state = initial_state; + fsm->param = param; + fsm->result = 0; + + INIT_WORK(&fsm->work, sirdev_config_fsm, dev); + queue_work(irda_sir_wq, &fsm->work); + return 0; +} + + /***************************************************************************/ void sirdev_enable_rx(struct sir_dev *dev) @@ -619,10 +911,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n spin_lock_init(&dev->tx_lock); init_MUTEX(&dev->fsm.sem); - INIT_LIST_HEAD(&dev->fsm.rq.lh_request); - dev->fsm.rq.pending = 0; - init_timer(&dev->fsm.rq.timer); - dev->drv = drv; dev->netdev = ndev; @@ -682,3 +970,22 @@ int sirdev_put_instance(struct sir_dev *dev) } EXPORT_SYMBOL(sirdev_put_instance); +static int __init sir_wq_init(void) +{ + irda_sir_wq = create_singlethread_workqueue("irda_sir_wq"); + if (!irda_sir_wq) + return -ENOMEM; + return 0; +} + +static void __exit sir_wq_exit(void) +{ + destroy_workqueue(irda_sir_wq); +} + +module_init(sir_wq_init); +module_exit(sir_wq_exit); + +MODULE_AUTHOR("Martin Diehl "); +MODULE_DESCRIPTION("IrDA SIR core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c deleted file mode 100644 index e3904d6bfecd..000000000000 --- a/drivers/net/irda/sir_kthread.c +++ /dev/null @@ -1,508 +0,0 @@ -/********************************************************************* - * - * sir_kthread.c: dedicated thread to process scheduled - * sir device setup requests - * - * Copyright (c) 2002 Martin Diehl - * - * 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 of - * the License, or (at your option) any later version. - * - ********************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sir-dev.h" - -/************************************************************************** - * - * kIrDAd kernel thread and config state machine - * - */ - -struct irda_request_queue { - struct list_head request_list; - spinlock_t lock; - task_t *thread; - struct completion exit; - wait_queue_head_t kick, done; - atomic_t num_pending; -}; - -static struct irda_request_queue irda_rq_queue; - -static int irda_queue_request(struct irda_request *rq) -{ - int ret = 0; - unsigned long flags; - - if (!test_and_set_bit(0, &rq->pending)) { - spin_lock_irqsave(&irda_rq_queue.lock, flags); - list_add_tail(&rq->lh_request, &irda_rq_queue.request_list); - wake_up(&irda_rq_queue.kick); - atomic_inc(&irda_rq_queue.num_pending); - spin_unlock_irqrestore(&irda_rq_queue.lock, flags); - ret = 1; - } - return ret; -} - -static void irda_request_timer(unsigned long data) -{ - struct irda_request *rq = (struct irda_request *)data; - unsigned long flags; - - spin_lock_irqsave(&irda_rq_queue.lock, flags); - list_add_tail(&rq->lh_request, &irda_rq_queue.request_list); - wake_up(&irda_rq_queue.kick); - spin_unlock_irqrestore(&irda_rq_queue.lock, flags); -} - -static int irda_queue_delayed_request(struct irda_request *rq, unsigned long delay) -{ - int ret = 0; - struct timer_list *timer = &rq->timer; - - if (!test_and_set_bit(0, &rq->pending)) { - timer->expires = jiffies + delay; - timer->function = irda_request_timer; - timer->data = (unsigned long)rq; - atomic_inc(&irda_rq_queue.num_pending); - add_timer(timer); - ret = 1; - } - return ret; -} - -static void run_irda_queue(void) -{ - unsigned long flags; - struct list_head *entry, *tmp; - struct irda_request *rq; - - spin_lock_irqsave(&irda_rq_queue.lock, flags); - list_for_each_safe(entry, tmp, &irda_rq_queue.request_list) { - rq = list_entry(entry, struct irda_request, lh_request); - list_del_init(entry); - spin_unlock_irqrestore(&irda_rq_queue.lock, flags); - - clear_bit(0, &rq->pending); - rq->func(rq->data); - - if (atomic_dec_and_test(&irda_rq_queue.num_pending)) - wake_up(&irda_rq_queue.done); - - spin_lock_irqsave(&irda_rq_queue.lock, flags); - } - spin_unlock_irqrestore(&irda_rq_queue.lock, flags); -} - -static int irda_thread(void *startup) -{ - DECLARE_WAITQUEUE(wait, current); - - daemonize("kIrDAd"); - - irda_rq_queue.thread = current; - - complete((struct completion *)startup); - - while (irda_rq_queue.thread != NULL) { - - /* We use TASK_INTERRUPTIBLE, rather than - * TASK_UNINTERRUPTIBLE. Andrew Morton made this - * change ; he told me that it is safe, because "signal - * blocking is now handled in daemonize()", he added - * that the problem is that "uninterruptible sleep - * contributes to load average", making user worry. - * Jean II */ - set_task_state(current, TASK_INTERRUPTIBLE); - add_wait_queue(&irda_rq_queue.kick, &wait); - if (list_empty(&irda_rq_queue.request_list)) - schedule(); - else - __set_task_state(current, TASK_RUNNING); - remove_wait_queue(&irda_rq_queue.kick, &wait); - - /* make swsusp happy with our thread */ - try_to_freeze(); - - run_irda_queue(); - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,35) - reparent_to_init(); -#endif - complete_and_exit(&irda_rq_queue.exit, 0); - /* never reached */ - return 0; -} - - -static void flush_irda_queue(void) -{ - if (atomic_read(&irda_rq_queue.num_pending)) { - - DECLARE_WAITQUEUE(wait, current); - - if (!list_empty(&irda_rq_queue.request_list)) - run_irda_queue(); - - set_task_state(current, TASK_UNINTERRUPTIBLE); - add_wait_queue(&irda_rq_queue.done, &wait); - if (atomic_read(&irda_rq_queue.num_pending)) - schedule(); - else - __set_task_state(current, TASK_RUNNING); - remove_wait_queue(&irda_rq_queue.done, &wait); - } -} - -/* substate handler of the config-fsm to handle the cases where we want - * to wait for transmit completion before changing the port configuration - */ - -static int irda_tx_complete_fsm(struct sir_dev *dev) -{ - struct sir_fsm *fsm = &dev->fsm; - unsigned next_state, delay; - unsigned bytes_left; - - do { - next_state = fsm->substate; /* default: stay in current substate */ - delay = 0; - - switch(fsm->substate) { - - case SIRDEV_STATE_WAIT_XMIT: - if (dev->drv->chars_in_buffer) - bytes_left = dev->drv->chars_in_buffer(dev); - else - bytes_left = 0; - if (!bytes_left) { - next_state = SIRDEV_STATE_WAIT_UNTIL_SENT; - break; - } - - if (dev->speed > 115200) - delay = (bytes_left*8*10000) / (dev->speed/100); - else if (dev->speed > 0) - delay = (bytes_left*10*10000) / (dev->speed/100); - else - delay = 0; - /* expected delay (usec) until remaining bytes are sent */ - if (delay < 100) { - udelay(delay); - delay = 0; - break; - } - /* sleep some longer delay (msec) */ - delay = (delay+999) / 1000; - break; - - case SIRDEV_STATE_WAIT_UNTIL_SENT: - /* block until underlaying hardware buffer are empty */ - if (dev->drv->wait_until_sent) - dev->drv->wait_until_sent(dev); - next_state = SIRDEV_STATE_TX_DONE; - break; - - case SIRDEV_STATE_TX_DONE: - return 0; - - default: - IRDA_ERROR("%s - undefined state\n", __FUNCTION__); - return -EINVAL; - } - fsm->substate = next_state; - } while (delay == 0); - return delay; -} - -/* - * Function irda_config_fsm - * - * State machine to handle the configuration of the device (and attached dongle, if any). - * This handler is scheduled for execution in kIrDAd context, so we can sleep. - * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too - * long. Instead, for longer delays we start a timer to reschedule us later. - * On entry, fsm->sem is always locked and the netdev xmit queue stopped. - * Both must be unlocked/restarted on completion - but only on final exit. - */ - -static void irda_config_fsm(void *data) -{ - struct sir_dev *dev = data; - struct sir_fsm *fsm = &dev->fsm; - int next_state; - int ret = -1; - unsigned delay; - - IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); - - do { - IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n", - __FUNCTION__, fsm->state, fsm->substate); - - next_state = fsm->state; - delay = 0; - - switch(fsm->state) { - - case SIRDEV_STATE_DONGLE_OPEN: - if (dev->dongle_drv != NULL) { - ret = sirdev_put_dongle(dev); - if (ret) { - fsm->result = -EINVAL; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - - /* Initialize dongle */ - ret = sirdev_get_dongle(dev, fsm->param); - if (ret) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - - /* Dongles are powered through the modem control lines which - * were just set during open. Before resetting, let's wait for - * the power to stabilize. This is what some dongle drivers did - * in open before, while others didn't - should be safe anyway. - */ - - delay = 50; - fsm->substate = SIRDEV_STATE_DONGLE_RESET; - next_state = SIRDEV_STATE_DONGLE_RESET; - - fsm->param = 9600; - - break; - - case SIRDEV_STATE_DONGLE_CLOSE: - /* shouldn't we just treat this as success=? */ - if (dev->dongle_drv == NULL) { - fsm->result = -EINVAL; - next_state = SIRDEV_STATE_ERROR; - break; - } - - ret = sirdev_put_dongle(dev); - if (ret) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_SET_DTR_RTS: - ret = sirdev_set_dtr_rts(dev, - (fsm->param&0x02) ? TRUE : FALSE, - (fsm->param&0x01) ? TRUE : FALSE); - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_SET_SPEED: - fsm->substate = SIRDEV_STATE_WAIT_XMIT; - next_state = SIRDEV_STATE_DONGLE_CHECK; - break; - - case SIRDEV_STATE_DONGLE_CHECK: - ret = irda_tx_complete_fsm(dev); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - if ((delay=ret) != 0) - break; - - if (dev->dongle_drv) { - fsm->substate = SIRDEV_STATE_DONGLE_RESET; - next_state = SIRDEV_STATE_DONGLE_RESET; - } - else { - dev->speed = fsm->param; - next_state = SIRDEV_STATE_PORT_SPEED; - } - break; - - case SIRDEV_STATE_DONGLE_RESET: - if (dev->dongle_drv->reset) { - ret = dev->dongle_drv->reset(dev); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - else - ret = 0; - if ((delay=ret) == 0) { - /* set serial port according to dongle default speed */ - if (dev->drv->set_speed) - dev->drv->set_speed(dev, dev->speed); - fsm->substate = SIRDEV_STATE_DONGLE_SPEED; - next_state = SIRDEV_STATE_DONGLE_SPEED; - } - break; - - case SIRDEV_STATE_DONGLE_SPEED: - if (dev->dongle_drv->reset) { - ret = dev->dongle_drv->set_speed(dev, fsm->param); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - else - ret = 0; - if ((delay=ret) == 0) - next_state = SIRDEV_STATE_PORT_SPEED; - break; - - case SIRDEV_STATE_PORT_SPEED: - /* Finally we are ready to change the serial port speed */ - if (dev->drv->set_speed) - dev->drv->set_speed(dev, dev->speed); - dev->new_speed = 0; - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_DONE: - /* Signal network layer so it can send more frames */ - netif_wake_queue(dev->netdev); - next_state = SIRDEV_STATE_COMPLETE; - break; - - default: - IRDA_ERROR("%s - undefined state\n", __FUNCTION__); - fsm->result = -EINVAL; - /* fall thru */ - - case SIRDEV_STATE_ERROR: - IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result); - -#if 0 /* don't enable this before we have netdev->tx_timeout to recover */ - netif_stop_queue(dev->netdev); -#else - netif_wake_queue(dev->netdev); -#endif - /* fall thru */ - - case SIRDEV_STATE_COMPLETE: - /* config change finished, so we are not busy any longer */ - sirdev_enable_rx(dev); - up(&fsm->sem); - return; - } - fsm->state = next_state; - } while(!delay); - - irda_queue_delayed_request(&fsm->rq, msecs_to_jiffies(delay)); -} - -/* schedule some device configuration task for execution by kIrDAd - * on behalf of the above state machine. - * can be called from process or interrupt/tasklet context. - */ - -int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param) -{ - struct sir_fsm *fsm = &dev->fsm; - int xmit_was_down; - - IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); - - if (down_trylock(&fsm->sem)) { - if (in_interrupt() || in_atomic() || irqs_disabled()) { - IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__); - return -EWOULDBLOCK; - } else - down(&fsm->sem); - } - - if (fsm->state == SIRDEV_STATE_DEAD) { - /* race with sirdev_close should never happen */ - IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__); - up(&fsm->sem); - return -ESTALE; /* or better EPIPE? */ - } - - xmit_was_down = netif_queue_stopped(dev->netdev); - netif_stop_queue(dev->netdev); - atomic_set(&dev->enable_rx, 0); - - fsm->state = initial_state; - fsm->param = param; - fsm->result = 0; - - INIT_LIST_HEAD(&fsm->rq.lh_request); - fsm->rq.pending = 0; - fsm->rq.func = irda_config_fsm; - fsm->rq.data = dev; - - if (!irda_queue_request(&fsm->rq)) { /* returns 0 on error! */ - atomic_set(&dev->enable_rx, 1); - if (!xmit_was_down) - netif_wake_queue(dev->netdev); - up(&fsm->sem); - return -EAGAIN; - } - return 0; -} - -static int __init irda_thread_create(void) -{ - struct completion startup; - int pid; - - spin_lock_init(&irda_rq_queue.lock); - irda_rq_queue.thread = NULL; - INIT_LIST_HEAD(&irda_rq_queue.request_list); - init_waitqueue_head(&irda_rq_queue.kick); - init_waitqueue_head(&irda_rq_queue.done); - atomic_set(&irda_rq_queue.num_pending, 0); - - init_completion(&startup); - pid = kernel_thread(irda_thread, &startup, CLONE_FS|CLONE_FILES); - if (pid <= 0) - return -EAGAIN; - else - wait_for_completion(&startup); - - return 0; -} - -static void __exit irda_thread_join(void) -{ - if (irda_rq_queue.thread) { - flush_irda_queue(); - init_completion(&irda_rq_queue.exit); - irda_rq_queue.thread = NULL; - wake_up(&irda_rq_queue.kick); - wait_for_completion(&irda_rq_queue.exit); - } -} - -module_init(irda_thread_create); -module_exit(irda_thread_join); - -MODULE_AUTHOR("Martin Diehl "); -MODULE_DESCRIPTION("IrDA SIR core"); -MODULE_LICENSE("GPL"); - -- cgit v1.2.2 From 5941d079f2c3bdf0dffed1afb8941678fcd0bcb7 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 May 2006 22:54:59 -0700 Subject: IPoIB: Free child interfaces properly When deleting a child interface with a non-default P_Key via /sys/class/net/ibX/delete_child, the interface must be freed with free_netdev() (rather than kfree() on the private data). Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 4ca175553f9f..f887780e8093 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -158,10 +158,8 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) if (priv->pkey == pkey) { unregister_netdev(priv->dev); ipoib_dev_cleanup(priv->dev); - list_del(&priv->list); - - kfree(priv); + free_netdev(priv->dev); ret = 0; break; -- cgit v1.2.2 From a50bb7b9af9a7c39b2aba15678eb686ae428718c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 May 2006 23:14:35 -0700 Subject: [TG3]: Fix possible NULL deref in tg3_run_loopback(). tg3_run_loopback doesn't check that dev_alloc_skb() returns anything useful. Even if dev_alloc_skb() fails to return an skb to us we'll happily go on and assume it did, so we risk dereferencing a NULL pointer. Much better to fail gracefully by returning -ENOMEM than crashing here. Signed-off-by: Jesper Juhl Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index beeb612be98f..2bd9592b75cd 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8454,6 +8454,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) tx_len = 1514; skb = dev_alloc_skb(tx_len); + if (!skb) + return -ENOMEM; + tx_data = skb_put(skb, tx_len); memcpy(tx_data, tp->dev->dev_addr, 6); memset(tx_data + 6, 0x0, 8); -- cgit v1.2.2 From 6dd727da92290193d0f74fa39f3ad53f423524db Mon Sep 17 00:00:00 2001 From: "mdr@sgi.com" Date: Mon, 1 May 2006 13:07:04 -0500 Subject: [SCSI] mptfc: race between mptfc_register_dev and mptfc_target_alloc A race condition exists in mptfc between the thread registering a device with the fc transport and the scan work generated by the transport. This race existed prior to the application of the mptfc bug fix patch. mptfc_register_dev() calls fc_remote_port_add() with the FC_RPORT_ROLE_TARGET bit set in the rport ids passed to the function. Having this bit set causes fc_remote_port_add() to schedule a scan of the device. This scan can execute before mptfc_register_dev() can fill in the dd_data in the rport structure. When this happens, mptfc_target_alloc() will fail because dd_data is null. Attached is a patch which fixes the problem. The patch changes the rport ids passed to fc_remote_port_add() to not have the TARGET bit set. This prevents the scan from being scheduled. After mptfc_register_dev() fills in the rport dd_data field, fc_remote_port_rolechg() is called, changing the role of the rport to TARGET. Thus, the scan is scheduled after dd_data is filled in which prevents the failure in mptfc_target_alloc(). Signed-off-by: Michael Reed Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptfc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index e1fb5a166366..856487741ef4 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid) rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low; rid->port_id = pg0->PortIdentifier; rid->roles = FC_RPORT_ROLE_UNKNOWN; - rid->roles |= FC_RPORT_ROLE_FCP_TARGET; - if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR) - rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR; return 0; } @@ -357,10 +354,15 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) int new_ri = 1; u64 pn, nn; VirtTarget *vtarget; + u32 roles = FC_RPORT_ROLE_UNKNOWN; if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) return; + roles |= FC_RPORT_ROLE_FCP_TARGET; + if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR) + roles |= FC_RPORT_ROLE_FCP_INITIATOR; + /* scan list looking for a match */ list_for_each_entry(ri, &ioc->fc_rports, list) { pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; @@ -400,8 +402,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) vtarget->bus_id = pg0->CurrentBus; } } - /* once dd_data is filled in, commands will issue to hardware */ *((struct mptfc_rport_info **)rport->dd_data) = ri; + /* scan will be scheduled once rport becomes a target */ + fc_remote_port_rolechg(rport,roles); pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; -- cgit v1.2.2 From 7fc5b1e3a170d865f625e609c087cf8d84fd285d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 10 May 2006 13:28:52 +0200 Subject: [Cardman 40x0] Fix udev device creation This patch corrects the order of the calls to register_chrdev() and pcmcia_register_driver(). Now udev correctly creates userspace device files /dev/cmmN and /dev/cmxN respectively. Based on an earlier patch by Jan Niehusmann . Signed-off-by: Harald Welte Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/cm4000_cs.c | 10 ++++++---- drivers/char/pcmcia/cm4040_cs.c | 11 +++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 02114a0bd0d9..128b2632512d 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1981,10 +1981,6 @@ static int __init cmm_init(void) if (!cmm_class) return -1; - rc = pcmcia_register_driver(&cm4000_driver); - if (rc < 0) - return rc; - major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME @@ -1992,6 +1988,12 @@ static int __init cmm_init(void) return -1; } + rc = pcmcia_register_driver(&cm4000_driver); + if (rc < 0) { + unregister_chrdev(major, DEVICE_NAME); + return rc; + } + return 0; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 29efa64580a8..47a8465bf95b 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -724,16 +724,19 @@ static int __init cm4040_init(void) if (!cmx_class) return -1; - rc = pcmcia_register_driver(&reader_driver); - if (rc < 0) - return rc; - major = register_chrdev(0, DEVICE_NAME, &reader_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); return -1; } + + rc = pcmcia_register_driver(&reader_driver); + if (rc < 0) { + unregister_chrdev(major, DEVICE_NAME); + return rc; + } + return 0; } -- cgit v1.2.2 From f4ea431bb7c4856b930eafca6eb1fb474dae9b40 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 May 2006 14:46:54 -0700 Subject: sky2: ifdown kills irq mask Bringing down a port also masks off the status and other IRQ's needed for device to function due to missing paren's. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 227df9876a2c..27da9b75dedc 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -122,6 +122,7 @@ MODULE_DEVICE_TABLE(pci, sky2_id_table); /* Avoid conditionals by using array */ static const unsigned txqaddr[] = { Q_XA1, Q_XA2 }; static const unsigned rxqaddr[] = { Q_R1, Q_R2 }; +static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 }; /* This driver supports yukon2 chipset only */ static const char *yukon2_name[] = { @@ -1050,7 +1051,7 @@ static int sky2_up(struct net_device *dev) /* Enable interrupts from phy/mac for port */ imask = sky2_read32(hw, B0_IMSK); - imask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; + imask |= portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); return 0; @@ -1401,7 +1402,7 @@ static int sky2_down(struct net_device *dev) /* Disable port IRQ */ imask = sky2_read32(hw, B0_IMSK); - imask &= ~(sky2->port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; + imask &= ~portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); /* turn off LED's */ -- cgit v1.2.2 From 64b1c2b42b555ef38c475d104f2faf3f6f93690d Mon Sep 17 00:00:00 2001 From: Herbert Valerio Riedel Date: Wed, 10 May 2006 12:12:57 -0400 Subject: phy: mdiobus_register(): initialize all phy_map entries make sure phy_map entries whose PHY address is masked are initialized to NULL, given that other code (such as mdiobus_unregister for instance) assumes that non-NULL phy_map entries are allocated phy_devices Signed-off-by: Herbert Valerio Riedel Signed-off-by: Stephen Hemminger --- drivers/net/phy/mdio_bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 459443b572ce..1b236bdf6b92 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -60,8 +60,10 @@ int mdiobus_register(struct mii_bus *bus) for (i = 0; i < PHY_MAX_ADDR; i++) { struct phy_device *phydev; - if (bus->phy_mask & (1 << i)) + if (bus->phy_mask & (1 << i)) { + bus->phy_map[i] = NULL; continue; + } phydev = get_phy_device(bus, i); -- cgit v1.2.2 From 4c1b46226ce4424a93b8ac544e37afb26c8a72c6 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Wed, 10 May 2006 12:48:57 -0700 Subject: dl2k: use DMA_48BIT_MASK constant Typo will be harder with this one. Signed-off-by: Francois Romieu Signed-off-by: Stephen Hemminger --- drivers/net/dl2k.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 1f3627470c95..1ddefd281213 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -765,7 +765,7 @@ rio_free_tx (struct net_device *dev, int irq) break; skb = np->tx_skbuff[entry]; pci_unmap_single (np->pdev, - np->tx_ring[entry].fraginfo & 0xffffffffffff, + np->tx_ring[entry].fraginfo & DMA_48BIT_MASK, skb->len, PCI_DMA_TODEVICE); if (irq) dev_kfree_skb_irq (skb); @@ -893,7 +893,7 @@ receive_packet (struct net_device *dev) /* Small skbuffs for short packets */ if (pkt_len > copy_thresh) { pci_unmap_single (np->pdev, - desc->fraginfo & 0xffffffffffff, + desc->fraginfo & DMA_48BIT_MASK, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put (skb = np->rx_skbuff[entry], pkt_len); @@ -901,7 +901,7 @@ receive_packet (struct net_device *dev) } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) { pci_dma_sync_single_for_cpu(np->pdev, desc->fraginfo & - 0xffffffffffff, + DMA_48BIT_MASK, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb->dev = dev; @@ -913,7 +913,7 @@ receive_packet (struct net_device *dev) skb_put (skb, pkt_len); pci_dma_sync_single_for_device(np->pdev, desc->fraginfo & - 0xffffffffffff, + DMA_48BIT_MASK, np->rx_buf_sz, PCI_DMA_FROMDEVICE); } @@ -1800,7 +1800,7 @@ rio_close (struct net_device *dev) skb = np->rx_skbuff[i]; if (skb) { pci_unmap_single(np->pdev, - np->rx_ring[i].fraginfo & 0xffffffffffff, + np->rx_ring[i].fraginfo & DMA_48BIT_MASK, skb->len, PCI_DMA_FROMDEVICE); dev_kfree_skb (skb); np->rx_skbuff[i] = NULL; @@ -1810,7 +1810,7 @@ rio_close (struct net_device *dev) skb = np->tx_skbuff[i]; if (skb) { pci_unmap_single(np->pdev, - np->tx_ring[i].fraginfo & 0xffffffffffff, + np->tx_ring[i].fraginfo & DMA_48BIT_MASK, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb (skb); np->tx_skbuff[i] = NULL; -- cgit v1.2.2 From d8e95e52a9db0e26b37f51ab5140b89da7c4b31e Mon Sep 17 00:00:00 2001 From: James Cameron Date: Wed, 10 May 2006 13:33:29 -0700 Subject: sis900: phy for FoxCon motherboard 661FX7MI-S motherboard which uses the SiS 661FX chipset. The patch adds an entry to mii_chip_info for the transceiver. The PHY ids were found using the sis900_c_122.diff patch from http://brownhat.org/sis900.html but that patch didn't solve the problem, because the PHY at address 1 was already being chosen. Without my patch, when bursts of packets arrive from other hosts on a LAN, the interface dropped one roughly 10% of the time, causing retransmits. There were fifth second pauses in refresh of large xterms, and it made Netrek suck. I can provide further test data. Workaround in lieu of patch is to use mii-tool to advertise 100baseTx-HD, then force renegotiation. I wasn't able to identify the actual transceiver, so the description field is a guess. This patch is similar to Artur Skawina's patch: http://marc.theaimsgroup.com/?l=linux-netdev&m=114297516729079&w=2 I'm not sure, but I wonder if it means the default behaviour should be changed, so as to better handle future transceivers. Diff is against 2.6.16.13. Signed-off-by: James Cameron Signed-off-by: Stephen Hemminger --- drivers/net/sis900.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index b82191d2bee1..f5a3bf4d959a 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -127,6 +127,7 @@ static const struct mii_chip_info { } mii_chip_table[] = { { "SiS 900 Internal MII PHY", 0x001d, 0x8000, LAN }, { "SiS 7014 Physical Layer Solution", 0x0016, 0xf830, LAN }, + { "SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, LAN }, { "Altimata AC101LF PHY", 0x0022, 0x5520, LAN }, { "ADM 7001 LAN PHY", 0x002e, 0xcc60, LAN }, { "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN }, -- cgit v1.2.2 From ce477ae4f8c75c94587c3157deffad8219db09a0 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 10 May 2006 17:58:41 +0300 Subject: IB/mthca: FMR ioremap fix Addresses for ioremap must be calculated off of pci_resource_start; we can't directly use the bus address as seen by the HCA. Fix the code that remaps device memory for FMR access. Based on patch by Klaus Smolin. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_mr.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 25e1c1db9a40..a486dec1707e 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -761,6 +761,7 @@ void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) int __devinit mthca_init_mr_table(struct mthca_dev *dev) { + unsigned long addr; int err, i; err = mthca_alloc_init(&dev->mr_table.mpt_alloc, @@ -796,9 +797,12 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev) goto err_fmr_mpt; } + addr = pci_resource_start(dev->pdev, 4) + + ((pci_resource_len(dev->pdev, 4) - 1) & + dev->mr_table.mpt_base); + dev->mr_table.tavor_fmr.mpt_base = - ioremap(dev->mr_table.mpt_base, - (1 << i) * sizeof (struct mthca_mpt_entry)); + ioremap(addr, (1 << i) * sizeof(struct mthca_mpt_entry)); if (!dev->mr_table.tavor_fmr.mpt_base) { mthca_warn(dev, "MPT ioremap for FMR failed.\n"); @@ -806,9 +810,12 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev) goto err_fmr_mpt; } + addr = pci_resource_start(dev->pdev, 4) + + ((pci_resource_len(dev->pdev, 4) - 1) & + dev->mr_table.mtt_base); + dev->mr_table.tavor_fmr.mtt_base = - ioremap(dev->mr_table.mtt_base, - (1 << i) * MTHCA_MTT_SEG_SIZE); + ioremap(addr, (1 << i) * MTHCA_MTT_SEG_SIZE); if (!dev->mr_table.tavor_fmr.mtt_base) { mthca_warn(dev, "MTT ioremap for FMR failed.\n"); err = -ENOMEM; -- cgit v1.2.2 From b68f7de02ae380ddb4e5e457e3fe945ddfd0aa08 Mon Sep 17 00:00:00 2001 From: Ken Brush Date: Mon, 8 May 2006 20:24:12 -0500 Subject: [PATCH] USB: Add Sieraa Wireless 580 evdo card to airprime.c This adds the Sierra Wireless card to airprime.c. I tested this on my laptop. Signed-off-by: Ken Brush Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index dbf1f063098c..694b205f9b73 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -18,6 +18,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit v1.2.2 From 332bbf613868a5d5938ad9fb7436b2beae72d53d Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 5 May 2006 11:07:21 +0200 Subject: [PATCH] USB: add an IBM USB keyboard to the HID_QUIRK_NOGET blacklist After recent changes, the USB keyboard as shipped with IBM pSeries systems does not work anymore, unless the keyboard is replugged after reboot. Adding this model to the blacklist fixes it. Signed-off-by: Olaf Hering Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index f419bd82ab7f..435273e7c85c 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1557,6 +1557,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_HP 0x03f0 #define USB_DEVICE_ID_HP_USBHUB_KB 0x020c +#define USB_VENDOR_ID_IBM 0x04b3 +#define USB_DEVICE_ID_IBM_USBHUB_KB 0x3005 + #define USB_VENDOR_ID_CREATIVELABS 0x062a #define USB_DEVICE_ID_CREATIVELABS_SILVERCREST 0x0201 @@ -1681,6 +1684,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET}, { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET }, { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_USBHUB_KB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_SILVERCREST, USB_DEVICE_ID_SILVERCREST_KB, HID_QUIRK_NOGET }, -- cgit v1.2.2 From 16c23f7d88cbcce491f9370b2846fad66e8ef319 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 9 May 2006 12:37:22 -0700 Subject: [PATCH] USB: Emagic USB firmware loading fixes It's become apparent as machines get faster that the emagic kernel firmware loaders (based on the ezusb loader) have a reset race. a 400MHz TiBook never tripped it, but a 2GHz Pentium M seems to hit it about 30% of the time. The bug is seen as a hung USB box and the kernel error: drivers/usb/misc/emi62.c: emi62_load_firmware - error loading firmware: error = -110 The patch below inserts a delay after deasserting reset to allow the box to settle before a new command is issued. This affects only device startup. Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/emi26.c | 4 ++++ drivers/usb/misc/emi62.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c index 3824df33094e..1fd9cb85f4ca 100644 --- a/drivers/usb/misc/emi26.c +++ b/drivers/usb/misc/emi26.c @@ -15,6 +15,7 @@ #include #include #include +#include #define MAX_INTEL_HEX_RECORD_LENGTH 16 typedef struct _INTEL_HEX_RECORD @@ -114,6 +115,7 @@ static int emi26_load_firmware (struct usb_device *dev) /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); + msleep(250); /* let device settle */ /* 2. We upload the FPGA firmware into the EMI * Note: collect up to 1023 (yes!) bytes and send them with @@ -150,6 +152,7 @@ static int emi26_load_firmware (struct usb_device *dev) goto wraperr; } } + msleep(250); /* let device settle */ /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); @@ -192,6 +195,7 @@ static int emi26_load_firmware (struct usb_device *dev) err("%s - error loading firmware: error = %d", __FUNCTION__, err); goto wraperr; } + msleep(250); /* let device settle */ /* return 1 to fail the driver inialization * and give real driver change to load */ diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c index 52fea2e08db8..fe351371f274 100644 --- a/drivers/usb/misc/emi62.c +++ b/drivers/usb/misc/emi62.c @@ -15,6 +15,7 @@ #include #include #include +#include #define MAX_INTEL_HEX_RECORD_LENGTH 16 typedef struct _INTEL_HEX_RECORD @@ -123,6 +124,7 @@ static int emi62_load_firmware (struct usb_device *dev) /* De-assert reset (let the CPU run) */ err = emi62_set_reset(dev,0); + msleep(250); /* let device settle */ /* 2. We upload the FPGA firmware into the EMI * Note: collect up to 1023 (yes!) bytes and send them with @@ -166,6 +168,7 @@ static int emi62_load_firmware (struct usb_device *dev) err("%s - error loading firmware: error = %d", __FUNCTION__, err); goto wraperr; } + msleep(250); /* let device settle */ /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ @@ -228,6 +231,7 @@ static int emi62_load_firmware (struct usb_device *dev) err("%s - error loading firmware: error = %d", __FUNCTION__, err); goto wraperr; } + msleep(250); /* let device settle */ kfree(buf); -- cgit v1.2.2 From 704936a25bda9bb12e35bb222d5e3f26186dc279 Mon Sep 17 00:00:00 2001 From: Luiz Fernando Capitulino Date: Thu, 11 May 2006 22:34:17 -0300 Subject: [PATCH] usbserial: Fixes use-after-free in serial_open(). If the device is disconnected while serial_open() is executing and either try_module_get() or the device specific open function fails, the kref_put() call in the 'bailout_kref_put' label will free the memory pointed out by 'port'. The subsequent dereferences in the 'bailout_kref_put' label will be invalid. The fix is just to assure kref_put() is called after any 'port' usage. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 071f86a59c08..d9dceb4f57b9 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -225,9 +225,9 @@ static int serial_open (struct tty_struct *tty, struct file * filp) bailout_module_put: module_put(serial->type->driver.owner); bailout_kref_put: - kref_put(&serial->kref, destroy_serial); port->open_count = 0; mutex_unlock(&port->mutex); + kref_put(&serial->kref, destroy_serial); return retval; } -- cgit v1.2.2 From 71a84163ca6b4e36744978385e94150af32f9d75 Mon Sep 17 00:00:00 2001 From: Luiz Fernando Capitulino Date: Thu, 11 May 2006 22:34:24 -0300 Subject: [PATCH] usbserial: Fixes leak in serial_open() error path. If serial_open() fails at the port assignment or mutex_lock_interruptible() is interrupted, the 'serial' object will never be freed. We should call kref_put() when those errors happens. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index d9dceb4f57b9..9c36f0ece20f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -189,11 +189,15 @@ static int serial_open (struct tty_struct *tty, struct file * filp) portNumber = tty->index - serial->minor; port = serial->port[portNumber]; - if (!port) - return -ENODEV; + if (!port) { + retval = -ENODEV; + goto bailout_kref_put; + } - if (mutex_lock_interruptible(&port->mutex)) - return -ERESTARTSYS; + if (mutex_lock_interruptible(&port->mutex)) { + retval = -ERESTARTSYS; + goto bailout_kref_put; + } ++port->open_count; @@ -209,7 +213,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) * safe because we are called with BKL held */ if (!try_module_get(serial->type->driver.owner)) { retval = -ENODEV; - goto bailout_kref_put; + goto bailout_mutex_unlock; } /* only call the device specific open if this @@ -224,9 +228,10 @@ static int serial_open (struct tty_struct *tty, struct file * filp) bailout_module_put: module_put(serial->type->driver.owner); -bailout_kref_put: +bailout_mutex_unlock: port->open_count = 0; mutex_unlock(&port->mutex); +bailout_kref_put: kref_put(&serial->kref, destroy_serial); return retval; } -- cgit v1.2.2 From 815ddc99dd8108908d14c699a37d0f5974da6def Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 12 May 2006 11:05:29 -0700 Subject: [PATCH] USB: add ark3116 usb to serial driver Based on Simon's original driver, with some minor code cleanups and tidying by me. Cc: Simon Schulz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile | 1 + drivers/usb/serial/ark3116.c | 465 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/serial/generic.c | 1 + 4 files changed, 477 insertions(+) create mode 100644 drivers/usb/serial/ark3116.c (limited to 'drivers') diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index f96b73f54bf1..5c60be521561 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -71,6 +71,16 @@ config USB_SERIAL_ANYDATA To compile this driver as a module, choose M here: the module will be called anydata. +config USB_SERIAL_ARK3116 + tristate "USB ARK Micro 3116 USB Serial Driver (EXPERIMENTAL)" + depends on USB_SERIAL && EXPERIMENTAL + help + Say Y here if you want to use a ARK Micro 3116 USB to Serial + device. + + To compile this driver as a module, choose M here: the + module will be called ark3116 + config USB_SERIAL_BELKIN tristate "USB Belkin and Peracom Single Port Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 93c21245b1af..5a0960fc9d3e 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -13,6 +13,7 @@ usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y) obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o obj-$(CONFIG_USB_SERIAL_ANYDATA) += anydata.o +obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c new file mode 100644 index 000000000000..8dec796222a0 --- /dev/null +++ b/drivers/usb/serial/ark3116.c @@ -0,0 +1,465 @@ +/* + * ark3116 + * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547, + * productid=0x0232) (used in a datacable called KQ-U8A) + * + * - based on code by krisfx -> thanks !! + * (see http://www.linuxquestions.org/questions/showthread.php?p=2184457#post2184457) + * + * - based on logs created by usbsnoopy + * + * Author : Simon Schulz [ark3116_driverauctionant.de] + * + * 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 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include "usb-serial.h" + + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x6547, 0x0232) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct ark3116_private { + spinlock_t lock; + u8 termios_initialized; +}; + +static inline void ARK3116_SND(struct usb_serial *serial, int seq, + __u8 request, __u8 requesttype, + __u16 value, __u16 index) +{ + int result; + result = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev,0), + request, requesttype, value, index, + NULL,0x00, 1000); + dbg("%03d > ok",seq); +} + +static inline void ARK3116_RCV(struct usb_serial *serial, int seq, + __u8 request, __u8 requesttype, + __u16 value, __u16 index, __u8 expected, + char *buf) +{ + int result; + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev,0), + request, requesttype, value, index, + buf, 0x0000001, 1000); + if (result) + dbg("%03d < %d bytes [0x%02X]",seq, result, buf[0]); + else + dbg("%03d < 0 bytes", seq); +} + + +static inline void ARK3116_RCV_QUIET(struct usb_serial *serial, + __u8 request, __u8 requesttype, + __u16 value, __u16 index, char *buf) +{ + usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev,0), + request, requesttype, value, index, + buf, 0x0000001, 1000); +} + + +static int ark3116_attach(struct usb_serial *serial) +{ + char *buf; + struct ark3116_private *priv; + int i; + + for (i = 0; i < serial->num_ports; ++i) { + priv = kmalloc (sizeof (struct ark3116_private), GFP_KERNEL); + if (!priv) + goto cleanup; + memset (priv, 0x00, sizeof (struct ark3116_private)); + spin_lock_init(&priv->lock); + + usb_set_serial_port_data(serial->port[i], priv); + } + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + dbg("error kmalloc -> out of mem ?"); + goto cleanup; + } + + /* 3 */ + ARK3116_SND(serial, 3,0xFE,0x40,0x0008,0x0002); + ARK3116_SND(serial, 4,0xFE,0x40,0x0008,0x0001); + ARK3116_SND(serial, 5,0xFE,0x40,0x0000,0x0008); + ARK3116_SND(serial, 6,0xFE,0x40,0x0000,0x000B); + + /* <-- seq7 */ + ARK3116_RCV(serial, 7,0xFE,0xC0,0x0000,0x0003, 0x00, buf); + ARK3116_SND(serial, 8,0xFE,0x40,0x0080,0x0003); + ARK3116_SND(serial, 9,0xFE,0x40,0x001A,0x0000); + ARK3116_SND(serial,10,0xFE,0x40,0x0000,0x0001); + ARK3116_SND(serial,11,0xFE,0x40,0x0000,0x0003); + + /* <-- seq12 */ + ARK3116_RCV(serial,12,0xFE,0xC0,0x0000,0x0004, 0x00, buf); + ARK3116_SND(serial,13,0xFE,0x40,0x0000,0x0004); + + /* 14 */ + ARK3116_RCV(serial,14,0xFE,0xC0,0x0000,0x0004, 0x00, buf); + ARK3116_SND(serial,15,0xFE,0x40,0x0000,0x0004); + + /* 16 */ + ARK3116_RCV(serial,16,0xFE,0xC0,0x0000,0x0004, 0x00, buf); + /* --> seq17 */ + ARK3116_SND(serial,17,0xFE,0x40,0x0001,0x0004); + + /* <-- seq18 */ + ARK3116_RCV(serial,18,0xFE,0xC0,0x0000,0x0004, 0x01, buf); + + /* --> seq19 */ + ARK3116_SND(serial,19,0xFE,0x40,0x0003,0x0004); + + + /* <-- seq20 */ + /* seems like serial port status info (RTS, CTS,...) */ + /* returns modem control line status ?! */ + ARK3116_RCV(serial,20,0xFE,0xC0,0x0000,0x0006, 0xFF, buf); + + /* set 9600 baud & do some init ?! */ + ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003); + ARK3116_SND(serial,148,0xFE,0x40,0x0038,0x0000); + ARK3116_SND(serial,149,0xFE,0x40,0x0001,0x0001); + ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003); + ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf); + ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003); + ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf); + ARK3116_SND(serial,154,0xFE,0x40,0x0003,0x0003); + + kfree(buf); + return(0); + +cleanup: + for (--i; i>=0; --i) + usb_set_serial_port_data(serial->port[i], NULL); + return -ENOMEM; +} + +static void ark3116_set_termios(struct usb_serial_port *port, + struct termios *old_termios) +{ + struct usb_serial *serial = port->serial; + struct ark3116_private *priv = usb_get_serial_port_data(port); + unsigned int cflag = port->tty->termios->c_cflag; + unsigned long flags; + int baud; + int ark3116_baud; + char *buf; + char config; + + config = 0; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if ((!port->tty) || (!port->tty->termios)) { + dbg("%s - no tty structures", __FUNCTION__); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (!priv->termios_initialized) { + *(port->tty->termios) = tty_std_termios; + port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + priv->termios_initialized = 1; + } + spin_unlock_irqrestore(&priv->lock, flags); + + cflag = port->tty->termios->c_cflag; + + /* check that they really want us to change something: */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(port->tty->termios->c_iflag) == + RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg("%s - nothing to change...", __FUNCTION__); + return; + } + } + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + dbg("error kmalloc"); + return; + } + + /* set data bit count (8/7/6/5) */ + if (cflag & CSIZE){ + switch (cflag & CSIZE){ + case CS5: + config |= 0x00; + dbg("setting CS5"); + break; + case CS6: + config |= 0x01; + dbg("setting CS6"); + break; + case CS7: + config |= 0x02; + dbg("setting CS7"); + break; + default: + err ("CSIZE was set but not CS5-CS8, using CS8!"); + case CS8: + config |= 0x03; + dbg("setting CS8"); + break; + } + } + + /* set parity (NONE,EVEN,ODD) */ + if (cflag & PARENB){ + if (cflag & PARODD) { + config |= 0x08; + dbg("setting parity to ODD"); + } else { + config |= 0x18; + dbg("setting parity to EVEN"); + } + } else { + dbg("setting parity to NONE"); + } + + /* SET STOPBIT (1/2) */ + if (cflag & CSTOPB) { + config |= 0x04; + dbg ("setting 2 stop bits"); + } else { + dbg ("setting 1 stop bit"); + } + + + /* set baudrate: */ + baud = 0; + switch (cflag & CBAUD){ + case B0: + err("can't set 0baud, using 9600 instead"); + break; + case B75: baud = 75; break; + case B150: baud = 150; break; + case B300: baud = 300; break; + case B600: baud = 600; break; + case B1200: baud = 1200; break; + case B1800: baud = 1800; break; + case B2400: baud = 2400; break; + case B4800: baud = 4800; break; + case B9600: baud = 9600; break; + case B19200: baud = 19200; break; + case B38400: baud = 38400; break; + case B57600: baud = 57600; break; + case B115200: baud = 115200; break; + case B230400: baud = 230400; break; + case B460800: baud = 460800; break; + default: + dbg("does not support the baudrate requested (fix it)"); + break; + } + + /* set 9600 as default (if given baudrate is invalid for example) */ + if (baud == 0) + baud = 9600; + + /* + * found by try'n'error, be careful, maybe there are other options + * for multiplicator etc! + */ + if (baud == 460800) + /* strange, for 460800 the formula is wrong + * (dont use round(), then 9600baud is wrong) */ + ark3116_baud = 7; + else + ark3116_baud = 3000000 / baud; + + /* ? */ + ARK3116_RCV(serial,0,0xFE,0xC0,0x0000,0x0003, 0x03, buf); + /* offset = buf[0]; */ + /* offset = 0x03; */ + /* dbg("using 0x%04X as target for 0x0003:",0x0080+offset); */ + + + /* set baudrate */ + dbg("setting baudrate to %d (->reg=%d)",baud,ark3116_baud); + ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003); + ARK3116_SND(serial,148,0xFE,0x40,(ark3116_baud & 0x00FF) ,0x0000); + ARK3116_SND(serial,149,0xFE,0x40,(ark3116_baud & 0xFF00)>>8,0x0001); + ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003); + + /* ? */ + ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf); + ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003); + + /* set data bit count, stop bit count & parity: */ + dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config); + ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf); + ARK3116_SND(serial,154,0xFE,0x40,config,0x0003); + + if (cflag & CRTSCTS) + dbg("CRTSCTS not supported by chipset ?!"); + + /* TEST ARK3116_SND(154,0xFE,0x40,0xFFFF, 0x0006); */ + + kfree(buf); + return; +} + +static int ark3116_open(struct usb_serial_port *port, struct file *filp) +{ + struct termios tmp_termios; + struct usb_serial *serial = port->serial; + char *buf; + int result = 0; + + dbg("%s - port %d", __FUNCTION__, port->number); + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + dbg("error kmalloc -> out of mem ?"); + return -ENOMEM; + } + + result = usb_serial_generic_open(port, filp); + if (result) + return result; + + /* open */ + ARK3116_RCV(serial,111,0xFE,0xC0,0x0000,0x0003, 0x02, buf); + + ARK3116_SND(serial,112,0xFE,0x40,0x0082,0x0003); + ARK3116_SND(serial,113,0xFE,0x40,0x001A,0x0000); + ARK3116_SND(serial,114,0xFE,0x40,0x0000,0x0001); + ARK3116_SND(serial,115,0xFE,0x40,0x0002,0x0003); + + ARK3116_RCV(serial,116,0xFE,0xC0,0x0000,0x0004, 0x03, buf); + ARK3116_SND(serial,117,0xFE,0x40,0x0002,0x0004); + + ARK3116_RCV(serial,118,0xFE,0xC0,0x0000,0x0004, 0x02, buf); + ARK3116_SND(serial,119,0xFE,0x40,0x0000,0x0004); + + ARK3116_RCV(serial,120,0xFE,0xC0,0x0000,0x0004, 0x00, buf); + + ARK3116_SND(serial,121,0xFE,0x40,0x0001,0x0004); + + ARK3116_RCV(serial,122,0xFE,0xC0,0x0000,0x0004, 0x01, buf); + + ARK3116_SND(serial,123,0xFE,0x40,0x0003,0x0004); + + /* returns different values (control lines ?!) */ + ARK3116_RCV(serial,124,0xFE,0xC0,0x0000,0x0006, 0xFF, buf); + + /* initialise termios: */ + if (port->tty) + ark3116_set_termios(port, &tmp_termios); + + kfree(buf); + + return result; + +} + +static int ark3116_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + dbg("ioctl not supported yet..."); + return -ENOIOCTLCMD; +} + +static int ark3116_tiocmget(struct usb_serial_port *port, struct file *file) +{ + struct usb_serial *serial = port->serial; + char *buf; + char temp; + + /* seems like serial port status info (RTS, CTS,...) is stored + * in reg(?) 0x0006 + * pcb connection point 11 = GND -> sets bit4 of response + * pcb connection point 7 = GND -> sets bit6 of response + */ + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + dbg("error kmalloc"); + return -ENOMEM; + } + + /* read register: */ + ARK3116_RCV_QUIET(serial,0xFE,0xC0,0x0000,0x0006,buf); + temp = buf[0]; + kfree(buf); + + /* i do not really know if bit4=CTS and bit6=DSR... was just a + * quick guess !! + */ + return (temp & (1<<4) ? TIOCM_CTS : 0) | + (temp & (1<<6) ? TIOCM_DSR : 0); +} + +static struct usb_driver ark3116_driver = { + .name = "ark3116", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, +}; + +static struct usb_serial_driver ark3116_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ark3116", + }, + .id_table = id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .attach = ark3116_attach, + .set_termios = ark3116_set_termios, + .ioctl = ark3116_ioctl, + .tiocmget = ark3116_tiocmget, + .open = ark3116_open, +}; + +static int __init ark3116_init(void) +{ + int retval; + + retval = usb_serial_register(&ark3116_device); + if (retval) + return retval; + retval = usb_register(&ark3116_driver); + if (retval) + usb_serial_deregister(&ark3116_device); + return retval; +} + +static void __exit ark3116_exit(void) +{ + usb_deregister(&ark3116_driver); + usb_serial_deregister(&ark3116_device); +} + +module_init(ark3116_init); +module_exit(ark3116_exit); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 476cda107f4f..c62cc2876519 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -138,6 +138,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) return result; } +EXPORT_SYMBOL_GPL(usb_serial_generic_open); static void generic_cleanup (struct usb_serial_port *port) { -- cgit v1.2.2 From df3fccb14ad02c5fabe095a104a0323c223f2833 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 May 2006 08:44:45 +0200 Subject: [PATCH] USB: fix omninet driver bug I introduced this way back in 2.6.13 when adding the port lock logic. This device talks out through different "ports" all at the same time, so the lock logic was wrong, preventing any data from ever being sent properly. Thanks a lot to Bernhard Reiter for being patient and helping with debugging this. Cc: Bernhard Reiter Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/omninet.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 4d40704dea2c..238033a87092 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -257,14 +257,14 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf return (0); } - spin_lock(&port->lock); - if (port->write_urb_busy) { - spin_unlock(&port->lock); + spin_lock(&wport->lock); + if (wport->write_urb_busy) { + spin_unlock(&wport->lock); dbg("%s - already writing", __FUNCTION__); return 0; } - port->write_urb_busy = 1; - spin_unlock(&port->lock); + wport->write_urb_busy = 1; + spin_unlock(&wport->lock); count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; @@ -283,7 +283,7 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf wport->write_urb->dev = serial->dev; result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); if (result) { - port->write_urb_busy = 0; + wport->write_urb_busy = 0; err("%s - failed submitting write urb, error %d", __FUNCTION__, result); } else result = count; -- cgit v1.2.2 From ef34814426862c41c061520d4ac833be5914b5ba Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 12 May 2006 12:49:08 -0700 Subject: [TG3]: ethtool always report port is TP. Even with fiber cards ethtool reports that the connected port is TP, the patch fix this. Signed-off-by: Karsten Keil Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2bd9592b75cd..e1b33a25a25f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7653,21 +7653,23 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) + if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) { cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_MII); - else + cmd->port = PORT_TP; + } else { cmd->supported |= SUPPORTED_FIBRE; + cmd->port = PORT_FIBRE; + } cmd->advertising = tp->link_config.advertising; if (netif_running(dev)) { cmd->speed = tp->link_config.active_speed; cmd->duplex = tp->link_config.active_duplex; } - cmd->port = 0; cmd->phy_address = PHY_ADDR; cmd->transceiver = 0; cmd->autoneg = tp->link_config.autoneg; -- cgit v1.2.2 From 586152560ae8df2a9babf1a8b667d7a145cb8208 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Fri, 12 May 2006 12:53:59 -0700 Subject: [SPARC]: Fix warning on prom_getproperty in openprom.c Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- drivers/sbus/char/openprom.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 383a95f34a0d..239e108b8ed1 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -392,13 +392,16 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file, return -ENOMEM; } - prom_getproperty(op.op_nodeid, str, tmp, len); - - tmp[len] = '\0'; + cnt = prom_getproperty(op.op_nodeid, str, tmp, len); + if (cnt <= 0) { + error = -EINVAL; + } else { + tmp[len] = '\0'; - if (__copy_to_user(argp, &op, sizeof(op)) != 0 - || copy_to_user(op.op_buf, tmp, len) != 0) - error = -EFAULT; + if (__copy_to_user(argp, &op, sizeof(op)) != 0 || + copy_to_user(op.op_buf, tmp, len) != 0) + error = -EFAULT; + } kfree(tmp); kfree(str); -- cgit v1.2.2 From 6f4bb3d8205d943acafa2f536f37131777524b67 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 12 May 2006 14:57:52 -0700 Subject: IB/ipath: Properly terminate PCI ID table The ipath driver's table of PCI IDs needs a { 0, } entry at the end. This makes all of the device aliases visible to userspace so hotplug loads the module for all supported devices. Without the patch, modinfo ipath_core only shows: alias: pci:v00001FC1d0000000Dsv*sd*bc*sc*i* instead of the correct: alias: pci:v00001FC1d00000010sv*sd*bc*sc*i* alias: pci:v00001FC1d0000000Dsv*sd*bc*sc*i* Signed-off-by: Roland Dreier Signed-off-by: Bryan O'Sullivan --- drivers/infiniband/hw/ipath/ipath_driver.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 398add4d4cb1..3697edafd6d2 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -116,10 +116,9 @@ static int __devinit ipath_init_one(struct pci_dev *, #define PCI_DEVICE_ID_INFINIPATH_PE800 0x10 static const struct pci_device_id ipath_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, - PCI_DEVICE_ID_INFINIPATH_HT)}, - {PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, - PCI_DEVICE_ID_INFINIPATH_PE800)}, + { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) }, + { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, ipath_pci_tbl); -- cgit v1.2.2 From 1b52fa98edd1c3e663ea4a06519e3d20976084a8 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Fri, 12 May 2006 14:57:52 -0700 Subject: IB: refcount race fixes Fix race condition during destruction calls to avoid possibility of accessing object after it has been freed. Instead of waking up a wait queue directly, which is susceptible to a race where the object is freed between the reference count going to 0 and the wake_up(), use a completion to wait in the function doing the freeing. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 12 ++++++---- drivers/infiniband/core/mad.c | 47 ++++++++++++++++++++------------------ drivers/infiniband/core/mad_priv.h | 5 ++-- drivers/infiniband/core/mad_rmpp.c | 20 ++++++++-------- drivers/infiniband/core/ucm.c | 12 ++++++---- 5 files changed, 52 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 7cfedb8d9bcd..86fee43502cd 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -34,6 +34,8 @@ * * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ */ + +#include #include #include #include @@ -122,7 +124,7 @@ struct cm_id_private { struct rb_node service_node; struct rb_node sidr_id_node; spinlock_t lock; /* Do not acquire inside cm.lock */ - wait_queue_head_t wait; + struct completion comp; atomic_t refcount; struct ib_mad_send_buf *msg; @@ -159,7 +161,7 @@ static void cm_work_handler(void *data); static inline void cm_deref_id(struct cm_id_private *cm_id_priv) { if (atomic_dec_and_test(&cm_id_priv->refcount)) - wake_up(&cm_id_priv->wait); + complete(&cm_id_priv->comp); } static int cm_alloc_msg(struct cm_id_private *cm_id_priv, @@ -559,7 +561,7 @@ struct ib_cm_id *ib_create_cm_id(struct ib_device *device, goto error; spin_lock_init(&cm_id_priv->lock); - init_waitqueue_head(&cm_id_priv->wait); + init_completion(&cm_id_priv->comp); INIT_LIST_HEAD(&cm_id_priv->work_list); atomic_set(&cm_id_priv->work_count, -1); atomic_set(&cm_id_priv->refcount, 1); @@ -724,8 +726,8 @@ retest: } cm_free_id(cm_id->local_id); - atomic_dec(&cm_id_priv->refcount); - wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount)); + cm_deref_id(cm_id_priv); + wait_for_completion(&cm_id_priv->comp); while ((work = cm_dequeue_work(cm_id_priv)) != NULL) cm_free_work(work); if (cm_id_priv->private_data && cm_id_priv->private_data_len) diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 469b6923a2e2..5ad41a64314c 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -352,7 +352,7 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, INIT_WORK(&mad_agent_priv->local_work, local_completions, mad_agent_priv); atomic_set(&mad_agent_priv->refcount, 1); - init_waitqueue_head(&mad_agent_priv->wait); + init_completion(&mad_agent_priv->comp); return &mad_agent_priv->agent; @@ -467,7 +467,7 @@ struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, mad_snoop_priv->agent.qp = port_priv->qp_info[qpn].qp; mad_snoop_priv->agent.port_num = port_num; mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; - init_waitqueue_head(&mad_snoop_priv->wait); + init_completion(&mad_snoop_priv->comp); mad_snoop_priv->snoop_index = register_snoop_agent( &port_priv->qp_info[qpn], mad_snoop_priv); @@ -486,6 +486,18 @@ error1: } EXPORT_SYMBOL(ib_register_mad_snoop); +static inline void deref_mad_agent(struct ib_mad_agent_private *mad_agent_priv) +{ + if (atomic_dec_and_test(&mad_agent_priv->refcount)) + complete(&mad_agent_priv->comp); +} + +static inline void deref_snoop_agent(struct ib_mad_snoop_private *mad_snoop_priv) +{ + if (atomic_dec_and_test(&mad_snoop_priv->refcount)) + complete(&mad_snoop_priv->comp); +} + static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) { struct ib_mad_port_private *port_priv; @@ -509,9 +521,8 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) flush_workqueue(port_priv->wq); ib_cancel_rmpp_recvs(mad_agent_priv); - atomic_dec(&mad_agent_priv->refcount); - wait_event(mad_agent_priv->wait, - !atomic_read(&mad_agent_priv->refcount)); + deref_mad_agent(mad_agent_priv); + wait_for_completion(&mad_agent_priv->comp); kfree(mad_agent_priv->reg_req); ib_dereg_mr(mad_agent_priv->agent.mr); @@ -529,9 +540,8 @@ static void unregister_mad_snoop(struct ib_mad_snoop_private *mad_snoop_priv) atomic_dec(&qp_info->snoop_count); spin_unlock_irqrestore(&qp_info->snoop_lock, flags); - atomic_dec(&mad_snoop_priv->refcount); - wait_event(mad_snoop_priv->wait, - !atomic_read(&mad_snoop_priv->refcount)); + deref_snoop_agent(mad_snoop_priv); + wait_for_completion(&mad_snoop_priv->comp); kfree(mad_snoop_priv); } @@ -600,8 +610,7 @@ static void snoop_send(struct ib_mad_qp_info *qp_info, spin_unlock_irqrestore(&qp_info->snoop_lock, flags); mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, send_buf, mad_send_wc); - if (atomic_dec_and_test(&mad_snoop_priv->refcount)) - wake_up(&mad_snoop_priv->wait); + deref_snoop_agent(mad_snoop_priv); spin_lock_irqsave(&qp_info->snoop_lock, flags); } spin_unlock_irqrestore(&qp_info->snoop_lock, flags); @@ -626,8 +635,7 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info, spin_unlock_irqrestore(&qp_info->snoop_lock, flags); mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent, mad_recv_wc); - if (atomic_dec_and_test(&mad_snoop_priv->refcount)) - wake_up(&mad_snoop_priv->wait); + deref_snoop_agent(mad_snoop_priv); spin_lock_irqsave(&qp_info->snoop_lock, flags); } spin_unlock_irqrestore(&qp_info->snoop_lock, flags); @@ -968,8 +976,7 @@ void ib_free_send_mad(struct ib_mad_send_buf *send_buf) free_send_rmpp_list(mad_send_wr); kfree(send_buf->mad); - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); } EXPORT_SYMBOL(ib_free_send_mad); @@ -1757,8 +1764,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv, mad_recv_wc); if (!mad_recv_wc) { - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); return; } } @@ -1770,8 +1776,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, if (!mad_send_wr) { spin_unlock_irqrestore(&mad_agent_priv->lock, flags); ib_free_recv_mad(mad_recv_wc); - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); return; } ib_mark_mad_done(mad_send_wr); @@ -1790,8 +1795,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, } else { mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, mad_recv_wc); - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); } } @@ -2021,8 +2025,7 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, mad_send_wc); /* Release reference on agent taken when sending */ - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); return; done: spin_unlock_irqrestore(&mad_agent_priv->lock, flags); diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 6c9c133d71ef..b4fa28d3160f 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -37,6 +37,7 @@ #ifndef __IB_MAD_PRIV_H__ #define __IB_MAD_PRIV_H__ +#include #include #include #include @@ -108,7 +109,7 @@ struct ib_mad_agent_private { struct list_head rmpp_list; atomic_t refcount; - wait_queue_head_t wait; + struct completion comp; }; struct ib_mad_snoop_private { @@ -117,7 +118,7 @@ struct ib_mad_snoop_private { int snoop_index; int mad_snoop_flags; atomic_t refcount; - wait_queue_head_t wait; + struct completion comp; }; struct ib_mad_send_wr_private { diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index dfd4e588ce03..d4704e054e30 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -49,7 +49,7 @@ struct mad_rmpp_recv { struct list_head list; struct work_struct timeout_work; struct work_struct cleanup_work; - wait_queue_head_t wait; + struct completion comp; enum rmpp_state state; spinlock_t lock; atomic_t refcount; @@ -69,10 +69,16 @@ struct mad_rmpp_recv { u8 method; }; +static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) +{ + if (atomic_dec_and_test(&rmpp_recv->refcount)) + complete(&rmpp_recv->comp); +} + static void destroy_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) { - atomic_dec(&rmpp_recv->refcount); - wait_event(rmpp_recv->wait, !atomic_read(&rmpp_recv->refcount)); + deref_rmpp_recv(rmpp_recv); + wait_for_completion(&rmpp_recv->comp); ib_destroy_ah(rmpp_recv->ah); kfree(rmpp_recv); } @@ -253,7 +259,7 @@ create_rmpp_recv(struct ib_mad_agent_private *agent, goto error; rmpp_recv->agent = agent; - init_waitqueue_head(&rmpp_recv->wait); + init_completion(&rmpp_recv->comp); INIT_WORK(&rmpp_recv->timeout_work, recv_timeout_handler, rmpp_recv); INIT_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler, rmpp_recv); spin_lock_init(&rmpp_recv->lock); @@ -279,12 +285,6 @@ error: kfree(rmpp_recv); return NULL; } -static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) -{ - if (atomic_dec_and_test(&rmpp_recv->refcount)) - wake_up(&rmpp_recv->wait); -} - static struct mad_rmpp_recv * find_rmpp_recv(struct ib_mad_agent_private *agent, struct ib_mad_recv_wc *mad_recv_wc) diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index f6a05965a4e8..9164a09b6ccd 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -32,6 +32,8 @@ * * $Id: ucm.c 2594 2005-06-13 19:46:02Z libor $ */ + +#include #include #include #include @@ -72,7 +74,7 @@ struct ib_ucm_file { struct ib_ucm_context { int id; - wait_queue_head_t wait; + struct completion comp; atomic_t ref; int events_reported; @@ -138,7 +140,7 @@ static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) static void ib_ucm_ctx_put(struct ib_ucm_context *ctx) { if (atomic_dec_and_test(&ctx->ref)) - wake_up(&ctx->wait); + complete(&ctx->comp); } static inline int ib_ucm_new_cm_id(int event) @@ -178,7 +180,7 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) return NULL; atomic_set(&ctx->ref, 1); - init_waitqueue_head(&ctx->wait); + init_completion(&ctx->comp); ctx->file = file; INIT_LIST_HEAD(&ctx->events); @@ -586,8 +588,8 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file, if (IS_ERR(ctx)) return PTR_ERR(ctx); - atomic_dec(&ctx->ref); - wait_event(ctx->wait, !atomic_read(&ctx->ref)); + ib_ucm_ctx_put(ctx); + wait_for_completion(&ctx->comp); /* No new events will be generated after destroying the cm_id. */ ib_destroy_cm_id(ctx->cm_id); -- cgit v1.2.2 From 90d5ede5985f3b172cc3ccd89bf8c52a209088a5 Mon Sep 17 00:00:00 2001 From: Stefan Schweizer Date: Mon, 15 May 2006 09:43:52 -0700 Subject: [PATCH] Fix capi reload by unregistering the correct major I am having the bug FATAL: Error inserting capi ([..]/capi.ko): Device or resource busy when I try to reload capi after loading it. in dmesg: capi20: unable to get major 68 Fix the issue which is caused by setting the major to zero when registering the chrdev succeeded. (akpm: this means that we can again not use `major=0' (dynamic major allocation) for this driver). Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/capi/capi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 9b493f0becc4..173c899a1fb4 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1499,7 +1499,6 @@ static int __init capi_init(void) printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); return major_ret; } - capi_major = major_ret; capi_class = class_create(THIS_MODULE, "capi"); if (IS_ERR(capi_class)) { unregister_chrdev(capi_major, "capi20"); -- cgit v1.2.2 From 94585136606e0598a93ec145d9a899c8ec9b2208 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Mon, 15 May 2006 09:43:53 -0700 Subject: [PATCH] tpm: update module dependencies The TIS driver is dependent upon information from the ACPI table for device discovery thus it compiles but does no actual work without this dependency. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 1efde3b27619..fe00c7dfb649 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -22,7 +22,7 @@ config TCG_TPM config TCG_TIS tristate "TPM Interface Specification 1.2 Interface" - depends on TCG_TPM + depends on TCG_TPM && PNPACPI ---help--- If you have a TPM security chip that is compliant with the TCG TIS 1.2 TPM specification say Yes and it will be accessible -- cgit v1.2.2 From 73d58588091e81e5ee4266488e2fb09a410f1512 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 May 2006 09:43:53 -0700 Subject: [PATCH] pcmcia Oopses fixes Fix some NULL dereferences in the pcmcia code when using old userland tools. Signed-off-by: Benjamin Herrenschmidt Acked-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/pcmcia_ioctl.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index c53db7ceda5e..738b1ef595a3 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -426,7 +426,7 @@ static int ds_open(struct inode *inode, struct file *file) if (!warning_printed) { printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl " - "usage.\n"); + "usage from process: %s.\n", current->comm); printk(KERN_INFO "pcmcia: This interface will soon be removed from " "the kernel; please expect breakage unless you upgrade " "to new tools.\n"); @@ -601,8 +601,12 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = CS_BAD_ARGS; else { struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function); - ret = pccard_get_configuration_info(s, p_dev, &buf->config); - pcmcia_put_dev(p_dev); + if (p_dev == NULL) + ret = CS_BAD_ARGS; + else { + ret = pccard_get_configuration_info(s, p_dev, &buf->config); + pcmcia_put_dev(p_dev); + } } break; case DS_GET_FIRST_TUPLE: @@ -632,8 +636,12 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = CS_BAD_ARGS; else { struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function); - ret = pccard_get_status(s, p_dev, &buf->status); - pcmcia_put_dev(p_dev); + if (p_dev == NULL) + ret = CS_BAD_ARGS; + else { + ret = pccard_get_status(s, p_dev, &buf->status); + pcmcia_put_dev(p_dev); + } } break; case DS_VALIDATE_CIS: @@ -665,9 +673,10 @@ static int ds_ioctl(struct inode * inode, struct file * file, if (!(buf->conf_reg.Function && (buf->conf_reg.Function >= s->functions))) { struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function); - if (p_dev) + if (p_dev) { ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg); - pcmcia_put_dev(p_dev); + pcmcia_put_dev(p_dev); + } } break; case DS_GET_FIRST_REGION: -- cgit v1.2.2 From a7b862f663d81858531dfccc0537bc9d8a2a4121 Mon Sep 17 00:00:00 2001 From: Chris Wedgwood Date: Mon, 15 May 2006 09:43:55 -0700 Subject: [PATCH] VIA quirk fixup, additional PCI IDs An earlier commit (75cf7456dd87335f574dcd53c4ae616a2ad71a11) changed an overly-zealous PCI quirk to only poke those VIA devices that need it. However, some PCI devices were not included in what I hope is now the full list. Consequently we're failing to run the quirk on all machines which need it, causing IRQ routing failures. This should I hope correct this. Thanks to Masoud Sharbiani for pointing this out and testing the fix. Signed-off-by: Chris Wedgwood Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/quirks.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 19e2b174d33c..0d36d5040880 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -634,6 +634,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vi * non-x86 architectures (yes Via exists on PPC among other places), * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get * interrupts delivered properly. + * + * Some of the on-chip devices are actually '586 devices' so they are + * listed here. */ static void quirk_via_irq(struct pci_dev *dev) { @@ -648,6 +651,10 @@ static void quirk_via_irq(struct pci_dev *dev) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } } +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq); DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq); DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq); DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq); -- cgit v1.2.2 From 698d070746770aaaec78ab4ffa3ab1f1d5c6abe8 Mon Sep 17 00:00:00 2001 From: Greg Smith Date: Mon, 15 May 2006 09:44:02 -0700 Subject: [PATCH] s390: lcs incorrect test While debugging why our LCS emulator is having some problems I noticed the following weirdness in drivers/s390/net/lcs.c routine lcs_irq. The `if' statement is always true since SCHN_STAT_PCI is defined as 0x80. Cc: Martin Schwidefsky Cc: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/s390/net/lcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 5d6b7a57b02f..e65da921a827 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1348,7 +1348,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) - channel->ccws; if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) || - (irb->scsw.cstat | SCHN_STAT_PCI)) + (irb->scsw.cstat & SCHN_STAT_PCI)) /* Bloody io subsystem tells us lies about cpa... */ index = (index - 1) & (LCS_NUM_BUFFS - 1); while (channel->io_idx != index) { -- cgit v1.2.2 From a8d2e7d95229db9999682113bfac40b49978f212 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 15 May 2006 09:44:14 -0700 Subject: [PATCH] LED: Improve Kconfig information Improve the NEW_LEDS Kconfig information to say what it does as well as what it doesn't. Signed-off-by: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/Kconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 3f5b64794542..626506234b76 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -4,8 +4,11 @@ menu "LED devices" config NEW_LEDS bool "LED Support" help - Say Y to enable Linux LED support. This is not related to standard - keyboard LEDs which are controlled via the input system. + Say Y to enable Linux LED support. This allows control of supported + LEDs from both userspace and optionally, by kernel events (triggers). + + This is not related to standard keyboard LEDs which are controlled + via the input system. config LEDS_CLASS tristate "LED Class Support" -- cgit v1.2.2 From 68673afd443c5eeb4cebfb9026e3675f43d79f2b Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 15 May 2006 09:44:15 -0700 Subject: [PATCH] Backlight/LCD Class: Fix sysfs _store error handling The backlight and LCD class _store functions currently accept values like "34 some random strings" without error. This corrects them to return -EINVAL if the value is not numeric with an optional byte of trailing whitespace. Signed-off-by: Richard Purdie Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/backlight.c | 18 ++++++++++++------ drivers/video/backlight/lcd.c | 32 ++++++++++++++++---------------- 2 files changed, 28 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 334b1db1bd7c..27597c576eff 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -29,12 +29,15 @@ static ssize_t backlight_show_power(struct class_device *cdev, char *buf) static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count) { - int rc = -ENXIO, power; + int rc = -ENXIO; char *endp; struct backlight_device *bd = to_backlight_device(cdev); + int power = simple_strtoul(buf, &endp, 0); + size_t size = endp - buf; - power = simple_strtoul(buf, &endp, 0); - if (*endp && !isspace(*endp)) + if (*endp && isspace(*endp)) + size++; + if (size != count) return -EINVAL; down(&bd->sem); @@ -65,12 +68,15 @@ static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf) static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count) { - int rc = -ENXIO, brightness; + int rc = -ENXIO; char *endp; struct backlight_device *bd = to_backlight_device(cdev); + int brightness = simple_strtoul(buf, &endp, 0); + size_t size = endp - buf; - brightness = simple_strtoul(buf, &endp, 0); - if (*endp && !isspace(*endp)) + if (*endp && isspace(*endp)) + size++; + if (size != count) return -EINVAL; down(&bd->sem); diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 86908a60c630..bc8ab005a3fb 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -31,12 +31,15 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf) static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count) { - int rc, power; + int rc = -ENXIO; char *endp; struct lcd_device *ld = to_lcd_device(cdev); + int power = simple_strtoul(buf, &endp, 0); + size_t size = endp - buf; - power = simple_strtoul(buf, &endp, 0); - if (*endp && !isspace(*endp)) + if (*endp && isspace(*endp)) + size++; + if (size != count) return -EINVAL; down(&ld->sem); @@ -44,8 +47,7 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_ pr_debug("lcd: set power to %d\n", power); ld->props->set_power(ld, power); rc = count; - } else - rc = -ENXIO; + } up(&ld->sem); return rc; @@ -53,14 +55,12 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf) { - int rc; + int rc = -ENXIO; struct lcd_device *ld = to_lcd_device(cdev); down(&ld->sem); if (likely(ld->props && ld->props->get_contrast)) rc = sprintf(buf, "%d\n", ld->props->get_contrast(ld)); - else - rc = -ENXIO; up(&ld->sem); return rc; @@ -68,12 +68,15 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf) static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count) { - int rc, contrast; + int rc = -ENXIO; char *endp; struct lcd_device *ld = to_lcd_device(cdev); + int contrast = simple_strtoul(buf, &endp, 0); + size_t size = endp - buf; - contrast = simple_strtoul(buf, &endp, 0); - if (*endp && !isspace(*endp)) + if (*endp && isspace(*endp)) + size++; + if (size != count) return -EINVAL; down(&ld->sem); @@ -81,8 +84,7 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si pr_debug("lcd: set contrast to %d\n", contrast); ld->props->set_contrast(ld, contrast); rc = count; - } else - rc = -ENXIO; + } up(&ld->sem); return rc; @@ -90,14 +92,12 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf) { - int rc; + int rc = -ENXIO; struct lcd_device *ld = to_lcd_device(cdev); down(&ld->sem); if (likely(ld->props)) rc = sprintf(buf, "%d\n", ld->props->max_contrast); - else - rc = -ENXIO; up(&ld->sem); return rc; -- cgit v1.2.2 From 3dc7b82ea7649356bf027fba50c16ca50cec31e2 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 15 May 2006 09:44:17 -0700 Subject: [PATCH] LED: Fix sysfs store function error handling Fix the error handling of some LED _store functions. This corrects them to return -EINVAL if the value is not numeric with an optional byte of trailing whitespace. Signed-off-by: Richard Purdie Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/led-class.c | 9 +++++++-- drivers/leds/ledtrig-timer.c | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index b0b5d05fadd6..c75d0ef1609c 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "leds.h" @@ -43,9 +44,13 @@ static ssize_t led_brightness_store(struct class_device *dev, ssize_t ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); + size_t count = after - buf; - if (after - buf > 0) { - ret = after - buf; + if (*after && isspace(*after)) + count++; + + if (count == size) { + ret = count; led_set_brightness(led_cdev, state); } diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index f484b5d6dbf8..fbf141ef46ec 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "leds.h" @@ -69,11 +70,15 @@ static ssize_t led_delay_on_store(struct class_device *dev, const char *buf, int ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); + size_t count = after - buf; - if (after - buf > 0) { + if (*after && isspace(*after)) + count++; + + if (count == size) { timer_data->delay_on = state; mod_timer(&timer_data->timer, jiffies + 1); - ret = after - buf; + ret = count; } return ret; @@ -97,11 +102,15 @@ static ssize_t led_delay_off_store(struct class_device *dev, const char *buf, int ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); + size_t count = after - buf; + + if (*after && isspace(*after)) + count++; - if (after - buf > 0) { + if (count == size) { timer_data->delay_off = state; mod_timer(&timer_data->timer, jiffies + 1); - ret = after - buf; + ret = count; } return ret; -- cgit v1.2.2 From 2a7362f52a17e8dbeab57c00c3c45fcfeb0dff54 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Mon, 15 May 2006 09:44:25 -0700 Subject: [PATCH] tpm: fix constant Fix the constant used for the base address when it cannot be determined from ACPI. It was off by one order of magnitude. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index b9cae9a238bb..f621168f38ae 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -55,7 +55,7 @@ enum tis_int_flags { }; enum tis_defaults { - TIS_MEM_BASE = 0xFED4000, + TIS_MEM_BASE = 0xFED40000, TIS_MEM_LEN = 0x5000, TIS_SHORT_TIMEOUT = 750, /* ms */ TIS_LONG_TIMEOUT = 2000, /* 2 sec */ -- cgit v1.2.2 From 655fdeab809a5612b0eab6aee873b00d26404ca7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 15 May 2006 09:44:26 -0700 Subject: [PATCH] Final rio polish Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 2 +- drivers/char/rio/host.h | 9 -------- drivers/char/rio/rioboot.c | 1 + drivers/char/rio/rioctrl.c | 43 ++++++++++++++++++++++------------ drivers/char/rio/rioioctl.h | 56 ++++----------------------------------------- 5 files changed, 35 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 402296670d3a..78d928f9d9f1 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -291,7 +291,7 @@ config SX config RIO tristate "Specialix RIO system support" - depends on SERIAL_NONSTANDARD && !64BIT + depends on SERIAL_NONSTANDARD help This is a driver for the Specialix RIO, a smart serial card which drives an outboard box that can support up to 128 ports. Product diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h index 3ec73d1a279a..179cdbea712b 100644 --- a/drivers/char/rio/host.h +++ b/drivers/char/rio/host.h @@ -33,12 +33,6 @@ #ifndef __rio_host_h__ #define __rio_host_h__ -#ifdef SCCS_LABELS -#ifndef lint -static char *_host_h_sccs_ = "@(#)host.h 1.2"; -#endif -#endif - /* ** the host structure - one per host card in the system. */ @@ -77,9 +71,6 @@ struct Host { #define RC_STARTUP 1 #define RC_RUNNING 2 #define RC_STUFFED 3 -#define RC_SOMETHING 4 -#define RC_SOMETHING_NEW 5 -#define RC_SOMETHING_ELSE 6 #define RC_READY 7 #define RUN_STATE 7 /* diff --git a/drivers/char/rio/rioboot.c b/drivers/char/rio/rioboot.c index acda9326c2ef..290143addd34 100644 --- a/drivers/char/rio/rioboot.c +++ b/drivers/char/rio/rioboot.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c index d31aba62bb7f..75b2557c37ec 100644 --- a/drivers/char/rio/rioctrl.c +++ b/drivers/char/rio/rioctrl.c @@ -1394,14 +1394,17 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) return RIO_FAIL; } - if (((int) ((char) PortP->InUse) == -1) || !(CmdBlkP = RIOGetCmdBlk())) { - rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block for command %d on port %d\n", Cmd, PortP->PortNum); + if ((PortP->InUse == (typeof(PortP->InUse))-1) || + !(CmdBlkP = RIOGetCmdBlk())) { + rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block " + "for command %d on port %d\n", Cmd, PortP->PortNum); return RIO_FAIL; } - rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n", CmdBlkP, PortP->InUse); + rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n", + CmdBlkP, PortP->InUse); - PktCmdP = (struct PktCmd_M *) &CmdBlkP->Packet.data[0]; + PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0]; CmdBlkP->Packet.src_unit = 0; if (PortP->SecondBlock) @@ -1425,38 +1428,46 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) switch (Cmd) { case MEMDUMP: - rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p (addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p " + "(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr); PktCmdP->SubCommand = MEMDUMP; PktCmdP->SubAddr = SubCmd.Addr; break; case FCLOSE: - rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n", + CmdBlkP); break; case READ_REGISTER: - rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) command blk %p\n", (int) SubCmd.Addr, CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) " + "command blk %p\n", (int) SubCmd.Addr, CmdBlkP); PktCmdP->SubCommand = READ_REGISTER; PktCmdP->SubAddr = SubCmd.Addr; break; case RESUME: - rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n", + CmdBlkP); break; case RFLUSH: - rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n", + CmdBlkP); CmdBlkP->PostFuncP = RIORFlushEnable; break; case SUSPEND: - rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n", + CmdBlkP); break; case MGET: - rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n", + CmdBlkP); break; case MSET: case MBIC: case MBIS: CmdBlkP->Packet.data[4] = (char) PortP->ModemLines; - rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command " + "blk %p\n", CmdBlkP); break; case WFLUSH: @@ -1465,12 +1476,14 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) ** allowed then we should not bother sending any more to the ** RTA. */ - if ((int) ((char) PortP->WflushFlag) == (int) -1) { - rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, WflushFlag about to wrap!"); + if (PortP->WflushFlag == (typeof(PortP->WflushFlag))-1) { + rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, " + "WflushFlag about to wrap!"); RIOFreeCmdBlk(CmdBlkP); return (RIO_FAIL); } else { - rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command " + "blk %p\n", CmdBlkP); CmdBlkP->PostFuncP = RIOWFlushMark; } break; diff --git a/drivers/char/rio/rioioctl.h b/drivers/char/rio/rioioctl.h index 14b83fae75c8..e8af5b30519e 100644 --- a/drivers/char/rio/rioioctl.h +++ b/drivers/char/rio/rioioctl.h @@ -33,10 +33,6 @@ #ifndef __rioioctl_h__ #define __rioioctl_h__ -#ifdef SCCS_LABELS -static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2"; -#endif - /* ** RIO device driver - user ioctls and associated structures. */ @@ -44,55 +40,13 @@ static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2"; struct portStats { int port; int gather; - ulong txchars; - ulong rxchars; - ulong opens; - ulong closes; - ulong ioctls; + unsigned long txchars; + unsigned long rxchars; + unsigned long opens; + unsigned long closes; + unsigned long ioctls; }; - -#define rIOC ('r'<<8) -#define TCRIOSTATE (rIOC | 1) -#define TCRIOXPON (rIOC | 2) -#define TCRIOXPOFF (rIOC | 3) -#define TCRIOXPCPS (rIOC | 4) -#define TCRIOXPRINT (rIOC | 5) -#define TCRIOIXANYON (rIOC | 6) -#define TCRIOIXANYOFF (rIOC | 7) -#define TCRIOIXONON (rIOC | 8) -#define TCRIOIXONOFF (rIOC | 9) -#define TCRIOMBIS (rIOC | 10) -#define TCRIOMBIC (rIOC | 11) -#define TCRIOTRIAD (rIOC | 12) -#define TCRIOTSTATE (rIOC | 13) - -/* -** 15.10.1998 ARG - ESIL 0761 part fix -** Add RIO ioctls for manipulating RTS and CTS flow control, (as LynxOS -** appears to not support hardware flow control). -*/ -#define TCRIOCTSFLOWEN (rIOC | 14) /* enable CTS flow control */ -#define TCRIOCTSFLOWDIS (rIOC | 15) /* disable CTS flow control */ -#define TCRIORTSFLOWEN (rIOC | 16) /* enable RTS flow control */ -#define TCRIORTSFLOWDIS (rIOC | 17) /* disable RTS flow control */ - -/* -** 09.12.1998 ARG - ESIL 0776 part fix -** Definition for 'RIOC' also appears in daemon.h, so we'd better do a -** #ifndef here first. -** 'RIO_QUICK_CHECK' also #define'd here as this ioctl is now -** allowed to be used by customers. -** -** 05.02.1999 ARG - -** This is what I've decied to do with ioctls etc., which are intended to be -** invoked from users applications : -** Anything that needs to be defined here will be removed from daemon.h, that -** way it won't end up having to be defined/maintained in two places. The only -** consequence of this is that this file should now be #include'd by daemon.h -** -** 'stats' ioctls now #define'd here as they are to be used by customers. -*/ #define RIOC ('R'<<8)|('i'<<16)|('o'<<24) #define RIO_QUICK_CHECK (RIOC | 105) -- cgit v1.2.2 From bb53a76116a8af13ee2581c85c02fe40e0c1a599 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 15 May 2006 09:44:27 -0700 Subject: [PATCH] tpm_register_hardware gcc 4.1 warning fix drivers/char/tpm/tpm.c: In function 'tpm_register_hardware': drivers/char/tpm/tpm.c:1157: warning: assignment from incompatible pointer type Signed-off-by: Daniel Walker Acked-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 54a4c804e25f..050ced247f68 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -140,7 +140,7 @@ extern int tpm_pm_resume(struct device *); extern struct dentry ** tpm_bios_log_setup(char *); extern void tpm_bios_log_teardown(struct dentry **); #else -static inline struct dentry* tpm_bios_log_setup(char *name) +static inline struct dentry ** tpm_bios_log_setup(char *name) { return NULL; } -- cgit v1.2.2 From ce007ea59729d627f62bb5fa8c1a81e25653a0ad Mon Sep 17 00:00:00 2001 From: Carl-Daniel Hailfinger Date: Mon, 15 May 2006 09:44:33 -0700 Subject: [PATCH] smbus unhiding kills thermal management Do not enable the SMBus device on Asus boards if suspend is used. We do not reenable the device on resume, leading to all sorts of undesirable effects, the worst being a total fan failure after resume on Samsung P35 laptop. Signed-off-by: Carl-Daniel Hailfinger Signed-off-by: Pavel Machek Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/quirks.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0d36d5040880..d378478612fb 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -902,6 +902,7 @@ static void __init k8t_sound_hostbridge(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); +#ifndef CONFIG_ACPI_SLEEP /* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge * is not activated. The myth is that Asus said that they do not want the @@ -913,8 +914,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho * bridge. Unfortunately, this device has no subvendor/subdevice ID. So it * becomes necessary to do this tweak in two steps -- I've chosen the Host * bridge as trigger. + * + * Actually, leaving it unhidden and not redoing the quirk over suspend2ram + * will cause thermal management to break down, and causing machine to + * overheat. */ -static int __initdata asus_hides_smbus = 0; +static int __initdata asus_hides_smbus; static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) { @@ -1057,6 +1062,8 @@ static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); +#endif + /* * SiS 96x south bridge: BIOS typically hides SMBus device... */ -- cgit v1.2.2 From bfe2e9349f318883c036607c64b6205d573a28ff Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 15 May 2006 09:44:35 -0700 Subject: [PATCH] gigaset: endian fix Signed-off-by: Alexey Dobriyan Cc: Hansjoerg Lipp Cc: Tilman Schmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/gigaset/usb-gigaset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index bfb73fd5077e..d86ab68114b0 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -710,8 +710,8 @@ static int gigaset_probe(struct usb_interface *interface, retval = -ENODEV; //FIXME /* See if the device offered us matches what we can accept */ - if ((le16_to_cpu(udev->descriptor.idVendor != USB_M105_VENDOR_ID)) || - (le16_to_cpu(udev->descriptor.idProduct != USB_M105_PRODUCT_ID))) + if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) || + (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) return -ENODEV; /* this starts to become ascii art... */ -- cgit v1.2.2 From 264a341231e8af2c2e35ac15d26de76f1198525b Mon Sep 17 00:00:00 2001 From: Thomas Kleffel Date: Mon, 15 May 2006 09:44:37 -0700 Subject: [PATCH] ide_cs: Add IBM microdrive to known IDs Add the IBM microdrive to the known PCMCIA IDs for ide_cs. Signed-off-by: Thomas Kleffel Cc: Bartlomiej Zolnierkiewicz Cc: Alan Cox Cc: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/legacy/ide-cs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 4961f1e764a7..602797a44208 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -392,6 +392,7 @@ static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), + PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), -- cgit v1.2.2 From c4694c76ce28dd7e415b4f3014d8c6e580b5f3d2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 15 May 2006 09:44:43 -0700 Subject: [PATCH] dl2k needs dma-mapping.h On alpha: drivers/net/dl2k.c: In function `rio_free_tx': drivers/net/dl2k.c:768: error: `DMA_48BIT_MASK' undeclared (first use in this function) drivers/net/dl2k.c:768: error: (Each undeclared identifier is reported only once drivers/net/dl2k.c:768: error: for each function it appears in.) drivers/net/dl2k.c: In function `receive_packet': drivers/net/dl2k.c:896: error: `DMA_48BIT_MASK' undeclared (first use in this function) drivers/net/dl2k.c: In function `rio_close': drivers/net/dl2k.c:1803: error: `DMA_48BIT_MASK' undeclared (first use in this function) Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/dl2k.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 1ddefd281213..038447fb5c5e 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -53,6 +53,7 @@ #define DRV_VERSION "v1.17b" #define DRV_RELDATE "2006/03/10" #include "dl2k.h" +#include static char version[] __devinitdata = KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n"; -- cgit v1.2.2