Add an ISA attachement to the aic7xxx driver to handle 284X controllers.
The ISA probe uses an identify routine to probe all slot locations from 1 to 14 that do not conflict with other allocated resources. This required making aic7770.c part of the driver core when compiled as a module. aic7xxx.c: aic79xx.c: aic_osm_lib.c: Use aic_scb_timer_start() consistently to start the watchdog timer. This removes a few places that verbatum copied the code in aic_scb_timer_start(). During recovery processing, allow commands to still be queued to the controller. The only requirement we have is that our recovery command be queued first - something the code already guaranteed. The only other change required to make this work is to prevent timers from being started for these newly queued commands. Approved by: re
This commit is contained in:
parent
34c8a85fc8
commit
7afc02188a
@ -318,9 +318,9 @@ dev/ahb/ahb.c optional ahb eisa
|
||||
dev/aic/aic.c optional aic
|
||||
dev/aic/aic_pccard.c optional aic card
|
||||
dev/aic/aic_pccard.c optional aic pccard
|
||||
dev/aic7xxx/aic7770.c optional ahc eisa
|
||||
dev/aic7xxx/aic7770.c optional ahc
|
||||
dev/aic7xxx/ahc_eisa.c optional ahc eisa
|
||||
#dev/aic7xxx/ahc_isa.c optional ahc isa
|
||||
dev/aic7xxx/ahc_isa.c optional ahc isa
|
||||
dev/aic7xxx/ahc_pci.c optional ahc pci
|
||||
dev/aic7xxx/aic7xxx.c optional ahc
|
||||
dev/aic7xxx/aic7xxx_93cx6.c optional ahc
|
||||
|
@ -159,41 +159,6 @@ aic7770_attach(device_t dev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
aic7770_map_registers(struct ahc_softc *ahc, u_int unused_ioport_arg)
|
||||
{
|
||||
struct resource *regs;
|
||||
int rid;
|
||||
|
||||
rid = 0;
|
||||
regs = bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IOPORT, &rid,
|
||||
RF_ACTIVE);
|
||||
if (regs == NULL) {
|
||||
device_printf(ahc->dev_softc, "Unable to map I/O space?!\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
ahc->platform_data->regs_res_type = SYS_RES_IOPORT;
|
||||
ahc->platform_data->regs_res_id = rid,
|
||||
ahc->platform_data->regs = regs;
|
||||
ahc->tag = rman_get_bustag(regs);
|
||||
ahc->bsh = rman_get_bushandle(regs);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
aic7770_map_int(struct ahc_softc *ahc, int irq)
|
||||
{
|
||||
int zero;
|
||||
|
||||
zero = 0;
|
||||
ahc->platform_data->irq =
|
||||
bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IRQ, &zero,
|
||||
RF_ACTIVE);
|
||||
if (ahc->platform_data->irq == NULL)
|
||||
return (ENOMEM);
|
||||
ahc->platform_data->irq_res_type = SYS_RES_IRQ;
|
||||
return (ahc_map_int(ahc));
|
||||
}
|
||||
|
||||
static device_method_t ahc_eisa_device_methods[] = {
|
||||
/* Device interface */
|
||||
|
@ -237,22 +237,3 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
|
||||
ahc->platform_data->regs = regs;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ahc_pci_map_int(struct ahc_softc *ahc)
|
||||
{
|
||||
int zero;
|
||||
|
||||
zero = 0;
|
||||
ahc->platform_data->irq =
|
||||
bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IRQ, &zero,
|
||||
RF_ACTIVE | RF_SHAREABLE);
|
||||
if (ahc->platform_data->irq == NULL) {
|
||||
device_printf(ahc->dev_softc,
|
||||
"bus_alloc_resource() failed to allocate IRQ\n");
|
||||
return (ENOMEM);
|
||||
}
|
||||
ahc->platform_data->irq_res_type = SYS_RES_IRQ;
|
||||
return (ahc_map_int(ahc));
|
||||
}
|
||||
|
||||
|
@ -8351,9 +8351,14 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
|
||||
ahd_queue_scb(ahd, scb);
|
||||
/*
|
||||
* Ensure we have enough time to actually
|
||||
* retrieve the sense.
|
||||
* retrieve the sense, but only schedule
|
||||
* the timer if we are not in recovery or
|
||||
* this is a recovery SCB that is allowed
|
||||
* to have an active timer.
|
||||
*/
|
||||
aic_scb_timer_reset(scb, 5 * 1000000);
|
||||
if (ahd->scb_data.recovery_scbs == 0
|
||||
|| (scb->flags & SCB_RECOVERY_SCB) != 0)
|
||||
aic_scb_timer_reset(scb, 5 * 1000000);
|
||||
break;
|
||||
}
|
||||
case SCSI_STATUS_OK:
|
||||
@ -9441,15 +9446,6 @@ bus_reset:
|
||||
* In either case (selection or reselection),
|
||||
* we will now issue a target reset to the
|
||||
* timed-out device.
|
||||
*
|
||||
* Set the MK_MESSAGE control bit indicating
|
||||
* that we desire to send a message. We
|
||||
* also set the disconnected flag since
|
||||
* in the paging case there is no guarantee
|
||||
* that our SCB control byte matches the
|
||||
* version on the card. We don't want the
|
||||
* sequencer to abort the command thinking
|
||||
* an unsolicited reselection occurred.
|
||||
*/
|
||||
scb->flags |= SCB_DEVICE_RESET;
|
||||
scb->hscb->cdb_len = 0;
|
||||
|
@ -667,12 +667,15 @@ struct scb_data {
|
||||
*/
|
||||
struct scb *scbindex[AHD_SCB_MAX];
|
||||
|
||||
u_int recovery_scbs; /* Transactions currently in recovery */
|
||||
|
||||
/*
|
||||
* "Bus" addresses of our data structures.
|
||||
*/
|
||||
bus_dma_tag_t hscb_dmat; /* dmat for our hardware SCB array */
|
||||
bus_dma_tag_t sg_dmat; /* dmat for our sg segments */
|
||||
bus_dma_tag_t sense_dmat; /* dmat for our sense buffers */
|
||||
|
||||
SLIST_HEAD(, map_node) hscb_maps;
|
||||
SLIST_HEAD(, map_node) sg_maps;
|
||||
SLIST_HEAD(, map_node) sense_maps;
|
||||
@ -1068,6 +1071,8 @@ struct ahd_completion
|
||||
uint8_t valid_tag;
|
||||
};
|
||||
|
||||
#define AIC_SCB_DATA(softc) (&(softc)->scb_data)
|
||||
|
||||
struct ahd_softc {
|
||||
bus_space_tag_t tags[2];
|
||||
bus_space_handle_t bshs[2];
|
||||
|
@ -263,40 +263,31 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the recovery SCB completes, we have to be
|
||||
* out of our timeout.
|
||||
*/
|
||||
if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
|
||||
struct scb *list_scb;
|
||||
|
||||
/*
|
||||
* We were able to complete the command successfully,
|
||||
* so reinstate the timeouts for all other pending
|
||||
* commands.
|
||||
*/
|
||||
LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) {
|
||||
union ccb *ccb;
|
||||
uint64_t time;
|
||||
|
||||
ccb = list_scb->io_ctx;
|
||||
if (ccb->ccb_h.timeout == CAM_TIME_INFINITY)
|
||||
continue;
|
||||
|
||||
time = ccb->ccb_h.timeout;
|
||||
time *= hz;
|
||||
time /= 1000;
|
||||
ccb->ccb_h.timeout_ch =
|
||||
timeout(ahd_platform_timeout, list_scb, time);
|
||||
}
|
||||
ahd->scb_data.recovery_scbs--;
|
||||
|
||||
if (aic_get_transaction_status(scb) == CAM_BDR_SENT
|
||||
|| aic_get_transaction_status(scb) == CAM_REQ_ABORTED)
|
||||
aic_set_transaction_status(scb, CAM_CMD_TIMEOUT);
|
||||
|
||||
ahd_print_path(ahd, scb);
|
||||
printf("no longer in timeout, status = %x\n",
|
||||
ccb->ccb_h.status);
|
||||
if (ahd->scb_data.recovery_scbs == 0) {
|
||||
/*
|
||||
* All recovery actions have completed successfully,
|
||||
* so reinstate the timeouts for all other pending
|
||||
* commands.
|
||||
*/
|
||||
LIST_FOREACH(list_scb,
|
||||
&ahd->pending_scbs, pending_links) {
|
||||
|
||||
aic_scb_timer_reset(scb, aic_get_timeout(scb));
|
||||
}
|
||||
|
||||
ahd_print_path(ahd, scb);
|
||||
printf("no longer in timeout, status = %x\n",
|
||||
ccb->ccb_h.status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't clobber any existing error state */
|
||||
@ -1123,18 +1114,7 @@ ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
|
||||
|
||||
ccb->ccb_h.status |= CAM_SIM_QUEUED;
|
||||
|
||||
if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
|
||||
uint64_t time;
|
||||
|
||||
if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT)
|
||||
ccb->ccb_h.timeout = 5 * 1000;
|
||||
|
||||
time = ccb->ccb_h.timeout;
|
||||
time *= hz;
|
||||
time /= 1000;
|
||||
ccb->ccb_h.timeout_ch =
|
||||
timeout(ahd_platform_timeout, (caddr_t)scb, time);
|
||||
}
|
||||
aic_scb_timer_start(scb);
|
||||
|
||||
if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
|
||||
/* Define a mapping from our tag to the SCB. */
|
||||
|
@ -377,6 +377,9 @@ ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
|
||||
if ((scb = TAILQ_FIRST(queue)) != NULL
|
||||
&& (scb->flags & SCB_ACTIVE) == 0) {
|
||||
scb->flags |= SCB_ACTIVE;
|
||||
/*
|
||||
* Timers are disabled while recovery is in progress.
|
||||
*/
|
||||
aic_scb_timer_start(scb);
|
||||
ahc_queue_scb(ahc, scb);
|
||||
}
|
||||
@ -578,9 +581,14 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
|
||||
ahc_outb(ahc, RETURN_1, SEND_SENSE);
|
||||
/*
|
||||
* Ensure we have enough time to actually
|
||||
* retrieve the sense.
|
||||
* retrieve the sense, but only schedule
|
||||
* the timer if we are not in recovery or
|
||||
* this is a recovery SCB that is allowed
|
||||
* to have an active timer.
|
||||
*/
|
||||
aic_scb_timer_reset(scb, 5 * 1000000);
|
||||
if (ahc->scb_data->recovery_scbs == 0
|
||||
|| (scb->flags & SCB_RECOVERY_SCB) != 0)
|
||||
aic_scb_timer_reset(scb, 5 * 1000000);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -613,6 +613,8 @@ struct scb_data {
|
||||
struct scb *scbarray; /* Array of kernel SCBs */
|
||||
struct scsi_sense_data *sense; /* Per SCB sense data */
|
||||
|
||||
u_int recovery_scbs; /* Transactions currently in recovery */
|
||||
|
||||
/*
|
||||
* "Bus" addresses of our data structures.
|
||||
*/
|
||||
@ -920,6 +922,8 @@ typedef int (*ahc_bus_suspend_t)(struct ahc_softc *);
|
||||
typedef int (*ahc_bus_resume_t)(struct ahc_softc *);
|
||||
typedef void ahc_callback_t (void *);
|
||||
|
||||
#define AIC_SCB_DATA(softc) ((softc)->scb_data)
|
||||
|
||||
struct ahc_softc {
|
||||
bus_space_tag_t tag;
|
||||
bus_space_handle_t bsh;
|
||||
|
@ -90,6 +90,20 @@ int
|
||||
ahc_map_int(struct ahc_softc *ahc)
|
||||
{
|
||||
int error;
|
||||
int zero;
|
||||
int shareable;
|
||||
|
||||
zero = 0;
|
||||
shareable = (ahc->flags & AHC_EDGE_INTERRUPT) ? 0: RF_SHAREABLE;
|
||||
ahc->platform_data->irq =
|
||||
bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IRQ, &zero,
|
||||
RF_ACTIVE | shareable);
|
||||
if (ahc->platform_data->irq == NULL) {
|
||||
device_printf(ahc->dev_softc,
|
||||
"bus_alloc_resource() failed to allocate IRQ\n");
|
||||
return (ENOMEM);
|
||||
}
|
||||
ahc->platform_data->irq_res_type = SYS_RES_IRQ;
|
||||
|
||||
/* Hook up our interrupt handler */
|
||||
error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq,
|
||||
@ -102,6 +116,27 @@ ahc_map_int(struct ahc_softc *ahc)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
aic7770_map_registers(struct ahc_softc *ahc, u_int unused_ioport_arg)
|
||||
{
|
||||
struct resource *regs;
|
||||
int rid;
|
||||
|
||||
rid = 0;
|
||||
regs = bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IOPORT, &rid,
|
||||
RF_ACTIVE);
|
||||
if (regs == NULL) {
|
||||
device_printf(ahc->dev_softc, "Unable to map I/O space?!\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
ahc->platform_data->regs_res_type = SYS_RES_IOPORT;
|
||||
ahc->platform_data->regs_res_id = rid,
|
||||
ahc->platform_data->regs = regs;
|
||||
ahc->tag = rman_get_bustag(regs);
|
||||
ahc->bsh = rman_get_bushandle(regs);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach all the sub-devices we can find
|
||||
*/
|
||||
@ -346,22 +381,28 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
|
||||
if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
|
||||
struct scb *list_scb;
|
||||
|
||||
/*
|
||||
* We were able to complete the command successfully,
|
||||
* so renew the timeouts for all other pending
|
||||
* commands.
|
||||
*/
|
||||
LIST_FOREACH(list_scb, &ahc->pending_scbs, pending_links) {
|
||||
|
||||
aic_scb_timer_reset(scb, aic_get_timeout(scb));
|
||||
}
|
||||
ahc->scb_data->recovery_scbs--;
|
||||
|
||||
if (aic_get_transaction_status(scb) == CAM_BDR_SENT
|
||||
|| aic_get_transaction_status(scb) == CAM_REQ_ABORTED)
|
||||
aic_set_transaction_status(scb, CAM_CMD_TIMEOUT);
|
||||
ahc_print_path(ahc, scb);
|
||||
printf("no longer in timeout, status = %x\n",
|
||||
ccb->ccb_h.status);
|
||||
|
||||
if (ahc->scb_data->recovery_scbs == 0) {
|
||||
/*
|
||||
* All recovery actions have completed successfully,
|
||||
* so reinstate the timeouts for all other pending
|
||||
* commands.
|
||||
*/
|
||||
LIST_FOREACH(list_scb, &ahc->pending_scbs,
|
||||
pending_links) {
|
||||
|
||||
aic_scb_timer_reset(scb, aic_get_timeout(scb));
|
||||
}
|
||||
|
||||
ahc_print_path(ahc, scb);
|
||||
printf("no longer in timeout, status = %x\n",
|
||||
ccb->ccb_h.status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't clobber any existing error state */
|
||||
@ -1230,19 +1271,6 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
|
||||
|
||||
ccb->ccb_h.status |= CAM_SIM_QUEUED;
|
||||
|
||||
if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
|
||||
uint64_t time;
|
||||
|
||||
if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT)
|
||||
ccb->ccb_h.timeout = 5 * 1000;
|
||||
|
||||
time = ccb->ccb_h.timeout;
|
||||
time *= hz;
|
||||
time /= 1000;
|
||||
ccb->ccb_h.timeout_ch =
|
||||
timeout(ahc_platform_timeout, (caddr_t)scb, time);
|
||||
}
|
||||
|
||||
/*
|
||||
* We only allow one untagged transaction
|
||||
* per target in the initiator role unless
|
||||
@ -1265,6 +1293,11 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
|
||||
}
|
||||
scb->flags |= SCB_ACTIVE;
|
||||
|
||||
/*
|
||||
* Timers are disabled while recovery is in progress.
|
||||
*/
|
||||
aic_scb_timer_start(scb);
|
||||
|
||||
if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
|
||||
/* Define a mapping from our tag to the SCB. */
|
||||
ahc->scb_data->scbindex[scb->hscb->tag] = scb;
|
||||
|
@ -256,15 +256,35 @@ ahc_list_unlock(unsigned long *flags)
|
||||
{
|
||||
}
|
||||
|
||||
/************************* Initialization/Teardown ****************************/
|
||||
int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
|
||||
void ahc_platform_free(struct ahc_softc *ahc);
|
||||
int ahc_map_int(struct ahc_softc *ahc);
|
||||
int ahc_attach(struct ahc_softc *);
|
||||
int ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc);
|
||||
int ahc_detach(device_t);
|
||||
|
||||
/********************************** PCI ***************************************/
|
||||
#ifdef AIC_PCI_CONFIG
|
||||
int ahc_pci_map_registers(struct ahc_softc *ahc);
|
||||
int ahc_pci_map_int(struct ahc_softc *ahc);
|
||||
#define ahc_pci_map_int ahc_map_int
|
||||
#endif /*AIC_PCI_CONFIG*/
|
||||
|
||||
/******************************** VL/EISA *************************************/
|
||||
int aic7770_map_registers(struct ahc_softc *ahc, u_int port);
|
||||
int aic7770_map_int(struct ahc_softc *ahc, int irq);
|
||||
static __inline int aic7770_map_int(struct ahc_softc *, int);
|
||||
|
||||
static __inline int
|
||||
aic7770_map_int(struct ahc_softc *ahc, int irq)
|
||||
{
|
||||
/*
|
||||
* The IRQ is unused in the FreeBSD
|
||||
* implementation since the EISA and
|
||||
* ISA attachments register the IRQ
|
||||
* with newbus before the core is called.
|
||||
*/
|
||||
return ahc_map_int(ahc);
|
||||
}
|
||||
|
||||
/********************************* Debug **************************************/
|
||||
static __inline void ahc_print_path(struct ahc_softc *, struct scb *);
|
||||
@ -287,14 +307,6 @@ void ahc_notify_xfer_settings_change(struct ahc_softc *,
|
||||
void ahc_platform_set_tags(struct ahc_softc *, struct ahc_devinfo *,
|
||||
int /*enable*/);
|
||||
|
||||
/************************* Initialization/Teardown ****************************/
|
||||
int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
|
||||
void ahc_platform_free(struct ahc_softc *ahc);
|
||||
int ahc_map_int(struct ahc_softc *ahc);
|
||||
int ahc_attach(struct ahc_softc *);
|
||||
int ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc);
|
||||
int ahc_detach(device_t);
|
||||
|
||||
/****************************** Interrupts ************************************/
|
||||
void ahc_platform_intr(void *);
|
||||
static __inline void ahc_platform_flushwork(struct ahc_softc *ahc);
|
||||
|
@ -46,15 +46,7 @@ aic_set_recoveryscb(struct aic_softc *aic, struct scb *scb)
|
||||
|
||||
scb->flags |= SCB_RECOVERY_SCB;
|
||||
|
||||
/*
|
||||
* Take all queued, but not sent SCBs out of the equation.
|
||||
* Also ensure that no new CCBs are queued to us while we
|
||||
* try to fix this problem.
|
||||
*/
|
||||
if ((scb->io_ctx->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
|
||||
xpt_freeze_simq(SCB_GET_SIM(aic, scb), /*count*/1);
|
||||
scb->io_ctx->ccb_h.status |= CAM_RELEASE_SIMQ;
|
||||
}
|
||||
AIC_SCB_DATA(aic)->recovery_scbs++;
|
||||
|
||||
/*
|
||||
* Go through all of our pending SCBs and remove
|
||||
|
@ -223,7 +223,8 @@ static __inline void
|
||||
aic_scb_timer_start(struct scb *scb)
|
||||
{
|
||||
|
||||
if (scb->io_ctx->ccb_h.timeout != CAM_TIME_INFINITY) {
|
||||
if (AIC_SCB_DATA(scb->aic_softc)->recovery_scbs == 0
|
||||
&& scb->io_ctx->ccb_h.timeout != CAM_TIME_INFINITY) {
|
||||
uint64_t time;
|
||||
|
||||
time = scb->io_ctx->ccb_h.timeout;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/aic7xxx
|
||||
KMOD= ahc
|
||||
SUBDIR= ahc_eisa ahc_pci
|
||||
SUBDIR= ahc_eisa ahc_isa ahc_pci
|
||||
|
||||
GENSRCS= aic7xxx_{seq,reg}.h
|
||||
AHC_REG_PRETTY_PRINT=1
|
||||
@ -29,7 +29,7 @@ ${GENSRCS}: \
|
||||
${.CURDIR}/../../../dev/aic7xxx/aic7xxx.seq
|
||||
|
||||
SRCS= ${GENSRCS}
|
||||
SRCS+= aic7xxx.c aic7xxx_93cx6.c aic7xxx_osm.c
|
||||
SRCS+= aic7xxx.c aic7xxx_93cx6.c aic7xxx_osm.c aic7770.c
|
||||
SRCS+= opt_scsi.h opt_aic7xxx.h opt_cam.h
|
||||
SRCS+= device_if.h bus_if.h pci_if.h
|
||||
|
||||
|
@ -7,8 +7,8 @@ KMOD= ahc_eisa
|
||||
../aic7xxx_reg.h:
|
||||
( cd .. ; ${MAKE} aic7xxx_reg.h )
|
||||
|
||||
SRCS= ahc_eisa.c aic7770.c ../aic7xxx_reg.h
|
||||
SRCS+= device_if.h bus_if.h pci_if.h eisa_if.h
|
||||
SRCS= ahc_eisa.c ../aic7xxx_reg.h
|
||||
SRCS+= device_if.h bus_if.h eisa_if.h
|
||||
SRCS+= opt_scsi.h opt_cam.h opt_aic7xxx.h
|
||||
|
||||
CFLAGS+= -I${.CURDIR}/../../../../dev/aic7xxx -I..
|
||||
|
Loading…
x
Reference in New Issue
Block a user